7

As a test case, I'm trying to copy a file from Google Drive to Dropbox using Google Scripts

function pushBuild() {
  // Setup OAuthServiceConfig
  var oAuthConfig = UrlFetchApp.addOAuthService("dropbox");
  oAuthConfig.setAccessTokenUrl("https://api.dropbox.com/1/oauth/access_token");
  oAuthConfig.setRequestTokenUrl("https://api.dropbox.com/1/oauth/request_token");
  oAuthConfig.setAuthorizationUrl("https://www.dropbox.com/1/oauth/authorize");
  oAuthConfig.setConsumerKey(ScriptProperties.getProperty("dropboxKey"));
  oAuthConfig.setConsumerSecret(ScriptProperties.getProperty("dropboxSecret"));

  var fileName = "blah.zip"
  var folderName = "upload_dir"

  var docs = DocsList.getFolder(folderName).find(fileName);
  for(n=0;n<docs.length;++n){
    if(docs[n].getName() == fileName){
      var ID = docs[n].getId();
      var options = {
        "oAuthServiceName" : "dropbox",
        "oAuthUseToken" : "always",
        "method" : "put",
        "payload" : docs[n].getBlob().getBytes(),
        "contentType" : "application/zip"        
    };

  var response = UrlFetchApp.fetch("https://api-content.dropbox.com/1/files_put/sandbox/upload_dir/" + fileName, options);

  Logger.log(response);
  }
 }

}

The authorization request for the application in Dropbox appears and it tells me that I've successfully authorized my app, but when I check, the app is not in the list of "My Apps", the file has not been uploaded and there are no entries in the log. The directory "upload_dir" exists on both GD and DB. I've tried the same code with "App Folder" and "Full Dropbox" app types, but get the same result.

Additionally, running the script again once again triggers the Authorization page, similar to

this

to appear, clicking "Allow" then shows the success screen but the application is not listed in "My Apps". Running the script again repeats the process.

Can anyone point out what I've done wrong?

Update

So, I've now tried to implement this using the individual api calls and am still not having any success.

function testOAuth() {

  var timestamp = getTimestamp();
  var nonce = getNonce(timestamp);

  var authString = 'OAuth oauth_version="1.0", oauth_signature_method="PLAINTEXT", oauth_signature="' + encodeURIComponent(ScriptProperties.getProperty("dropboxSecret") + '&') + '", oauth_consumer_key="' + ScriptProperties.getProperty("dropboxKey") + '"';

  Logger.log(authString)

  var options = {
    method : "POST",
    headers : {"Authorization" : authString}
  }

  var response = UrlFetchApp.fetch("https://api.dropbox.com/1/oauth/request_token",options);  
  var params = response.getContentText().split("&");  
  var map = new Map;  
      for(i = 0; i < params.length; i++){
        var param = params[i].split("=");
        map.put(param[0],param[1]);        
      }

  var authStringx = "https://www.dropbox.com/1/oauth/authorize?oauth_token=" + map.get("oauth_token");

  Logger.log(authStringx);

  var response2 = UrlFetchApp.fetch(authStringx);

  Logger.log(response2.getContentText());

  var authString2 = 'OAuth oauth_version="1.0", oauth_signature_method="PLAINTEXT", oauth_token="' + map.get("oauth_token") + '" , oauth_signature="' + encodeURIComponent(ScriptProperties.getProperty("dropboxSecret") + '&' + map.get("oauth_token_secret")) + '", oauth_consumer_key="' + ScriptProperties.getProperty("dropboxKey") + '",oauth_timestamp="'+ timestamp +'", oauth_nonce="' + nonce +'"';

  Logger.log(authString2);

  var options3 = {
    "method" : "POST",
    "Authorization" : authString2  
  }

  var response3 = UrlFetchApp.fetch("https://api.dropbox.com/1/oauth/access_token", options3);

  Logger.log(response3.getContentText());
}

var getTimestamp = function(){
  return (Math.floor((new Date()).getTime() / 1000)).toString()
}

var getNonce = function(timestamp){
  return timestamp + Math.floor( Math.random() * 100000000)
}

The code implementation for the map is here. The main problem that I can see is that authorize step does not invoke the Dropbox authorize end point (ie no browser redirection takes place to authorize the application). If I place a breakpoint just after the line Logger.log(authStringx); and manually visit the web page pasting in the contents of authStringx I get the screen to authorize my app. I accept that and get the message that the app is registered in "My Apps". I now let the program continue and I am greeted with the message

enter image description here

Any ideas?

j0k
  • 22,600
  • 28
  • 79
  • 90
Pram
  • 2,261
  • 3
  • 31
  • 50
  • Can you explain what this means, "running the script again once again triggers the Authorization page to appear"? – Phil Bozak Feb 25 '13 at 14:15
  • "Running the script again..." means executing the script using the Run button on the Scripts control panel triggers the Dropbox screen that verifies if you want to run the custom application. I'll update the question to clarify – Pram Feb 25 '13 at 14:22

2 Answers2

3

Pram,

I was trying to accomplish the same task and came across your post. I am not a programmer, so I can't figure out the second part either (launching the authorization page fails), but I was able to complete the process in the third step and connect my app successfully.

Instead of:

var authString2 = 'OAuth oauth_version="1.0", oauth_signature_method="PLAINTEXT", oauth_token="' + map.get("oauth_token") + '" , oauth_signature="' + encodeURIComponent(ScriptProperties.getProperty("dropboxSecret") + '&' + map.get("oauth_token_secret")) + '", oauth_consumer_key="' + ScriptProperties.getProperty("dropboxKey") + '",oauth_timestamp="'+ timestamp +'", oauth_nonce="' + nonce +'"';

Logger.log(authString2);

var options3 = {
"method" : "POST",
"Authorization" : authString2  
}

var response3 = UrlFetchApp.fetch("https://api.dropbox.com/1/oauth/access_token", options3);

Logger.log(response3.getContentText());

I used:

var authtokenURL = "https://api.dropbox.com/1/oauth/access_token";

var authString2 = "?oauth_signature_method=PLAINTEXT&oauth_token=" + [MY_OAUTH_REQUEST_TOKEN] + "&oauth_signature=" + encodeURIComponent([MY_DROPBOX_CONSUMER_SECRET] + "&" + [MY_OAUTH_REQUEST_SECRET]) +"&oauth_consumer_key=" + [MY_DROPBOX_CONSUMER_KEY];

Logger.log(authString2);

var response3 = UrlFetchApp.fetch("https://api.dropbox.com/1/oauth/access_token" + authString2);    

Logger.log(response3.getContentText());

I then got an email confirmation that I connected a new app to Dropbox, and my app does show up under Settings in my account. Anyway, as I said, I'm no programmer, so sorry for the ugly code. Thanks for supplying your code for me to make it this far. I hope this helps you at least move forward, even if it doesn't solve the underlying problem.

  • What dropbox methods have you then gone on to use after this? Trying to get /fileops/create_folder to work myself. – Bryan P Mar 05 '13 at 06:25
  • I've been using files_put to automate the transfer of files from a website to my desktop. What problems are you encountering? – INTJCapital Mar 05 '13 at 06:33
  • I was missing out on including a payload object earlier, but now I'm looking for how to do the "Invite members to this folder" function. I only see /shares method which looks to just return the share link and not add an email to the sharing permission of a folder. – Bryan P Mar 05 '13 at 15:53
0

I am able to see this issue as well. There is something special going on here with Dropbox. You should check on their forums or with their API support team. Looks like they are not correctly accepting callback params. Perhaps this is a development mode limitation (vs. production mode). Or perhaps they are stringent about some POST vs GET differences that Google doesn't support.

This code below exhibits the same issue you described where the authorization is never complete.

function dropbox() {
  var oAuthCfg = UrlFetchApp.addOAuthService("dropbox");
  oAuthCfg.setAccessTokenUrl('https://api.dropbox.com/1/oauth/access_token');
  oAuthCfg.setRequestTokenUrl('https://api.dropbox.com/1/oauth/request_token');
  oAuthCfg.setAuthorizationUrl('https://api.dropbox.com/1/oauth/authorize');
  oAuthCfg.setConsumerKey('DROPBOX_KEY');
  oAuthCfg.setConsumerSecret('DROPBOX_SECRET');

  var options = {oAuthServiceName:'dropbox',oAuthUseToken:'always'}

  var url = 'https://api.dropbox.com/1/account/info';
  var response = UrlFetchApp.fetch(url, options).getContentText();
  Logger.log(response);
}

However, the same code works without issue with the Twitter OAuth 1 API. The code below should dump out JSON from your stream (once you substitute the tokens from your setup in http://dev.twitter.com

function twitter(){
  var oAuthCfg = UrlFetchApp.addOAuthService('twitter');
  oAuthCfg.setAccessTokenUrl('http://api.twitter.com/oauth/access_token');
  oAuthCfg.setRequestTokenUrl('http://api.twitter.com/oauth/request_token');
  oAuthCfg.setAuthorizationUrl('http://api.twitter.com/oauth/authorize');
  oAuthCfg.setConsumerKey('TWITTER_KEY');
  oAuthCfg.setConsumerSecret('TWITTER_SECRET');

  var options = {oAuthServiceName:'twitter',oAuthUseToken:'always'}

  var url = "http://api.twitter.com/1/statuses/user_timeline.json";
  var response = UrlFetchApp.fetch(url, options).getContentText();
  Logger.log(response);
}

If you are able to narrow this down to a Google issue log a bug here on the Issue Tracker.

Arun Nagarajan
  • 5,547
  • 1
  • 22
  • 19
  • I posted onto the Dropbox forums (https://forums.dropbox.com/topic.php?id=97153#post-529744) and received the response "The app won't appear in the "My Apps" list until the entire OAuth flow has been completed successfully, meaning that /access_token has to be called with the original request token, after the user authorizes the app on the site. Has that step been completed?" How do you go about doing that with UrlFetchApp I wonder? – Pram Feb 26 '13 at 07:40
  • Apps Script does a bit of magic for OAuth1 about fetching the tokens. You can do everything that `.addOAuthService()` does manually by making the calls to get tokens, handling callbacks etc. You can see an example of that here with OAuth2 - https://github.com/entaq/GoogleAppsScript/blob/master/Salesforce.com/OAuthAndUploadContactsToSalesforce.gs – Arun Nagarajan Feb 26 '13 at 12:42