/app/scripts/comp/dropbox-link.js
JavaScript | 330 lines | 296 code | 33 blank | 1 comment | 40 complexity | 110786474cd7704735ad9c6766e5fb3c MD5 | raw file
- 'use strict';
- var Dropbox = require('dropbox'),
- Alerts = require('./alerts'),
- Launcher = require('./launcher'),
- Logger = require('../util/logger'),
- Locale = require('../util/locale'),
- UrlUtil = require('../util/url-util'),
- AppSettingsModel = require('../models/app-settings-model');
- var logger = new Logger('dropbox');
- var DropboxKeys = {
- AppFolder: 'qp7ctun6qt5n9d6',
- FullDropbox: 'eor7hvv6u6oslq9'
- };
- var DropboxCustomErrors = {
- BadKey: 'bad-key'
- };
- function getKey() {
- return AppSettingsModel.instance.get('dropboxAppKey') || DropboxKeys.AppFolder;
- }
- 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),
- 'app_key': getKey(),
- '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();
- };
- var DropboxLink = {
- ERROR_CONFLICT: Dropbox.ApiError.CONFLICT,
- ERROR_NOT_FOUND: Dropbox.ApiError.NOT_FOUND,
- Keys: DropboxKeys,
- _getClient: function(complete, overrideAppKey) {
- if (this._dropboxClient && this._dropboxClient.isAuthenticated()) {
- complete(null, this._dropboxClient);
- return;
- }
- if (!overrideAppKey && !this.isValidKey()) {
- return complete(DropboxCustomErrors.BadKey);
- }
- var client = new Dropbox.Client({key: overrideAppKey || getKey()});
- if (Launcher) {
- client.authDriver(new Dropbox.AuthDriver.Electron({ receiverUrl: location.href }));
- } else {
- client.authDriver(new Dropbox.AuthDriver.Popup({ receiverUrl: location.href }));
- }
- client.authenticate((function(error, client) {
- if (!error) {
- this._dropboxClient = client;
- }
- complete(error, client);
- }).bind(this));
- },
- _handleUiError: function(err, alertCallback, callback) {
- if (!alertCallback) {
- if (!Alerts.alertDisplayed) {
- alertCallback = Alerts.error.bind(Alerts);
- }
- }
- logger.error('Dropbox error', err);
- switch (err.status) {
- case Dropbox.ApiError.INVALID_TOKEN:
- if (!Alerts.alertDisplayed) {
- Alerts.yesno({
- icon: 'dropbox',
- header: Locale.dropboxLogin,
- body: Locale.dropboxLoginBody,
- buttons: [{result: 'yes', title: Locale.alertSignIn}, {result: '', title: Locale.alertCancel}],
- success: (function () {
- this.authenticate(function (err) { callback(!err); });
- }).bind(this),
- cancel: function () {
- callback(false);
- }
- });
- return;
- }
- break;
- case Dropbox.ApiError.NOT_FOUND:
- alertCallback({
- header: Locale.dropboxSyncError,
- body: Locale.dropboxNotFoundBody
- });
- break;
- case Dropbox.ApiError.OVER_QUOTA:
- alertCallback({
- header: Locale.dropboxFull,
- body: Locale.dropboxFullBody
- });
- break;
- case Dropbox.ApiError.RATE_LIMITED:
- alertCallback({
- header: Locale.dropboxSyncError,
- body: Locale.dropboxRateLimitedBody
- });
- break;
- case Dropbox.ApiError.NETWORK_ERROR:
- alertCallback({
- header: Locale.dropboxNetError,
- body: Locale.dropboxNetErrorBody
- });
- break;
- case Dropbox.ApiError.INVALID_PARAM:
- case Dropbox.ApiError.OAUTH_ERROR:
- case Dropbox.ApiError.INVALID_METHOD:
- alertCallback({
- header: Locale.dropboxSyncError,
- body: Locale.dropboxErrorBody + err.status
- });
- break;
- case Dropbox.ApiError.CONFLICT:
- break;
- default:
- alertCallback({
- header: Locale.dropboxSyncError,
- body: Locale.dropboxErrorRepeatBody + err
- });
- break;
- }
- callback(false);
- },
- _callAndHandleError: function(callName, args, callback, errorAlertCallback) {
- var that = this;
- this._getClient(function(err, client) {
- if (err) {
- return callback(err);
- }
- var ts = logger.ts();
- logger.debug('Call', callName);
- client[callName].apply(client, args.concat(function(err) {
- logger.debug('Result', callName, logger.ts(ts), arguments);
- if (err) {
- that._handleUiError(err, errorAlertCallback, function(repeat) {
- if (repeat) {
- that._callAndHandleError(callName, args, callback, errorAlertCallback);
- } else {
- callback(err);
- }
- });
- } else {
- callback.apply(null, arguments);
- }
- }));
- });
- },
- canUseBuiltInKeys: function() {
- var isSelfHosted = !/^http(s?):\/\/localhost:8085/.test(location.href) &&
- !/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());
- },
- authenticate: function(complete, overrideAppKey) {
- this._getClient(function(err) { complete(err); }, overrideAppKey);
- },
- logout: function() {
- if (this._dropboxClient) {
- try {
- this._dropboxClient.signOut();
- } catch (e) {
- } finally {
- this._dropboxClient.reset();
- }
- }
- },
- resetClient: function() {
- this._dropboxClient = null;
- },
- receive: function() {
- Dropbox.AuthDriver.Popup.oauthReceiver();
- },
- saveFile: function(fileName, data, rev, complete, alertCallback) {
- if (rev) {
- var opts = typeof rev === 'string' ? { lastVersionTag: rev, noOverwrite: true, noAutoRename: true } : undefined;
- this._callAndHandleError('writeFile', [fileName, data, opts], complete, alertCallback);
- } else {
- var dir = UrlUtil.fileToDir(fileName);
- this.list(dir, (function(err, files) {
- 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));
- }
- },
- openFile: function(fileName, complete, errorAlertCallback) {
- this._callAndHandleError('readFile', [fileName, { arrayBuffer: true }], complete, errorAlertCallback);
- },
- stat: function(fileName, complete, errorAlertCallback) {
- this._callAndHandleError('stat', [fileName], complete, errorAlertCallback);
- },
- list: function(dir, complete) {
- this._callAndHandleError('readdir', [dir || ''], function(err, files, dirStat, filesStat) {
- if (files) {
- files = files.filter(function(f) { return /\.kdbx$/i.test(f); });
- }
- complete(err, files, dirStat, filesStat);
- });
- },
- deleteFile: function(fileName, complete) {
- this._callAndHandleError('remove', [fileName], complete);
- },
- canChooseFile: function() {
- return !Launcher;
- },
- chooseFile: function(callback) {
- new DropboxChooser(callback).choose();
- }
- };
- module.exports = DropboxLink;