error: Invalid Signature when uploading files on dropbox

一曲冷凌霜 提交于 2020-01-14 05:40:14

问题


I am trying to develop a desktop application that uses dropbox. I am using C++, libcurl (for the requests) liboauthcpp (for the authentication) and the Rest API (from dropbox).

Since I have successed the authentication and some more operations (list and download file), I cannot manage to upload a file. I am receiving the following error: {"error": "Invalid signature."}

Here is my code:

m_upload_url = "https://api-content.dropbox.com/1/files/sandbox/";

        OAuth::Consumer consumer(m_consumer_key, m_consumer_secret);
        OAuth::KeyValuePairs access_token_resp_data = OAuth::ParseKeyValuePairs(m_access_token_Response);
        OAuth::Token access_token = OAuth::Token::extract( access_token_resp_data );
        OAuth::Client  oauth = OAuth::Client(&consumer, &access_token);
        string oAuthQueryString = oauth.getURLQueryString( OAuth::Http::Post, m_upload_url);

        string upload_Request = (string(m_upload_url) + string("?") + oAuthQueryString);

       CURL *curl;
         CURLcode res;

         struct curl_httppost *formpost=NULL;
         struct curl_httppost *lastptr=NULL;
         struct curl_slist *headerlist=NULL;
         static const char buf[] = "Expect:";

         curl_global_init(CURL_GLOBAL_ALL);

         /* Fill in the file upload field */
         curl_formadd(&formpost,
                      &lastptr,
                      CURLFORM_COPYNAME, "file",
                      CURLFORM_FILE, "C:/Users/Desktop/textfile.txt",
                      CURLFORM_END);

         /* Fill in the filename field */
         curl_formadd(&formpost,
                      &lastptr,
                      CURLFORM_COPYNAME, "name",
                      CURLFORM_COPYCONTENTS, "textfile",
                      CURLFORM_END);


         /* Fill in the submit field too, even if this is rarely needed */
         curl_formadd(&formpost,
                      &lastptr,
                      CURLFORM_COPYNAME, "submit",
                      CURLFORM_COPYCONTENTS, "send",
                      CURLFORM_END);

         curl = curl_easy_init();
         /* initalize custom header list (stating that Expect: 100-continue is not
            wanted */
         headerlist = curl_slist_append(headerlist, buf);
         if(curl) {
           /* what URL that receives this POST */
           curl_easy_setopt(curl, CURLOPT_URL, upload_Request.c_str());
             /* only disable 100-continue header if explicitly requested */
           curl_easy_setopt(curl, CURLOPT_HTTPPOST, 1L);
           curl_easy_setopt(curl, CURLOPT_POST, 1L);
           curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
           curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
           curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
           curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
           curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunction);
           curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

           /* Perform the request, res will get the return code */
           res = curl_easy_perform(curl);
           string response = string(gData);

           qDebug() << QString::fromStdString(response);

           /* Check for errors */
           if(res != CURLE_OK)
           qDebug() << "curl_easy_perform() failed: %s\n" << curl_easy_strerror(res);

           /* always cleanup */
           curl_easy_cleanup(curl);

           /* then cleanup the formpost chain */
           curl_formfree(formpost);
           /* free slist */
           curl_slist_free_all (headerlist);
         }

and here is the writeFunction:

char gData[1024*1024];
unsigned int gDataLen = 0;

size_t writeFunction( char *ptr, size_t size, size_t nmemb)
{
    memcpy( &( gData[gDataLen] ), ptr, (size * nmemb) );
    gDataLen += (size * nmemb);
    gData[ gDataLen ] = '\0';
    return (size * nmemb);
}

Any ideas, please?

EDIT:

Here is the request that the present code produces: https://api-content.dropbox.com/1/files/sandbox/?oauth_consumer_key=xxxxxxxxxxxxxxx&oauth_nonce=13xxxxxx83cf&oauth_signature=xxxxxx%xxxxxxxxxxxxxxxxxx%xxxxx%xx&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1371107283&oauth_token=xxxxxxxxxxxxxxx&oauth_version=1.0

and the request that I produse with the plaintext method: https://api-content.dropbox.com/1/files/sandbox/?oauth_version=1.0&oauth_signature_method=PLAINTEXT&oauth_consumer_key=xxxxxxxxxxxxxxx&oauth_token=xxxxxxxxxxxxxxx&oauth_signature=xxxxxxxxxxxxxxx&xxxxxxxxxxxxxxx

Response that O get in both cases: {"error": "Invalid signature."}


回答1:


What OAuth signature method are you using? If it's anything but plaintext, then I believe the problem is that you're not passing the body of the HTTP request to getURLQueryString. The body needs to be part of the string that's signed. This explains why you've been able to get a few GET operations to work; those requests don't have a body.

Side note: it looks like you're using the POST form of file upload, which, as the docs say is considerably more complex than PUT. I think your life will be better if you switch. :-) For example, I think the submit field that you're adding will probably cause the call to not work.

EDIT: Here's a full working example using a manually-constructed plaintext signature. Fill in the app key, app secret, token, and token secret, and be sure to have a file called "hello.txt" for this to work:

#include <stdio.h>
#include <curl/curl.h>
#include <iostream>
#include <fstream>

using namespace std;

size_t read_data(void *ptr, size_t size, size_t nmeb, void *stream)
{
    return fread(ptr,size,nmeb,(FILE*)stream);
}

int main(void)
{
  CURL *curl;
  CURLcode res;

  FILE * rfp = fopen("hello.txt", "r");

  string appkey = "<APP KEY>";
  string appsecret = "<APP SECRET>";
  string token = "<ACCESS TOKEN>";
  string token_secret = "<ACCESS TOKEN SECRET>";

  curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://api-content.dropbox.com/1/files_put/sandbox/hello.txt");

    struct curl_slist *headers = NULL;
    string header = "Authorization: OAuth oauth_version=\"1.0\", oauth_signature_method=\"PLAINTEXT\", oauth_consumer_key=\"" + appkey + "\", oauth_token=\"" + token + "\", oauth_signature=\"" + appsecret + "&" + token_secret + "\"";
    headers = curl_slist_append(headers, header.c_str());
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

    curl_easy_setopt(curl, CURLOPT_PUT, 1L);
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_data);
    curl_easy_setopt(curl, CURLOPT_READDATA, rfp);

    res = curl_easy_perform(curl);

    curl_slist_free_all(headers);
    if(res != CURLE_OK)
      fprintf(stderr, "curl_easy_perform() failed: %s\n",
              curl_easy_strerror(res));

    curl_easy_cleanup(curl);
  }

  fclose(rfp);

  return 0;
}



回答2:


Has anyone used liboauthcpp? I suspect that my mistake is in the way I use getURLQueryString.. I am passing the url into this function, but I am not sure if I have to pass the data too. And unfortunately, there is no documentation for this library.



来源:https://stackoverflow.com/questions/17062916/error-invalid-signature-when-uploading-files-on-dropbox

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!