keeweb/app/scripts/comp/dropbox-link.js

331 lines
11 KiB
JavaScript
Raw Normal View History

2015-10-25 17:27:34 +01:00
'use strict';
2015-10-26 22:07:43 +01:00
var Dropbox = require('dropbox'),
2015-11-15 21:08:26 +01:00
Alerts = require('./alerts'),
Launcher = require('./launcher'),
2015-12-12 09:53:50 +01:00
Logger = require('../util/logger'),
2015-12-17 19:25:25 +01:00
Locale = require('../util/locale'),
2016-03-14 06:04:55 +01:00
UrlUtil = require('../util/url-util'),
2016-03-13 17:45:55 +01:00
AppSettingsModel = require('../models/app-settings-model');
2015-10-25 17:27:34 +01:00
2015-12-12 09:53:50 +01:00
var logger = new Logger('dropbox');
2015-10-25 17:27:34 +01:00
var DropboxKeys = {
AppFolder: 'qp7ctun6qt5n9d6',
FullDropbox: 'eor7hvv6u6oslq9'
2015-10-25 17:27:34 +01:00
};
var DropboxCustomErrors = {
BadKey: 'bad-key'
};
2016-03-13 17:45:55 +01:00
function getKey() {
return AppSettingsModel.instance.get('dropboxAppKey') || DropboxKeys.AppFolder;
}
2015-11-06 21:14:47 +01:00
var DropboxChooser = function(callback) {
this.cb = callback;
this.onMessage = this.onMessage.bind(this);
};
DropboxChooser.prototype.callback = function(err, res) {
if (this.cb) {
this.cb(err, res);
}
this.cb = null;
};
DropboxChooser.prototype.choose = function() {
var windowFeatures = 'width=640,height=552,left=357,top=100,resizable=yes,location=yes';
var url = this.buildUrl();
this.popup = window.open(url, 'dropbox', windowFeatures);
if (!this.popup) {
return this.callback('Failed to open window');
}
window.addEventListener('message', this.onMessage);
this.closeInt = setInterval(this.checkClose.bind(this), 200);
};
DropboxChooser.prototype.buildUrl = function() {
var urlParams = {
origin: encodeURIComponent(window.location.protocol + '//' + window.location.host),
2016-03-13 17:45:55 +01:00
'app_key': getKey(),
2015-11-06 21:14:47 +01:00
'link_type': 'direct',
trigger: 'js',
multiselect: 'false',
extensions: '',
folderselect: 'false',
iframe: 'false',
version: 2
};
return 'https://www.dropbox.com/chooser?' + Object.keys(urlParams).map(function(key) {
return key + '=' + urlParams[key];
}).join('&');
};
DropboxChooser.prototype.onMessage = function(e) {
if (e.source !== this.popup) {
return;
}
var data = JSON.parse(e.data);
switch (data.method) {
case 'origin_request':
e.source.postMessage(JSON.stringify({ method: 'origin' }), 'https://www.dropbox.com');
break;
case 'files_selected':
this.popup.close();
this.success(data.params);
break;
case 'close_dialog':
this.popup.close();
break;
case 'web_session_error':
case 'web_session_unlinked':
this.callback(data.method);
break;
case 'resize':
this.popup.resize(data.params);
break;
case 'error':
this.callback(data.params);
break;
}
};
DropboxChooser.prototype.checkClose = function() {
if (this.popup.closed) {
clearInterval(this.closeInt);
window.removeEventListener('message', this.onMessage);
if (!this.result) {
this.callback('closed');
}
}
};
DropboxChooser.prototype.success = function(params) {
/* jshint camelcase:false */
if (!params || !params[0] || !params[0].link || params[0].is_dir) {
return this.callback('bad result');
}
this.result = params[0];
this.readFile(this.result.link);
};
DropboxChooser.prototype.readFile = function(url) {
var xhr = new XMLHttpRequest();
xhr.addEventListener('load', (function() {
this.callback(null, { name: this.result.name, data: xhr.response });
}).bind(this));
xhr.addEventListener('error', this.callback.bind(this, 'download error'));
xhr.addEventListener('abort', this.callback.bind(this, 'download abort'));
xhr.open('GET', url);
xhr.responseType = 'arraybuffer';
xhr.send();
};
2015-10-25 17:27:34 +01:00
var DropboxLink = {
2015-12-11 21:51:16 +01:00
ERROR_CONFLICT: Dropbox.ApiError.CONFLICT,
2015-12-12 16:43:43 +01:00
ERROR_NOT_FOUND: Dropbox.ApiError.NOT_FOUND,
2016-03-13 17:08:25 +01:00
Keys: DropboxKeys,
2016-03-13 17:45:55 +01:00
_getClient: function(complete, overrideAppKey) {
2015-10-26 22:07:43 +01:00
if (this._dropboxClient && this._dropboxClient.isAuthenticated()) {
2015-10-25 17:27:34 +01:00
complete(null, this._dropboxClient);
return;
}
2016-03-13 17:45:55 +01:00
if (!overrideAppKey && !this.isValidKey()) {
return complete(DropboxCustomErrors.BadKey);
}
2016-03-13 17:45:55 +01:00
var client = new Dropbox.Client({key: overrideAppKey || getKey()});
2015-11-15 21:08:26 +01:00
if (Launcher) {
client.authDriver(new Dropbox.AuthDriver.Electron({ receiverUrl: location.href }));
} else {
client.authDriver(new Dropbox.AuthDriver.Popup({ receiverUrl: location.href }));
}
2015-10-25 17:27:34 +01:00
client.authenticate((function(error, client) {
if (!error) {
this._dropboxClient = client;
}
complete(error, client);
}).bind(this));
},
2015-11-07 20:02:45 +01:00
_handleUiError: function(err, alertCallback, callback) {
if (!alertCallback) {
2015-12-12 09:53:50 +01:00
if (!Alerts.alertDisplayed) {
alertCallback = Alerts.error.bind(Alerts);
}
2015-11-07 20:02:45 +01:00
}
2015-12-12 09:53:50 +01:00
logger.error('Dropbox error', err);
2015-10-26 22:07:43 +01:00
switch (err.status) {
case Dropbox.ApiError.INVALID_TOKEN:
2015-12-12 09:53:50 +01:00
if (!Alerts.alertDisplayed) {
Alerts.yesno({
icon: 'dropbox',
2015-12-17 19:25:25 +01:00
header: Locale.dropboxLogin,
body: Locale.dropboxLoginBody,
buttons: [{result: 'yes', title: Locale.alertSignIn}, {result: '', title: Locale.alertCancel}],
2015-12-12 09:53:50 +01:00
success: (function () {
this.authenticate(function (err) { callback(!err); });
}).bind(this),
cancel: function () {
callback(false);
}
});
return;
}
break;
2015-10-26 22:07:43 +01:00
case Dropbox.ApiError.NOT_FOUND:
2015-11-07 20:02:45 +01:00
alertCallback({
2015-12-17 19:25:25 +01:00
header: Locale.dropboxSyncError,
body: Locale.dropboxNotFoundBody
2015-10-26 22:07:43 +01:00
});
break;
case Dropbox.ApiError.OVER_QUOTA:
2015-11-07 20:02:45 +01:00
alertCallback({
2015-12-17 19:25:25 +01:00
header: Locale.dropboxFull,
body: Locale.dropboxFullBody
2015-10-26 22:07:43 +01:00
});
break;
case Dropbox.ApiError.RATE_LIMITED:
2015-11-07 20:02:45 +01:00
alertCallback({
2015-12-17 19:25:25 +01:00
header: Locale.dropboxSyncError,
body: Locale.dropboxRateLimitedBody
2015-10-26 22:07:43 +01:00
});
break;
case Dropbox.ApiError.NETWORK_ERROR:
2015-11-07 20:02:45 +01:00
alertCallback({
2015-12-17 19:25:25 +01:00
header: Locale.dropboxNetError,
body: Locale.dropboxNetErrorBody
2015-10-26 22:07:43 +01:00
});
break;
case Dropbox.ApiError.INVALID_PARAM:
case Dropbox.ApiError.OAUTH_ERROR:
case Dropbox.ApiError.INVALID_METHOD:
2015-11-07 20:02:45 +01:00
alertCallback({
2015-12-17 19:25:25 +01:00
header: Locale.dropboxSyncError,
body: Locale.dropboxErrorBody + err.status
2015-10-26 22:07:43 +01:00
});
break;
2015-12-11 21:51:16 +01:00
case Dropbox.ApiError.CONFLICT:
break;
2015-10-26 22:07:43 +01:00
default:
2015-11-07 20:02:45 +01:00
alertCallback({
2015-12-17 19:25:25 +01:00
header: Locale.dropboxSyncError,
body: Locale.dropboxErrorRepeatBody + err
2015-10-26 22:07:43 +01:00
});
break;
}
callback(false);
2015-10-25 17:27:34 +01:00
},
2015-11-07 20:02:45 +01:00
_callAndHandleError: function(callName, args, callback, errorAlertCallback) {
2015-10-26 22:07:43 +01:00
var that = this;
2015-10-25 17:27:34 +01:00
this._getClient(function(err, client) {
2015-10-26 22:07:43 +01:00
if (err) {
return callback(err);
2015-10-25 17:27:34 +01:00
}
2015-12-12 09:53:50 +01:00
var ts = logger.ts();
logger.debug('Call', callName);
client[callName].apply(client, args.concat(function(err) {
2015-12-12 09:53:50 +01:00
logger.debug('Result', callName, logger.ts(ts), arguments);
2015-10-26 22:07:43 +01:00
if (err) {
2015-11-07 20:02:45 +01:00
that._handleUiError(err, errorAlertCallback, function(repeat) {
2015-10-26 22:07:43 +01:00
if (repeat) {
2015-11-07 20:02:45 +01:00
that._callAndHandleError(callName, args, callback, errorAlertCallback);
2015-10-26 22:07:43 +01:00
} else {
callback(err);
}
});
} else {
callback.apply(null, arguments);
2015-10-26 22:07:43 +01:00
}
}));
2015-10-25 17:27:34 +01:00
});
},
canUseBuiltInKeys: function() {
var isSelfHosted = !/^http(s?):\/\/localhost:8085/.test(location.href) &&
2016-03-17 22:58:48 +01:00
!/http(s?):\/\/(app|beta)\.keeweb\.info/.test(location.href);
return !!Launcher || !isSelfHosted;
},
getKey: getKey,
isValidKey: function() {
var key = getKey();
var isBuiltIn = key === DropboxKeys.AppFolder || key === DropboxKeys.FullDropbox;
return key && key.indexOf(' ') < 0 && (!isBuiltIn || this.canUseBuiltInKeys());
2016-03-13 17:45:55 +01:00
},
authenticate: function(complete, overrideAppKey) {
this._getClient(function(err) { complete(err); }, overrideAppKey);
2015-10-26 22:07:43 +01:00
},
logout: function() {
if (this._dropboxClient) {
try {
this._dropboxClient.signOut();
} catch (e) {
} finally {
this._dropboxClient.reset();
}
}
},
2016-03-17 22:49:39 +01:00
resetClient: function() {
this._dropboxClient = null;
},
2015-10-26 22:07:43 +01:00
receive: function() {
Dropbox.AuthDriver.Popup.oauthReceiver();
},
2015-12-12 09:53:50 +01:00
saveFile: function(fileName, data, rev, complete, alertCallback) {
2015-12-10 20:44:02 +01:00
if (rev) {
2015-12-11 21:51:16 +01:00
var opts = typeof rev === 'string' ? { lastVersionTag: rev, noOverwrite: true, noAutoRename: true } : undefined;
2015-12-12 09:53:50 +01:00
this._callAndHandleError('writeFile', [fileName, data, opts], complete, alertCallback);
2015-10-26 22:07:43 +01:00
} else {
2016-03-14 06:04:55 +01:00
var dir = UrlUtil.fileToDir(fileName);
this.list(dir, (function(err, files) {
2015-10-26 22:07:43 +01:00
if (err) { return complete(err); }
var exists = files.some(function(file) { return file.toLowerCase() === fileName.toLowerCase(); });
if (exists) { return complete({ exists: true }); }
this._callAndHandleError('writeFile', [fileName, data], complete);
}).bind(this));
}
},
2015-11-07 20:02:45 +01:00
openFile: function(fileName, complete, errorAlertCallback) {
2015-12-07 22:00:44 +01:00
this._callAndHandleError('readFile', [fileName, { arrayBuffer: true }], complete, errorAlertCallback);
2015-10-25 17:27:34 +01:00
},
2015-12-12 09:53:50 +01:00
stat: function(fileName, complete, errorAlertCallback) {
this._callAndHandleError('stat', [fileName], complete, errorAlertCallback);
2015-12-08 20:18:35 +01:00
},
2016-03-14 06:04:55 +01:00
list: function(dir, complete) {
this._callAndHandleError('readdir', [dir || ''], function(err, files, dirStat, filesStat) {
2015-10-26 22:07:43 +01:00
if (files) {
2015-10-25 17:27:34 +01:00
files = files.filter(function(f) { return /\.kdbx$/i.test(f); });
2015-10-26 22:07:43 +01:00
}
2015-12-07 20:07:56 +01:00
complete(err, files, dirStat, filesStat);
2015-10-25 17:27:34 +01:00
});
2015-11-06 21:14:47 +01:00
},
2015-12-12 16:43:43 +01:00
deleteFile: function(fileName, complete) {
this._callAndHandleError('remove', [fileName], complete);
},
canChooseFile: function() {
return !Launcher;
},
2015-11-06 21:14:47 +01:00
chooseFile: function(callback) {
new DropboxChooser(callback).choose();
2015-10-25 17:27:34 +01:00
}
};
module.exports = DropboxLink;