" + char;
303 | });
304 | }
305 |
306 | var INDETERMINATE = {};
307 |
308 |
309 | function updateNotification(id,opt){
310 | chrome.notifications.update(id, opt,function(wasUpdated){
311 | if(!wasUpdated){
312 | console.log('Error! Could not locate notification', id,opt.title, opt.message);
313 | }
314 | });
315 | }
316 |
317 |
318 | var urlid = {
319 | 'todo_fix_this': 42
320 | //this is a sort of hack. it uses the file download urls
321 | //as a sort of state callback whatnot stuff.
322 | };
323 |
324 | function uploadProgress(url, evt){
325 | var pr=Math.round(evt.loaded * 100 / evt.total);
326 | var upload={
327 | type: 'progress',
328 | title:'Upload',
329 | message:'Uploading...',
330 | iconUrl:'icon/48.png',
331 | progress:pr
332 | }
333 | updateNotification(urlid[url],upload);
334 | }
335 |
336 | function downloadProgress(url, evt){
337 | var pr=Math.round(evt.loaded * 100 / evt.total);
338 | var download={
339 | type: 'progress',
340 | title:'Download',
341 | message:'Downloading...',
342 | iconUrl:'icon/48.png',
343 | progress:pr
344 | }
345 | updateNotification(urlid[url],download);
346 | }
347 |
348 |
349 | function upload(host, url, name){
350 | var id = Math.random().toString(36).substr(3);
351 | var opt = {
352 | type: "basic",
353 | title: "Saving",
354 | message: 'The file is being saved to '+title_map[host],
355 | iconUrl: "icon/throbber.gif"
356 | }
357 | chrome.notifications.create(id, opt,function(nid){
358 | console.log("id="+nid);
359 | })
360 |
361 | var has_uploaded = false;
362 | var upload_callback = function(){};
363 |
364 | chrome.notifications.onClicked.addListener(function(notificationId){
365 | if(has_uploaded){
366 | openFile();
367 | clearnotification(notificationId);
368 | }else{
369 | upload_callback = openFile;
370 | }
371 | })
372 |
373 | chrome.notifications.onClosed.addListener(function(notificationId,byUser){
374 | delete urlid[url];
375 | })
376 |
377 | function clearnotification(id){
378 | chrome.notifications.clear(id, function(wasCleared){
379 | if(wasCleared!=true)
380 | console.log('clear notification failed');
381 | })
382 | }
383 |
384 | function openFile(){
385 | chrome.tabs.create({url: has_uploaded})
386 | }
387 | urlid[url] = id;
388 | Hosts[host]({
389 | url: url,
390 | name: name
391 | }, function(e){
392 | has_uploaded = e && e.url;
393 | var ntitle,nmsg,nicon;
394 | setTimeout(upload_callback, 200);
395 | console.log('uploaded file yay', e);
396 | if(e && typeof e == "string" && e.indexOf('error:') != -1){
397 | ntitle='Error';
398 | nmsg="Could not be uploaded to "+title_map[host];
399 | console.log('e.error'+e.substr(6));
400 | nicon='icon/64sad.png';
401 | }else{
402 | ntitle="Success";
403 | nmsg="The file has been uploaded to "+title_map[host]+", click me to view.";
404 | nicon="icon/64.png";
405 | }
406 |
407 | var opt = {
408 | type: 'basic',
409 | title: ntitle,
410 | message: nmsg,
411 | iconUrl: nicon
412 | };
413 | updateNotification(id, opt);
414 | })
415 | }
416 |
417 |
418 | function install_additional(state){
419 | if(state){
420 | for(var i in additional){
421 | for(var ii in additional[i])
422 | classes[i][ii] = additional[i][ii];
423 | }
424 | }else{
425 | classes = clone(original);
426 | }
427 | updateMenus();
428 | }
429 |
430 | if(localStorage.additional == 'yes'){
431 | install_additional(true);
432 | }else{
433 | updateMenus();
434 | }
435 |
--------------------------------------------------------------------------------
/files.js:
--------------------------------------------------------------------------------
1 | //stolen from mozilla http://demos.hacks.mozilla.org/openweb/imageUploader/js/extends/xhr.js
2 | //http://code.google.com/p/chromium/issues/detail?id=35705#c6
3 | //http://efreedom.com/Question/1-3743047/Uploading-Binary-String-WebKit-Chrome-Using-XHR-Equivalent-Firefoxs-SendAsBinary
4 | //this is a mutilated sendMultipart function. BEWARE!
5 |
6 | if(typeof btoa == 'undefined'){
7 |
8 | btoa = function (input) {
9 | var output = "", i = 0, l = input.length,
10 | key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
11 | chr1, chr2, chr3, enc1, enc2, enc3, enc4;
12 | while (i < l) {
13 | chr1 = input.charCodeAt(i++);
14 | chr2 = input.charCodeAt(i++);
15 | chr3 = input.charCodeAt(i++);
16 | enc1 = chr1 >> 2;
17 | enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
18 | enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
19 | enc4 = chr3 & 63;
20 | if (isNaN(chr2)) enc3 = enc4 = 64;
21 | else if (isNaN(chr3)) enc4 = 64;
22 | output = output + key.charAt(enc1) + key.charAt(enc2) + key.charAt(enc3) + key.charAt(enc4);
23 | }
24 | return output;
25 | }
26 |
27 | atob = function(input){
28 | var output = "", i = 0, l = input.length,
29 | key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
30 | chr1, chr2, chr3, enc1, enc2, enc3, enc4;
31 | while (i < l) {
32 | enc1 = key.indexOf(input.charAt(i++));
33 | enc2 = key.indexOf(input.charAt(i++));
34 | enc3 = key.indexOf(input.charAt(i++));
35 | enc4 = key.indexOf(input.charAt(i++));
36 | chr1 = (enc1 << 2) | (enc2 >> 4);
37 | chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
38 | chr3 = ((enc3 & 3) << 6) | enc4;
39 | output = output + String.fromCharCode(chr1);
40 | if (enc3 != 64) output = output + String.fromCharCode(chr2);
41 | if (enc4 != 64) output = output + String.fromCharCode(chr3);
42 | }
43 | return output;
44 | }
45 |
46 | }
47 |
48 | XMLHttpRequest.prototype.sendMultipart = function(params) {
49 | var BOUNDARY = "---------------------------1966284435497298061834782736";
50 | var rn = "\r\n";
51 | console.log(params)
52 |
53 | var tmp = new XMLHttpRequest();
54 | var abuf = 'responseType' in tmp && 'response' in tmp;
55 |
56 | var binxhr = !!this.sendAsBinary;
57 | if(binxhr){
58 | var req = '', append = function(data){req += data}
59 | }else{
60 | var req = [], append = function(data){req.push(data)}
61 | }
62 |
63 | append("--" + BOUNDARY);
64 |
65 | var file_param = -1;
66 | var xhr = this;
67 |
68 |
69 |
70 |
71 | for (var i in params) {
72 | if (typeof params[i] == "object") {
73 | file_param = i;
74 | } else {
75 | append(rn + "Content-Disposition: form-data; name=\"" + i + "\"");
76 | append(rn + rn + params[i] + rn + "--" + BOUNDARY);
77 | }
78 | }
79 |
80 | var i = file_param;
81 |
82 | append(rn + "Content-Disposition: form-data; name=\"" + i + "\"");
83 |
84 | getURL(abuf?'arraybuffer':(binxhr?'binary':'raw'),params[i], function(file){
85 | //Uint8 does clamping, but sendAsBinary doesn't
86 | console.log('actual data entity', file);
87 |
88 | xhr.upload.addEventListener('progress', function(evt){
89 | uploadProgress(file.url, evt);
90 | }, false)
91 |
92 | append("; filename=\""+file.name+"\"" + rn + "Content-type: "+file.type);
93 |
94 | append(rn + rn);
95 |
96 | if(binxhr){
97 | append(file.data);
98 | }else if(abuf){
99 | append(file.data);
100 | }else{
101 | var bin = file.data
102 | var arr = new Uint8Array(bin.length);
103 | for(var i = 0, l = bin.length; i < l; i++)
104 | arr[i] = bin.charCodeAt(i);
105 |
106 | append(arr.buffer)
107 | }
108 | append(rn + "--" + BOUNDARY);
109 |
110 | append("--");
111 |
112 |
113 | xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
114 |
115 | if(binxhr){
116 | xhr.sendAsBinary(req);
117 | }else{
118 | superblob = new Blob(req);
119 | xhr.send(superblob);
120 | }
121 | });
122 | };
123 |
--------------------------------------------------------------------------------
/hosts/box.js:
--------------------------------------------------------------------------------
1 | //box.net
2 |
3 | Hosts.box = function uploadBox(file, callback){
4 | function create_folder(){
5 | var xhr = new XMLHttpRequest();
6 | var fname = 'cloudsave';
7 | xhr.open('GET', 'https://www.box.net/api/1.0/rest?action=create_folder&api_key='+Keys.box+'&auth_token='+localStorage.box_auth+'&parent_id=0&share=0&name='+fname, true);
8 | xhr.send();
9 | xhr.onload = function(){
10 | if(xhr.responseText.indexOf('not_logged_in') != -1){
11 | login(function(){
12 | //function inside a function (passed to another function inside a function inside a function) inside a function inside a function
13 | create_folder();
14 | });
15 | }else{
16 | var fid = xhr.responseXML.getElementsByTagName('folder_id')[0].firstChild.nodeValue;
17 | console.log('folder ID', fid);
18 | upload(fid);
19 | }
20 | }
21 | }
22 |
23 |
24 | function upload(folder){
25 | var xhr = new XMLHttpRequest();
26 | xhr.open('POST', 'https://upload.box.net/api/1.0/upload/'+localStorage.box_auth+'/'+folder+'?new_copy=1');
27 | xhr.onload = function(){
28 | callback({
29 | url: "http://box.net/"
30 | });
31 | }
32 | xhr.sendMultipart({
33 | share: 1,
34 | file: file
35 | })
36 | }
37 |
38 | function login(stopforward){ //sort of opposite vaguely of callback
39 |
40 | function auth_token(url){
41 | var auth = url.match(/auth_token=([^\&]+)/)[1];
42 | localStorage.box_auth = auth;
43 | console.log(localStorage.box_auth, localStorage.box_ticket);
44 | stopforward();
45 | }
46 |
47 | var xhr = new XMLHttpRequest();
48 | xhr.open('GET', https()+'www.box.net/api/1.0/rest?action=get_ticket&api_key='+Keys.box, true);
49 | xhr.send();
50 | xhr.onload = function(){
51 | var ticket = xhr.responseXML.getElementsByTagName('ticket')[0].firstChild.nodeValue;
52 | localStorage.box_ticket = ticket;
53 | var redirect = https()+"www.box.net/api/1.0/auth/"+ticket;
54 |
55 | loginTab(redirect, 'auth_token', auth_token);
56 | }
57 | }
58 |
59 | create_folder()
60 | }
61 |
--------------------------------------------------------------------------------
/hosts/cloudapp.js:
--------------------------------------------------------------------------------
1 | //uses multipart helper function.
2 | //does not support https
3 | Hosts.cloudapp = function uploadCloudApp(file, callback){
4 | var xhr = new XMLHttpRequest();
5 | xhr.open('GET', 'http://my.cl.ly/items/new');
6 | xhr.setRequestHeader('Accept', 'application/json');
7 | xhr.onload = function(){
8 | if(xhr.status == 401){
9 | //i can haz login
10 |
11 |
12 | if(typeof chrome != 'undefined'){
13 | chrome.tabs.create({
14 | url: "http://my.cl.ly/login"
15 | }, function(tab){
16 | var poll = function(){
17 | chrome.tabs.get(tab.id, function(info){
18 | if('http://my.cl.ly/' == (info.url)){
19 | chrome.tabs.remove(tab.id);
20 | uploadCloudApp(file, callback);
21 | }else{
22 | setTimeout(poll, 100)
23 | }
24 | })
25 | };
26 | poll();
27 | })
28 | }else if(typeof tabs != 'undefined'){
29 | tabs.open({
30 | url: "http://my.cl.ly/login",
31 | onOpen: function(tab){
32 | var poll = function(){
33 | if('http://my.cl.ly/' == (tab.url)){
34 | tab.close()
35 | uploadCloudApp(file, callback);
36 | }else{
37 | setTimeout(poll, 100)
38 | }
39 | };
40 | poll();
41 | }
42 | })
43 | }
44 |
45 |
46 | }else{
47 | var json = JSON.parse(xhr.responseText);
48 | var xhr2 = new XMLHttpRequest();
49 | xhr2.open('POST', json.url);
50 | if(json.uploads_remaining == 0){
51 | return callback('error: You have exceeded your maximum number of uploads today for CloudApp. You may need to upgrade your account.');
52 | }
53 | json.params.key = json.params.key.replace('${filename}', file.name);
54 | json.params.file = file;
55 | xhr2.sendMultipart(json.params);
56 | xhr2.onload = function(){
57 | //since ajax cant add the Accept: header to the redirects, heres a hack
58 | var xhr3 = new XMLHttpRequest();
59 | xhr3.open('GET', 'http://my.cl.ly/items');
60 | xhr3.setRequestHeader('Accept', 'application/json');
61 | xhr3.onload = function(){
62 | var j3 = JSON.parse(xhr3.responseText)[0];
63 | callback({
64 | direct: j3.remote_url,
65 | url: j3.url
66 | })
67 | }
68 | xhr3.send()
69 | }
70 | }
71 | }
72 | xhr.send()
73 | }
74 |
--------------------------------------------------------------------------------
/hosts/clouddrive.js:
--------------------------------------------------------------------------------
1 | Hosts.clouddrive = function uploadclouddrive(file, callback){
2 | var cid = '';
3 | var sessid = ''
4 |
5 | function apiRequest(p, callback){
6 | var xhr = new XMLHttpRequest();
7 | p._ = +new Date;
8 | p.ContentType = 'JSON';
9 | p.customerId = cid;
10 | xhr.open('GET', 'https://www.amazon.com/clouddrive/api/?'+urlencode(p), true);
11 | xhr.setRequestHeader('x-amzn-SessionId', sessid);
12 | xhr.onload = function(){
13 | var json = JSON.parse(xhr.responseText);
14 | callback(json);
15 | }
16 | xhr.send(null);
17 | }
18 |
19 | function urlencode(p){
20 | var params = [];
21 | for(var i in p){
22 | params.push(i+'='+encodeURIComponent(p[i]));
23 | }
24 | return params.join('&');
25 | }
26 |
27 |
28 | function login(){
29 | var loginurl = 'https://www.amazon.com/ap/signin?_encoding=UTF8&openid.assoc_handle=usflex&openid.return_to=https%3A%2F%2Fwww.amazon.com%2Fclouddrive%2F%3F_encoding%3DUTF8%26path%3D%252Fclouddrive%252F%26ref_%3Dpd_irl_gw_r%26signIn%3D1%26useRedirectOnSuccess%3D1%26action%3Dsign-out&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.pape.max_auth_age=0&openid.ns.pape=http%3A%2F%2Fspecs.openid.net%2Fextensions%2Fpape%2F1.0&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select';
30 | loginTab(loginurl, '/clouddrive', getKeys);
31 | }
32 |
33 |
34 | function getKeys(){
35 | var xhr = new XMLHttpRequest();
36 | xhr.open('GET', 'https://www.amazon.com/clouddrive', true);
37 | xhr.send(null);
38 | xhr.onload = function(){
39 | var match = xhr.responseText.match(//);
40 | var match2 = xhr.responseText.match(//);
41 | if(!match || !match2){
42 | //todo: redirect to amazon lgoin
43 | console.log('Error: not logged in');
44 | login();
45 | }else{
46 | cid = match[1];
47 | sessid = match2[1];
48 | createFile();
49 | }
50 | }
51 | }
52 |
53 |
54 |
55 | function createFile(){
56 | apiRequest({
57 | Operation: 'createByPath',
58 | type: 'FILE',
59 | path: '/',
60 | name: file.name,
61 | conflictResolution: 'RENAME',
62 | overwrite: true,
63 | autoparent: true
64 | }, function(json){
65 | getUpload(json.createByPathResponse.createByPathResult.objectId);
66 | })
67 | }
68 |
69 |
70 |
71 |
72 | function completeFile(objectid, storagekey){
73 | apiRequest({
74 | Operation: 'completeFileUploadById',
75 | objectId: objectid,
76 | storageKey: storagekey
77 | }, function(json){
78 | callback({
79 | url: 'https://www.amazon.com/clouddrive'
80 | })
81 | })
82 | }
83 |
84 | function getUpload(objectid){
85 | apiRequest({
86 | Operation: 'getUploadUrlById',
87 | objectId: objectid,
88 | size: 42, //d.data.byteLength,
89 | method: 'POST'
90 | }, function(json){
91 | var h = json.getUploadUrlByIdResponse.getUploadUrlByIdResult.httpRequest;
92 | console.log('got http stuff', h);
93 | var storageKey = json.getUploadUrlByIdResponse.getUploadUrlByIdResult.storageKey;
94 | doUpload(h, function(){
95 | completeFile(objectid, storageKey);
96 | });
97 | })
98 | }
99 |
100 | function doUpload(h, cb){
101 | var xhr = new XMLHttpRequest();
102 | var params = JSON.parse(JSON.stringify(h.parameters));
103 | params.Filename = file.name;
104 | params.file = file;
105 | console.log(params);
106 | xhr.open('POST', h.endpoint, true);
107 | xhr.onload = function(){
108 | if(cb) cb();
109 | }
110 | xhr.sendMultipart(params)
111 | }
112 |
113 | getKeys();
114 |
115 | }
116 |
--------------------------------------------------------------------------------
/hosts/cx.js:
--------------------------------------------------------------------------------
1 | // Cx
2 |
3 | Hosts.cx = function uploadCx(file, callback) {
4 | var login_shown = false;
5 | var poll = function(){
6 | var xhr = new XMLHttpRequest();
7 | xhr.open("GET", "https://www.cx.com/0/userInfo/viewProfile");
8 | xhr.send();
9 | xhr.onload = function(){
10 | if (xhr.status==200) { // Logged in
11 |
12 | var tmp = new XMLHttpRequest();
13 | var abuf = 'responseType' in tmp && 'response' in tmp;
14 | var binxhr = !!this.sendAsBinary;
15 |
16 | // Amazon needs file size to upload
17 | getURL(abuf?'arraybuffer':(binxhr?'binary':'raw'),file, function(file){
18 |
19 | var xhr2 = new XMLHttpRequest();
20 | xhr2.open("POST", "https://www.cx.com/0/filedata/upload");
21 | xhr2.onload = function(){
22 | callback({url:"http://www.cx.com/mycx/files"});
23 | }
24 | xhr2.sendMultipart({
25 | fileName: file.name,
26 | fileSize: file.data.byteLength,
27 | file: file
28 | });
29 | });
30 |
31 | } else {
32 | if (!login_shown) {
33 | chrome.tabs.create({url:"http://www.cx.com/mycx/sign_in"});
34 | login_shown = true;
35 | }
36 | setTimeout(poll, 2000);
37 | }
38 | }
39 | }
40 | poll();
41 | }
--------------------------------------------------------------------------------
/hosts/dropbox/dropbox.js:
--------------------------------------------------------------------------------
1 | //uses multipart helper function.
2 |
3 |
4 | Hosts.dropbox = function uploadDropbox(file, callback){
5 | var dropbox = new ModernDropbox(Keys.dropbox.key, Keys.dropbox.secret)
6 |
7 | var poll = function(){
8 | if(dropbox.isAccessGranted()){
9 | var fname = file.name;
10 | var folder = ''
11 |
12 | dropbox.getAccountInfo(function(user){
13 |
14 |
15 | dropbox.getDirectoryMetadata(folder + encodeURIComponent(file.name), function(json){
16 | if(json.error && json.error.indexOf('not found') != -1){
17 | //yay plop it on the top
18 | }else if(fname.indexOf('/') == -1){
19 | fname = Math.random().toString(36).substr(2,4) + '_' + fname;
20 | }else{
21 | //no idea. TODO: do something
22 | }
23 |
24 |
25 | dropbox.putFileContents(folder + fname, file,
26 | function(){
27 | console.log('done uploading');
28 | //yay done. hopefully
29 | console.log('got stuffs now');
30 | callback({
31 | url: 'https://www.dropbox.com/'
32 | })
33 | });
34 | })
35 |
36 | })
37 |
38 | }else{
39 | setTimeout(poll, 300);
40 | }
41 | };
42 | poll();
43 |
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/hosts/dropbox/modern_dropbox.js:
--------------------------------------------------------------------------------
1 | var ModernDropbox = function(consumerKey, consumerSecret) {
2 | // Constructor / Private
3 | var _consumerKey = consumerKey;
4 | var _consumerSecret = consumerSecret;
5 |
6 | var _tokens = {};
7 | var _storagePrefix = "moderndropbox_";
8 | var _isSandbox = false;
9 | var _cache = true;
10 | var _authCallback = "http://drag2up.appspot.com/static/tpilb.html";
11 | var _fileListLimit = 10000;
12 | var _cookieTimeOut = 3650;
13 | var _dropboxApiVersion = 0;
14 | var _xhr = new XMLHttpRequest();
15 |
16 | var _ajaxSendFileContents = function(message, filename, content, callback) {
17 | _xhr.open("POST", message.action, true);
18 |
19 | var params = {};
20 |
21 | for (i in message.parameters) {
22 | params[message.parameters[i][0]] = message.parameters[i][1];
23 | }
24 |
25 | content.name = filename;
26 | params.file = content;
27 |
28 | _xhr.onreadystatechange = function() {
29 | //console.log(this);
30 | if(_xhr.status == 200 && _xhr.readyState == 4){
31 | callback(_xhr);
32 | }
33 | }
34 | console.log(params);
35 | _xhr.sendMultipart(params);
36 | };
37 |
38 | var _setAuthCallback = function(callback) {
39 | _authCallback = callback;
40 | };
41 |
42 | var _setupAuthStorage = function() {
43 | keys = ["requestToken", "requestTokenSecret", "accessToken", "accessTokenSecret"];
44 |
45 | for (i in keys) {
46 | var key = keys[i];
47 | value = localStorage[_storagePrefix + key];
48 | if (value) {
49 | _tokens[key] = value;
50 | }
51 | }
52 | };
53 |
54 | var _clearAuthStorage = function() {
55 | keys = ["requestToken", "requestTokenSecret", "accessToken", "accessTokenSecret"];
56 |
57 | for (i in keys) {
58 | var key = keys[i];
59 | localStorage.removeItem(_storagePrefix + key);
60 | }
61 | };
62 |
63 | var _storeAuth = function(valueMap) {
64 | keys = ["requestToken", "requestTokenSecret", "accessToken", "accessTokenSecret"];
65 |
66 | for (i in keys) {
67 | var key = keys[i];
68 |
69 | if (valueMap[key] !== undefined) {
70 |
71 | localStorage[_storagePrefix + key] = valueMap[key];
72 | _tokens[key] = valueMap[key];
73 | }
74 | }
75 | };
76 |
77 | var _isAccessGranted = function() {
78 | return (_tokens["accessToken"] != null) && (_tokens["accessTokenSecret"] != null);
79 | };
80 |
81 | var _isAuthorized = function() {
82 | return (_tokens["requestToken"] != null) && (_tokens["requestTokenSecret"] != null);
83 | };
84 |
85 | var _createOauthRequest = function(url, options) {
86 | if (!options) {
87 | options = [];
88 | }
89 |
90 | // Outline the message
91 | var message = {
92 | action: url,
93 | method: "GET",
94 | parameters: [
95 | ["oauth_consumer_key", _consumerKey],
96 | ["oauth_signature_method", "HMAC-SHA1"]
97 | ]
98 | };
99 |
100 | // Define the accessor
101 | var accessor = {
102 | consumerSecret: _consumerSecret,
103 | };
104 |
105 | if (!options.token) {
106 | message.parameters.push(["oauth_token", _tokens["accessToken"]]);
107 | } else {
108 | message.parameters.push(["oauth_token", options.token]);
109 | delete options.token;
110 | }
111 |
112 | if (!options.tokenSecret) {
113 | accessor.tokenSecret = _tokens["accessTokenSecret"];
114 | } else {
115 | accessor.tokenSecret = options.tokenSecret;
116 | delete options.tokenSecret;
117 | }
118 |
119 | if (options.method) {
120 | message.method = options.method;
121 | delete options.method;
122 | }
123 |
124 | for (key in options) {
125 | message.parameters.push([key, options[key]]);
126 | }
127 |
128 | OAuth.setTimestampAndNonce(message);
129 | OAuth.SignatureMethod.sign(message, accessor);
130 |
131 | return message;
132 | };
133 |
134 | var _sendOauthRequest = function(message, options) {
135 | if (!options) {
136 | options = [];
137 | }
138 |
139 | if (!options.success) {
140 | options.success = function() {};
141 | }
142 |
143 | if (!options.error) {
144 | options.error = function() {};
145 | }
146 |
147 | if (!options.type) {
148 | options.type = "json";
149 | }
150 |
151 | if (options.multipart) {
152 | _ajaxSendFileContents(
153 | message,
154 | options.filename,
155 | options.content,
156 | options.success
157 | );
158 | } else {
159 | var xhr = new XMLHttpRequest();
160 | function params(obj){
161 | var str = [];
162 | for(var i in obj) str.push(i+'='+encodeURIComponent(obj[i]));
163 | return str.join('&');
164 | }
165 |
166 |
167 | var data = params(OAuth.getParameterMap(message.parameters));
168 |
169 |
170 | if(message.method.toLowerCase() == 'post'){
171 | xhr.open(message.method, message.action, true);
172 | xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded');
173 | xhr.send(data);
174 | }else{
175 | xhr.open(message.method, message.action+'?'+data, true);
176 | xhr.send(null);
177 | }
178 | xhr.onload = function(){
179 | var res = xhr.responseText;
180 |
181 | if(options.type == 'json') res = JSON.parse(res);
182 |
183 | options.success(res);
184 | }
185 | }
186 | };
187 |
188 | // Public
189 | return ({
190 | initialize: function() {
191 | _setupAuthStorage();
192 |
193 | if (!_isAccessGranted()) {
194 | if (!_isAuthorized()) {
195 | var message = _createOauthRequest("https://www.dropbox.com/" + _dropboxApiVersion + "/oauth/request_token");
196 |
197 | _sendOauthRequest(message, {
198 | type: "text",
199 | success: (function(data) {
200 | if (!data) {
201 | data = "";
202 | }
203 |
204 | var tokenPairStrings = data.split("&");
205 | var parsedTokenPairs = [];
206 |
207 | for (i in tokenPairStrings) {
208 | var tokenPairs = tokenPairStrings[i].split("=");
209 | parsedTokenPairs[tokenPairs[0]] = tokenPairs[1];
210 | }
211 |
212 | var authTokens = {};
213 | authTokens["requestToken"] = parsedTokenPairs["oauth_token"];
214 | authTokens["requestTokenSecret"] = parsedTokenPairs["oauth_token_secret"];
215 |
216 | _storeAuth(authTokens);
217 | var init = this.initialize;
218 | var url = "https://www.dropbox.com/" + _dropboxApiVersion + "/oauth/authorize?oauth_token="
219 | + authTokens["requestToken"]
220 | + "&oauth_callback="
221 | + _authCallback;
222 |
223 | loginTab(url, 'uid=', init);
224 | }).bind(this)
225 | });
226 | } else {
227 | var message = _createOauthRequest("https://www.dropbox.com/" + _dropboxApiVersion + "/oauth/access_token", {
228 | token: _tokens["requestToken"],
229 | tokenSecret: _tokens["requestTokenSecret"]
230 | });
231 |
232 | _sendOauthRequest(message, {
233 | type: "text",
234 | success: (function(data) {
235 | if (!data) {
236 | data = "";
237 | }
238 |
239 | var tokenPairStrings = data.split("&");
240 | var parsedTokenPairs = [];
241 |
242 | for (i in tokenPairStrings) {
243 | var tokenPairs = tokenPairStrings[i].split("=");
244 | parsedTokenPairs[tokenPairs[0]] = tokenPairs[1];
245 | }
246 |
247 | var authTokens = {};
248 | authTokens["accessToken"] = parsedTokenPairs["oauth_token"];
249 | authTokens["accessTokenSecret"] = parsedTokenPairs["oauth_token_secret"];
250 |
251 | _storeAuth(authTokens);
252 | }).bind(this),
253 | error: (function(data){
254 | _storeAuth({
255 | requestToken: '',
256 | requestTokenSecret: ''
257 | })
258 | this.initialize();
259 | }).bind(this)
260 | });
261 | }
262 | }
263 |
264 | return this;
265 | },
266 | isAccessGranted: function(){
267 | return _isAccessGranted()
268 | },
269 | getAccountInfo: function(callback) {
270 | var url = "https://www.dropbox.com/" + _dropboxApiVersion + "/account/info";
271 | var message = _createOauthRequest(url);
272 | _sendOauthRequest(message, {
273 | type: "json",
274 | success: (function(data) { callback(data); }).bind(this)
275 | });
276 | },
277 |
278 | getDirectoryContents: function(path, callback) {
279 | var url = "https://www.dropbox.com/" + _dropboxApiVersion + "/metadata/dropbox/" + path;
280 | var message = _createOauthRequest(url, {
281 | file_limit: _fileListLimit,
282 | list: "true"
283 | });
284 |
285 | _sendOauthRequest(message, {
286 | type: "json",
287 | success: (function(data) { callback(data); }).bind(this)
288 | });
289 | },
290 |
291 | getDirectoryMetadata: function(path, callback) {
292 | var url = "https://www.dropbox.com/" + _dropboxApiVersion + "/metadata/dropbox/" + path;
293 | var message = _createOauthRequest(url, {
294 | list: "false"
295 | });
296 |
297 | _sendOauthRequest(message, {
298 | type: "json",
299 | success: (function(data) { callback(data); }).bind(this)
300 | });
301 | },
302 |
303 | getFileContents: function(path, callback) {
304 | var url = "https://api-content.dropbox.com/" + _dropboxApiVersion + "/files/dropbox/" + path;
305 | var message = _createOauthRequest(url);
306 |
307 | _sendOauthRequest(message, {
308 | type: "text",
309 | success: (function(data) { callback(data); }).bind(this)
310 | });
311 | },
312 |
313 | putFileContents: function(path, file, callback) {
314 | var filename = path.match(/([^\\\/]+)$/)[1];
315 | var file_path = path.match(/^(.*?)[^\\\/]+$/)[1];
316 | var url = "https://api-content.dropbox.com/" + _dropboxApiVersion + "/files/dropbox/" + file_path + "?file=" + filename;
317 | var message = _createOauthRequest(url, { method: "POST" });
318 |
319 | _sendOauthRequest(message, {
320 | multipart: true,
321 | content: file,
322 | filename: filename,
323 | success: (function(data) { callback(data); }).bind(this)
324 | });
325 | },
326 |
327 | logOutDropbox: function() {
328 | _clearAuthStorage();
329 | }
330 | }).initialize();
331 | };
332 |
--------------------------------------------------------------------------------
/hosts/dropbox/oauth.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2008 Netflix, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | /* Here's some JavaScript software for implementing OAuth.
18 |
19 | This isn't as useful as you might hope. OAuth is based around
20 | allowing tools and websites to talk to each other. However,
21 | JavaScript running in web browsers is hampered by security
22 | restrictions that prevent code running on one website from
23 | accessing data stored or served on another.
24 |
25 | Before you start hacking, make sure you understand the limitations
26 | posed by cross-domain XMLHttpRequest.
27 |
28 | On the bright side, some platforms use JavaScript as their
29 | language, but enable the programmer to access other web sites.
30 | Examples include Google Gadgets, and Microsoft Vista Sidebar.
31 | For those platforms, this library should come in handy.
32 | */
33 |
34 | // The HMAC-SHA1 signature method calls b64_hmac_sha1, defined by
35 | // http://pajhome.org.uk/crypt/md5/sha1.js
36 |
37 | /* An OAuth message is represented as an object like this:
38 | {method: "GET", action: "http://server.com/path", parameters: ...}
39 |
40 | The parameters may be either a map {name: value, name2: value2}
41 | or an Array of name-value pairs [[name, value], [name2, value2]].
42 | The latter representation is more powerful: it supports parameters
43 | in a specific sequence, or several parameters with the same name;
44 | for example [["a", 1], ["b", 2], ["a", 3]].
45 |
46 | Parameter names and values are NOT percent-encoded in an object.
47 | They must be encoded before transmission and decoded after reception.
48 | For example, this message object:
49 | {method: "GET", action: "http://server/path", parameters: {p: "x y"}}
50 | ... can be transmitted as an HTTP request that begins:
51 | GET /path?p=x%20y HTTP/1.0
52 | (This isn't a valid OAuth request, since it lacks a signature etc.)
53 | Note that the object "x y" is transmitted as x%20y. To encode
54 | parameters, you can call OAuth.addToURL, OAuth.formEncode or
55 | OAuth.getAuthorization.
56 |
57 | This message object model harmonizes with the browser object model for
58 | input elements of an form, whose value property isn't percent encoded.
59 | The browser encodes each value before transmitting it. For example,
60 | see consumer.setInputs in example/consumer.js.
61 | */
62 |
63 | /* This script needs to know what time it is. By default, it uses the local
64 | clock (new Date), which is apt to be inaccurate in browsers. To do
65 | better, you can load this script from a URL whose query string contains
66 | an oauth_timestamp parameter, whose value is a current Unix timestamp.
67 | For example, when generating the enclosing document using PHP:
68 |
69 |
--------------------------------------------------------------------------------
/login_popup.js:
--------------------------------------------------------------------------------
1 | function usrpwd(){
2 | var up = {};
3 | up.usr = document.login_form.usr.value.trim();
4 | up.pwd = document.login_form.pwd.value.trim();
5 | up.keep = document.login_form.loginkeeping.checked;
6 | chrome.tabs.getCurrent(function(tab){
7 | up.tid=tab.id;
8 | chrome.extension.sendRequest(up);
9 | });
10 | }
11 |
12 | document.addEventListener('DOMContentLoaded', function () {
13 | document.login_form.addEventListener('submit',usrpwd);
14 | document.login_form.cancel.addEventListener('click',function(){window.close.call(window)});
15 | });
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "manifest_version": 2,
3 | "name": "Cloud Save",
4 | "version": "1.4.5",
5 | "description": "Save to cloud.",
6 | "background": {
7 | "page": "cloudsave.html"
8 | },
9 | "permissions": [
10 | "*://*/",
11 | "tabs",
12 | "contextMenus",
13 | "unlimitedStorage",
14 | "notifications"
15 | ],
16 | "options_page": "settings.html",
17 | "icons": {
18 | "16": "icon/16.png",
19 | "32": "icon/32.png",
20 | "48": "icon/48.png",
21 | "64": "icon/64.png",
22 | "128": "icon/128.png",
23 | "512": "icon/512.png"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/popup.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
27 |
28 |
29 |
30 | Starting to save file...
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/setting.js:
--------------------------------------------------------------------------------
1 | function toggle_additional(state){
2 | localStorage.additional = state ? 'yes': '';
3 | chrome.extension.getBackgroundPage().install_additional(state);
4 | }
5 | document.getElementById('moar').checked = localStorage.additional=='yes'
6 |
7 | function upload(files){
8 | for(var i = 0; i < files.length; i++){
9 | var url, file = files[i];
10 | if(window.createObjectURL){
11 | url = window.createObjectURL(file)
12 | }else if(window.createBlobURL){
13 | url = window.createBlobURL(file)
14 | }else if(window.URL && window.URL.createObjectURL){
15 | url = window.URL.createObjectURL(file)
16 | }else if(window.webkitURL && window.webkitURL.createObjectURL){
17 | url = window.webkitURL.createObjectURL(file)
18 | }
19 | chrome.extension.getBackgroundPage().upload(document.getElementById('hostselect').value, url, file.name);
20 | }
21 | }
22 |
23 | document.addEventListener('DOMContentLoaded', function (){
24 | var titles = chrome.extension.getBackgroundPage().title_map;
25 | for(var host in titles){
26 | var opt = document.createElement('option');
27 | opt.innerHTML = titles[host];
28 | opt.value = host;
29 | document.getElementById('hostselect').appendChild(opt);
30 | }
31 |
32 | document.querySelector("#moar").addEventListener('change', function(){toggle_additional(this.checked)});
33 | document.querySelector("#file").addEventListener('change', function(){upload(this.files)});
34 | });
--------------------------------------------------------------------------------
/settings.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Cloud Save Settings
5 |
6 |
15 |
16 |
17 | Cloud Save Settings
18 |
19 | Please excuse the fact that this settings page is mostly empty.
20 |
21 |
22 |
23 |
24 |
25 | Local File Upload (Beta):
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------