22

I do not seem to manage the file copy operating using the dropbox api. I can successfully authorize my client, download and upload files. The copy operation needs POST method to be used and I think this is where I produce wrong request. I am defining the POST Method for OAuth Authentication and use Indy TIdHTTP to Post the request, but I always receive the error code 403 - Permission denied.

Here is the dropbox api description: https://www.dropbox.com/developers/reference/api#fileops-copy

Here is part of my code:

 ParamStr := Format('root=%s&from_path=%s&to_path=%s', [Root, EncodeFileName(FromPath), EncodeFileName(ToPath)]);
 URL := 'https://api.dropbox.com/1/fileops/copy' + '?' + ParamStr;

 Consumer := TOAuthConsumer.Create(Key, Secret);
 AToken := TOAuthToken.Create(fToken, fTokenSecret);
 HMAC := TOAuthSignatureMethod_HMAC_SHA1.Create;
 ARequest := TOAuthRequest.Create('');
 try
  ARequest.HTTPURL := URL;
  ARequest.Method := 'POST';
  ARequest := ARequest.FromConsumerAndToken(Consumer, AToken, '');
  ARequest.Sign_Request(HMAC, Consumer, AToken);


  Params := TStringList.Create;
  try
   Params.Text := ParamStr + '&' + ARequest.GetString;
   HTTP.Post(URL, Params);
  finally
   Params.Free;
  end;
Nostradamus
  • 668
  • 6
  • 18
  • Try to look around how to use Indy with SSL. I bet you are missing the OpenSSL libraries. – TLama May 30 '12 at 16:03
  • What makes you think the error means anything other than the documented meaning? "403: An invalid copy operation was attempted (e.g. there is already a file at the given destination, or copying a shared folder into a shared folder)." – Rob Kennedy May 30 '12 at 18:18
  • 1
    @Tlama, wouldn't missing SSL libraries also interfere with authorize, upload, and download operations, which are supposedly working? – Rob Kennedy May 30 '12 at 18:19
  • @Rob, you're right, I missed that. – TLama May 31 '12 at 07:02
  • 1
    I definitely have the SSL libraries. As I said it works with all GET and PUT method APIs. – Nostradamus May 31 '12 at 08:05
  • 2
    There is no file or folder with the same name and I have checked the paths to be correct many times. I am only trying to copy a single file. The target folder exists and the source file exists as well. – Nostradamus May 31 '12 at 08:07
  • Just to be clear, the paths are relative to the root directory on dropbox? – Jason Feb 19 '14 at 02:17
  • Lastly I suggest adding the params to the string list one by one. From what I can tell it will end up with one entry in the params. Try Params.Add(root=%s); etc. – Jason Feb 19 '14 at 02:22
  • Where can one get the latest version of the oauth.pas file? The version I have does not have the TOAuthRequest.method property exposed. – M Schenkel Mar 05 '16 at 02:35

2 Answers2

1

As far as I know when using with indy the params are copied in the body of the message and not in the url try using something like:

http:Post(URL+encodeparams(params));

I'm not sure that this is the right syntax but that's the idea.

JohanTux
  • 382
  • 4
  • 11
Pacharrin
  • 126
  • 9
1

I think i might discovered whats wrong here. I am unaware of the TOAuthRequest class but I will guess that the GetString method gives the standart OAuth header 'Authorization Bearer {KEY}'. See that is header and the right way to add it to the http request is

HTTP.Request.CustomHeaders.AddValue('Authorization', <the rest of the string here>)

You on the other hand add that string to the body which may work for Get requests because the body(the authorization string) is mistaken for a header but with the POST method you have actual body before the authorization string and thus the OAuth string is ignored.

And lastly I don't think you need the parameters string in the body as well. An empty body should work just fine. The query string seems OK.

Example code:

  ParamStr := Format('root=%s&from_path=%s&to_path=%s', [Root, EncodeFileName(FromPath), EncodeFileName(ToPath)]);
 URL := 'https://api.dropbox.com/1/fileops/copy' + '?' + ParamStr;

 Consumer := TOAuthConsumer.Create(Key, Secret);
 AToken := TOAuthToken.Create(fToken, fTokenSecret);
 HMAC := TOAuthSignatureMethod_HMAC_SHA1.Create;
 ARequest := TOAuthRequest.Create('');
 try
  ARequest.HTTPURL := URL;
  ARequest.Method := 'POST';
  ARequest := ARequest.FromConsumerAndToken(Consumer, AToken, '');
  ARequest.Sign_Request(HMAC, Consumer, AToken);



  HTTP.Request.CustomHeaders.AddValue('Authorization', <parsed ARequest.GetString>)
  HTTP.Post(URL);

Hope that this helps.