2158 lines
80 KiB
JavaScript
2158 lines
80 KiB
JavaScript
define([
|
||
'/api/config',
|
||
'/customize/messages.js',
|
||
'/common/common-util.js',
|
||
'/common/common-hash.js',
|
||
'/common/common-messaging.js',
|
||
'/common/common-constants.js',
|
||
'/common/common-feedback.js',
|
||
'/common/userObject.js',
|
||
'/common/outer/local-store.js',
|
||
'/common/outer/worker-channel.js',
|
||
'/common/outer/login-block.js',
|
||
|
||
'/customize/application_config.js',
|
||
'/bower_components/nthen/index.js',
|
||
], function (Config, Messages, Util, Hash,
|
||
Messaging, Constants, Feedback, UserObject, LocalStore, Channel, Block,
|
||
AppConfig, Nthen) {
|
||
|
||
/* This file exposes functionality which is specific to Cryptpad, but not to
|
||
any particular pad type. This includes functions for committing metadata
|
||
about pads to your local storage for future use and improved usability.
|
||
|
||
Additionally, there is some basic functionality for import/export.
|
||
*/
|
||
var urlArgs = Util.find(Config, ['requireConf', 'urlArgs']) || '';
|
||
|
||
var postMessage = function (/*cmd, data, cb*/) {
|
||
/*setTimeout(function () {
|
||
AStore.query(cmd, data, cb);
|
||
});*/
|
||
console.error('NOT_READY');
|
||
};
|
||
var tryParsing = function (x) {
|
||
try { return JSON.parse(x); }
|
||
catch (e) {
|
||
console.error(e);
|
||
return null;
|
||
}
|
||
};
|
||
|
||
// Upgrade and donate URLs duplicated in pages.js
|
||
var origin = encodeURIComponent(window.location.hostname);
|
||
var common = window.Cryptpad = {
|
||
Messages: Messages,
|
||
//donateURL: 'https://accounts.cryptpad.fr/#/donate?on=' + origin,
|
||
donateURL: "https://opencollective.com/cryptpad/",
|
||
upgradeURL: 'https://accounts.cryptpad.fr/#/?on=' + origin,
|
||
account: {},
|
||
};
|
||
|
||
// COMMON
|
||
common.getLanguage = function () {
|
||
return Messages._languageUsed;
|
||
};
|
||
common.setLanguage = function (l, cb) {
|
||
var LS_LANG = "CRYPTPAD_LANG";
|
||
localStorage.setItem(LS_LANG, l);
|
||
cb();
|
||
};
|
||
|
||
common.makeNetwork = function (cb) {
|
||
require([
|
||
'/bower_components/netflux-websocket/netflux-client.js',
|
||
'/common/outer/network-config.js'
|
||
], function (Netflux, NetConfig) {
|
||
var wsUrl = NetConfig.getWebsocketURL();
|
||
Netflux.connect(wsUrl).then(function (network) {
|
||
cb(null, network);
|
||
}, function (err) {
|
||
cb(err);
|
||
});
|
||
});
|
||
};
|
||
|
||
// RESTRICTED
|
||
// Settings only
|
||
common.resetDrive = function (cb) {
|
||
postMessage("RESET_DRIVE", null, function (obj) {
|
||
if (obj && obj.error) { return void cb(obj.error); }
|
||
cb();
|
||
});
|
||
};
|
||
common.logoutFromAll = function (cb) {
|
||
var token = Math.floor(Math.random()*Number.MAX_SAFE_INTEGER);
|
||
localStorage.setItem(Constants.tokenKey, token);
|
||
postMessage("SET", {
|
||
key: [Constants.tokenKey],
|
||
value: token
|
||
}, function (obj) {
|
||
if (obj && obj.error) { return void cb(obj.error); }
|
||
cb();
|
||
});
|
||
};
|
||
// Settings and drive and auth
|
||
common.getUserObject = function (teamId, cb) {
|
||
postMessage("GET", {
|
||
teamId: teamId,
|
||
key: []
|
||
}, function (obj) {
|
||
cb(obj);
|
||
});
|
||
};
|
||
common.getSharedFolder = function (data, cb) {
|
||
postMessage("GET_SHARED_FOLDER", data, function (obj) {
|
||
cb(obj);
|
||
});
|
||
};
|
||
common.loadSharedFolder = function (id, data, cb) {
|
||
postMessage("LOAD_SHARED_FOLDER", {
|
||
id: id,
|
||
data: data
|
||
}, cb);
|
||
};
|
||
common.getEdPublic = function (teamId, cb) {
|
||
postMessage("GET", {
|
||
key: teamId ? ['teams', teamId, 'keys', 'drive', 'edPublic'] : ['edPublic']
|
||
}, function (obj) {
|
||
cb(obj);
|
||
});
|
||
};
|
||
// Settings and ready
|
||
common.mergeAnonDrive = function (cb) {
|
||
var data = {
|
||
anonHash: LocalStore.getFSHash()
|
||
};
|
||
postMessage("MIGRATE_ANON_DRIVE", data, cb);
|
||
};
|
||
// Settings
|
||
common.deleteAccount = function (cb) {
|
||
postMessage("DELETE_ACCOUNT", null, function (obj) {
|
||
if (obj.state) {
|
||
Feedback.send('DELETE_ACCOUNT_AUTOMATIC');
|
||
} else {
|
||
Feedback.send('DELETE_ACCOUNT_MANUAL');
|
||
}
|
||
cb(obj);
|
||
});
|
||
};
|
||
// Drive
|
||
common.userObjectCommand = function (data, cb) {
|
||
postMessage("DRIVE_USEROBJECT", data, cb);
|
||
};
|
||
common.restoreDrive = function (data, cb) {
|
||
if (data.sfId) { // Shared folder ID
|
||
postMessage('RESTORE_SHARED_FOLDER', data, cb, {
|
||
timeout: 5 * 60 * 1000
|
||
});
|
||
return;
|
||
}
|
||
postMessage("SET", {
|
||
teamId: data.teamId,
|
||
key:['drive'],
|
||
value: data.drive
|
||
}, function (obj) {
|
||
cb(obj);
|
||
}, {
|
||
timeout: 5 * 60 * 1000
|
||
});
|
||
};
|
||
common.addSharedFolder = function (teamId, secret, cb) {
|
||
var href = (secret.keys && secret.keys.editKeyStr) ? '/drive/#' + Hash.getEditHashFromKeys(secret) : undefined;
|
||
postMessage("ADD_SHARED_FOLDER", {
|
||
teamId: teamId,
|
||
path: ['root'],
|
||
folderData: {
|
||
href: href,
|
||
roHref: '/drive/#' + Hash.getViewHashFromKeys(secret),
|
||
channel: secret.channel,
|
||
password: secret.password,
|
||
ctime: +new Date()
|
||
}
|
||
}, cb);
|
||
};
|
||
common.drive = {};
|
||
common.drive.onLog = Util.mkEvent();
|
||
common.drive.onChange = Util.mkEvent();
|
||
common.drive.onRemove = Util.mkEvent();
|
||
// Profile
|
||
common.getProfileEditUrl = function (cb) {
|
||
postMessage("GET", { key: ['profile', 'edit'] }, function (obj) {
|
||
cb(obj);
|
||
});
|
||
};
|
||
common.setNewProfile = function (profile) {
|
||
postMessage("SET", {
|
||
key: ['profile'],
|
||
value: profile
|
||
}, function () {});
|
||
};
|
||
common.setAvatar = function (data, cb) {
|
||
var postData = {
|
||
key: ['profile', 'avatar']
|
||
};
|
||
// If we don't have "data", it means we want to remove the avatar and we should not have a
|
||
// "postData.value", even set to undefined (JSON.stringify transforms undefined to null)
|
||
if (data) { postData.value = data; }
|
||
postMessage("SET", postData, cb);
|
||
};
|
||
// Todo
|
||
common.getTodoHash = function (cb) {
|
||
postMessage("GET", { key: ['todo'] }, function (obj) {
|
||
cb(obj);
|
||
});
|
||
};
|
||
common.setTodoHash = function (hash) {
|
||
postMessage("SET", {
|
||
key: ['todo'],
|
||
value: hash
|
||
}, function () {});
|
||
};
|
||
|
||
|
||
// RPC
|
||
common.pinPads = function (pads, cb, teamId) {
|
||
var data = {
|
||
teamId: teamId,
|
||
pads: pads
|
||
};
|
||
postMessage("PIN_PADS", data, function (obj) {
|
||
if (obj && obj.error) { return void cb(obj.error); }
|
||
cb(null, obj.hash);
|
||
});
|
||
};
|
||
|
||
common.unpinPads = function (pads, cb, teamId) {
|
||
var data = {
|
||
teamId: teamId,
|
||
pads: pads
|
||
};
|
||
postMessage("UNPIN_PADS", data, function (obj) {
|
||
if (obj && obj.error) { return void cb(obj.error); }
|
||
cb(null, obj.hash);
|
||
});
|
||
};
|
||
|
||
common.getPinnedUsage = function (data, cb) {
|
||
postMessage("GET_PINNED_USAGE", data, function (obj) {
|
||
if (obj.error) { return void cb(obj.error); }
|
||
cb(null, obj.bytes);
|
||
});
|
||
};
|
||
|
||
common.updatePinLimit = function (cb) {
|
||
postMessage("UPDATE_PIN_LIMIT", null, function (obj) {
|
||
if (obj.error) { return void cb(obj.error); }
|
||
cb(undefined, obj.limit, obj.plan, obj.note);
|
||
});
|
||
};
|
||
|
||
common.getPinLimit = function (data, cb) {
|
||
postMessage("GET_PIN_LIMIT", data, function (obj) {
|
||
if (obj.error) { return void cb(obj.error); }
|
||
cb(undefined, obj.limit, obj.plan, obj.note);
|
||
});
|
||
};
|
||
|
||
common.isOverPinLimit = function (teamId, cb) {
|
||
if (!LocalStore.isLoggedIn()) { return void cb(null, false); }
|
||
var usage;
|
||
var andThen = function (e, limit, plan) {
|
||
if (e) { return void cb(e); }
|
||
var data = {usage: usage, limit: limit, plan: plan};
|
||
if (usage > limit) {
|
||
return void cb (null, true, data);
|
||
}
|
||
return void cb (null, false, data);
|
||
};
|
||
var todo = function (e, used) {
|
||
if (e) { return void cb(e); }
|
||
usage = used;
|
||
common.getPinLimit({
|
||
teamId: teamId
|
||
}, andThen);
|
||
};
|
||
common.getPinnedUsage({
|
||
teamId: teamId
|
||
}, todo);
|
||
};
|
||
|
||
common.clearOwnedChannel = function (channel, cb) {
|
||
postMessage("CLEAR_OWNED_CHANNEL", channel, cb);
|
||
};
|
||
// "force" allows you to delete your drive ID
|
||
common.removeOwnedChannel = function (data, cb) {
|
||
postMessage("REMOVE_OWNED_CHANNEL", data, cb);
|
||
};
|
||
|
||
common.getDeletedPads = function (data, cb) {
|
||
postMessage("GET_DELETED_PADS", data, function (obj) {
|
||
if (obj && obj.error) { return void cb(obj.error); }
|
||
cb(null, obj);
|
||
});
|
||
};
|
||
|
||
common.uploadComplete = function (teamId, id, owned, cb) {
|
||
postMessage("UPLOAD_COMPLETE", {teamId: teamId, id: id, owned: owned}, function (obj) {
|
||
if (obj && obj.error) { return void cb(obj.error); }
|
||
cb(null, obj);
|
||
});
|
||
};
|
||
|
||
common.uploadStatus = function (teamId, size, cb) {
|
||
postMessage("UPLOAD_STATUS", {teamId: teamId, size: size}, function (obj) {
|
||
if (obj && obj.error) { return void cb(obj.error); }
|
||
cb(null, obj);
|
||
});
|
||
};
|
||
|
||
common.uploadCancel = function (teamId, size, cb) {
|
||
postMessage("UPLOAD_CANCEL", {teamId: teamId, size: size}, function (obj) {
|
||
if (obj && obj.error) { return void cb(obj.error); }
|
||
cb(null, obj);
|
||
});
|
||
};
|
||
|
||
common.uploadChunk = function (teamId, data, cb) {
|
||
postMessage("UPLOAD_CHUNK", {teamId: teamId, chunk: data}, function (obj) {
|
||
if (obj && obj.error) { return void cb(obj.error); }
|
||
cb(null, obj);
|
||
});
|
||
};
|
||
|
||
common.writeLoginBlock = function (data, cb) {
|
||
postMessage('WRITE_LOGIN_BLOCK', data, function (obj) {
|
||
cb(obj);
|
||
});
|
||
};
|
||
|
||
common.removeLoginBlock = function (data, cb) {
|
||
postMessage('REMOVE_LOGIN_BLOCK', data, function (obj) {
|
||
cb(obj);
|
||
});
|
||
};
|
||
|
||
// ANON RPC
|
||
|
||
// SFRAME: talk to anon_rpc from the iframe
|
||
common.anonRpcMsg = function (msg, data, cb) {
|
||
if (!msg) { return; }
|
||
postMessage("ANON_RPC_MESSAGE", {
|
||
msg: msg,
|
||
data: data
|
||
}, function (obj) {
|
||
if (obj && obj.error) { return void cb(obj.error); }
|
||
cb(null, obj);
|
||
});
|
||
};
|
||
|
||
common.getFileSize = function (href, password, cb) {
|
||
postMessage("GET_FILE_SIZE", {href: href, password: password}, function (obj) {
|
||
if (obj && obj.error) { return void cb(obj.error); }
|
||
cb(undefined, obj.size);
|
||
});
|
||
};
|
||
|
||
common.getMultipleFileSize = function (files, cb) {
|
||
postMessage("GET_MULTIPLE_FILE_SIZE", {files:files}, function (obj) {
|
||
if (obj.error) { return void cb(obj.error); }
|
||
cb(undefined, obj.size);
|
||
});
|
||
};
|
||
|
||
common.isNewChannel = function (href, password, cb) {
|
||
postMessage('IS_NEW_CHANNEL', {href: href, password: password}, function (obj) {
|
||
if (obj.error) { return void cb(obj.error); }
|
||
if (!obj) { return void cb('INVALID_RESPONSE'); }
|
||
cb(undefined, obj.isNew);
|
||
});
|
||
};
|
||
|
||
// Store
|
||
|
||
|
||
|
||
common.getMetadata = function (cb) {
|
||
var parsed = Hash.parsePadUrl(window.location.href);
|
||
postMessage("GET_METADATA", parsed && parsed.type, function (obj) {
|
||
if (obj && obj.error) { return void cb(obj.error); }
|
||
cb(null, obj);
|
||
});
|
||
};
|
||
|
||
common.isOnlyInSharedFolder = function (data, cb) {
|
||
postMessage("IS_ONLY_IN_SHARED_FOLDER", data, function (obj) {
|
||
if (obj && obj.error) { return void cb(obj.error); }
|
||
cb(null, obj);
|
||
});
|
||
};
|
||
|
||
common.setDisplayName = function (value, cb) {
|
||
postMessage("SET_DISPLAY_NAME", value, cb);
|
||
};
|
||
|
||
common.setPadAttribute = function (attr, value, cb, href) {
|
||
cb = cb || function () {};
|
||
href = Hash.getRelativeHref(href || window.location.href);
|
||
postMessage("SET_PAD_ATTRIBUTE", {
|
||
href: href,
|
||
attr: attr,
|
||
value: value
|
||
}, function (obj) {
|
||
if (obj && obj.error) { return void cb(obj.error); }
|
||
cb();
|
||
});
|
||
};
|
||
common.getPadAttribute = function (attr, cb, href) {
|
||
href = Hash.getRelativeHref(href || window.location.href);
|
||
if (!href) {
|
||
return void cb('E404');
|
||
}
|
||
postMessage("GET_PAD_ATTRIBUTE", {
|
||
href: href,
|
||
attr: attr,
|
||
}, function (obj) {
|
||
if (obj && obj.error) { return void cb(obj.error); }
|
||
cb(null, obj);
|
||
});
|
||
};
|
||
common.setAttribute = function (attr, value, cb) {
|
||
cb = cb || function () {};
|
||
postMessage("SET_ATTRIBUTE", {
|
||
attr: attr,
|
||
value: value
|
||
}, function (obj) {
|
||
if (obj && obj.error) { return void cb(obj.error); }
|
||
cb();
|
||
});
|
||
};
|
||
common.getAttribute = function (attr, cb) {
|
||
postMessage("GET_ATTRIBUTE", {
|
||
attr: attr
|
||
}, function (obj) {
|
||
if (obj && obj.error) { return void cb(obj.error); }
|
||
cb(null, obj);
|
||
});
|
||
};
|
||
|
||
// Tags
|
||
common.resetTags = function (href, tags, cb) {
|
||
// set pad attribute
|
||
cb = cb || function () {};
|
||
if (!Array.isArray(tags)) { return void cb('INVALID_TAGS'); }
|
||
common.setPadAttribute('tags', tags.slice(), cb, href);
|
||
};
|
||
common.tagPad = function (href, tag, cb) {
|
||
if (typeof(cb) !== 'function') {
|
||
return void console.error('EXPECTED_CALLBACK');
|
||
}
|
||
if (typeof(tag) !== 'string') { return void cb('INVALID_TAG'); }
|
||
common.getPadAttribute('tags', function (e, tags) {
|
||
if (e) { return void cb(e); }
|
||
var newTags;
|
||
if (!tags) {
|
||
newTags = [tag];
|
||
} else if (tags.indexOf(tag) === -1) {
|
||
newTags = tags.slice();
|
||
newTags.push(tag);
|
||
}
|
||
common.setPadAttribute('tags', newTags, cb, href);
|
||
}, href);
|
||
};
|
||
common.untagPad = function (href, tag, cb) {
|
||
if (typeof(cb) !== 'function') {
|
||
return void console.error('EXPECTED_CALLBACK');
|
||
}
|
||
if (typeof(tag) !== 'string') { return void cb('INVALID_TAG'); }
|
||
common.getPadAttribute('tags', function (e, tags) {
|
||
if (e) { return void cb(e); }
|
||
if (!tags) { return void cb(); }
|
||
var idx = tags.indexOf(tag);
|
||
if (idx === -1) { return void cb(); }
|
||
var newTags = tags.slice();
|
||
newTags.splice(idx, 1);
|
||
common.setPadAttribute('tags', newTags, cb, href);
|
||
}, href);
|
||
};
|
||
common.getPadTags = function (href, cb) {
|
||
if (typeof(cb) !== 'function') { return; }
|
||
common.getPadAttribute('tags', function (e, tags) {
|
||
if (e) { return void cb(e); }
|
||
cb(void 0, tags ? tags.slice() : []);
|
||
}, href);
|
||
};
|
||
common.listAllTags = function (cb) {
|
||
postMessage("LIST_ALL_TAGS", null, function (obj) {
|
||
if (obj && obj.error) { return void cb(obj.error); }
|
||
cb(void 0, obj);
|
||
});
|
||
};
|
||
|
||
// STORAGE - TEMPLATES
|
||
common.listTemplates = function (type, cb) {
|
||
postMessage("GET_TEMPLATES", null, function (obj) {
|
||
if (obj && obj.error) { return void cb(obj.error); }
|
||
if (!Array.isArray(obj)) { return void cb ('NOT_AN_ARRAY'); }
|
||
if (!type) { return void cb(null, obj); }
|
||
|
||
var templates = obj.filter(function (f) {
|
||
var parsed = Hash.parsePadUrl(f.href);
|
||
return parsed.type === type;
|
||
});
|
||
cb(null, templates);
|
||
});
|
||
};
|
||
|
||
common.saveAsTemplate = function (Cryptput, data, cb) {
|
||
var p = Hash.parsePadUrl(window.location.href);
|
||
if (!p.type) { return; }
|
||
// PPP: password for the new template?
|
||
var hash = Hash.createRandomHash(p.type);
|
||
var href = '/' + p.type + '/#' + hash;
|
||
|
||
var optsPut = {};
|
||
if (p.type === 'poll') { optsPut.initialState = '{}'; }
|
||
// PPP: add password as cryptput option
|
||
Cryptput(hash, data.toSave, function (e) {
|
||
if (e) { throw new Error(e); }
|
||
postMessage("ADD_PAD", {
|
||
teamId: data.teamId,
|
||
href: href,
|
||
title: data.title,
|
||
path: ['template']
|
||
}, function (obj) {
|
||
if (obj && obj.error) { return void cb(obj.error); }
|
||
cb();
|
||
});
|
||
}, optsPut);
|
||
};
|
||
|
||
common.isTemplate = function (href, cb) {
|
||
var rhref = Hash.getRelativeHref(href);
|
||
common.listTemplates(null, function (err, templates) {
|
||
cb(void 0, templates.some(function (t) {
|
||
return t.href === rhref;
|
||
}));
|
||
});
|
||
};
|
||
|
||
common.useTemplate = function (data, Crypt, cb, optsPut) {
|
||
// opts is used to overrides options for chainpad-netflux in cryptput
|
||
// it allows us to add owners and expiration time if it is a new file
|
||
var href = data.href;
|
||
|
||
var parsed = Hash.parsePadUrl(href);
|
||
var parsed2 = Hash.parsePadUrl(window.location.href);
|
||
if(!parsed) { throw new Error("Cannot get template hash"); }
|
||
postMessage("INCREMENT_TEMPLATE_USE", href);
|
||
|
||
optsPut = optsPut || {};
|
||
var optsGet = {};
|
||
|
||
if (parsed.type === 'poll') { optsGet.initialState = '{}'; }
|
||
if (parsed2.type === 'poll') { optsPut.initialState = '{}'; }
|
||
|
||
Nthen(function (waitFor) {
|
||
if (parsed.hashData && parsed.hashData.password) {
|
||
common.getPadAttribute('password', waitFor(function (err, password) {
|
||
optsGet.password = password;
|
||
}), href);
|
||
}
|
||
if (parsed2.hashData && parsed2.hashData.password && !optsPut.password) {
|
||
common.getPadAttribute('password', waitFor(function (err, password) {
|
||
optsPut.password = password;
|
||
}));
|
||
}
|
||
}).nThen(function () {
|
||
Crypt.get(parsed.hash, function (err, val) {
|
||
if (err) { throw new Error(err); }
|
||
try {
|
||
// Try to fix the title before importing the template
|
||
var parsed = JSON.parse(val);
|
||
var meta;
|
||
if (Array.isArray(parsed) && typeof(parsed[3]) === "object") {
|
||
meta = parsed[3].metadata; // pad
|
||
} else if (parsed.info) {
|
||
meta = parsed.info; // poll
|
||
} else {
|
||
meta = parsed.metadata;
|
||
}
|
||
if (typeof(meta) === "object") {
|
||
meta.defaultTitle = meta.title || meta.defaultTitle;
|
||
meta.title = "";
|
||
delete meta.users;
|
||
delete meta.chat2;
|
||
delete meta.chat;
|
||
delete meta.cursor;
|
||
if (data.chat) { meta.chat2 = data.chat; }
|
||
if (data.cursor) { meta.cursor = data.cursor; }
|
||
}
|
||
val = JSON.stringify(parsed);
|
||
} catch (e) {
|
||
console.log("Can't fix template title", e);
|
||
}
|
||
Crypt.put(parsed2.hash, val, cb, optsPut);
|
||
}, optsGet);
|
||
});
|
||
};
|
||
|
||
common.useFile = function (Crypt, cb, optsPut) {
|
||
var fileHost = Config.fileHost || window.location.origin;
|
||
var data = common.fromFileData;
|
||
var parsed = Hash.parsePadUrl(data.href);
|
||
var parsed2 = Hash.parsePadUrl(window.location.href);
|
||
var hash = parsed.hash;
|
||
var name = data.title;
|
||
var secret = Hash.getSecrets('file', hash, data.password);
|
||
var src = fileHost + Hash.getBlobPathFromHex(secret.channel);
|
||
var key = secret.keys && secret.keys.cryptKey;
|
||
|
||
var u8;
|
||
var res;
|
||
var mode;
|
||
var val;
|
||
Nthen(function(waitFor) {
|
||
Util.fetch(src, waitFor(function (err, _u8) {
|
||
if (err) { return void waitFor.abort(); }
|
||
u8 = _u8;
|
||
}));
|
||
}).nThen(function (waitFor) {
|
||
require(["/file/file-crypto.js"], waitFor(function (FileCrypto) {
|
||
FileCrypto.decrypt(u8, key, waitFor(function (err, _res) {
|
||
if (err || !_res.content) { return void waitFor.abort(); }
|
||
res = _res;
|
||
}));
|
||
}));
|
||
}).nThen(function (waitFor) {
|
||
var ext = Util.parseFilename(data.title).ext;
|
||
if (!ext) {
|
||
mode = "text";
|
||
return;
|
||
}
|
||
require(["/common/modes.js"], waitFor(function (Modes) {
|
||
Modes.list.some(function (fType) {
|
||
if (fType.ext === ext) {
|
||
mode = fType.mode;
|
||
return true;
|
||
}
|
||
});
|
||
}));
|
||
}).nThen(function (waitFor) {
|
||
var reader = new FileReader();
|
||
reader.addEventListener('loadend', waitFor(function (e) {
|
||
val = {
|
||
content: e.srcElement.result,
|
||
highlightMode: mode,
|
||
metadata: {
|
||
defaultTitle: name,
|
||
title: name,
|
||
type: "code",
|
||
},
|
||
};
|
||
}));
|
||
reader.readAsText(res.content);
|
||
}).nThen(function () {
|
||
Crypt.put(parsed2.hash, JSON.stringify(val), cb, optsPut);
|
||
});
|
||
|
||
};
|
||
|
||
// Forget button
|
||
common.moveToTrash = function (cb, href) {
|
||
href = href || window.location.href;
|
||
postMessage("MOVE_TO_TRASH", { href: href }, cb);
|
||
};
|
||
|
||
// When opening a new pad or renaming it, store the new title
|
||
common.setPadTitle = function (data, cb) {
|
||
if (!data || typeof (data) !== "object") { return cb ('Data is not an object'); }
|
||
|
||
var href = data.href || window.location.href;
|
||
var parsed = Hash.parsePadUrl(href);
|
||
if (!parsed.hash) { return cb ('Invalid hash'); }
|
||
data.href = parsed.getUrl({present: parsed.present});
|
||
|
||
if (typeof (data.title) !== "string") { return cb('Missing title'); }
|
||
|
||
if (common.initialTeam) {
|
||
// If the value is -1, it means the user drive was selected from the pad creation screen
|
||
// If the value is a positive Integer, force save in the team with the selected ID
|
||
if (common.initialTeam !== -1) {
|
||
// Team selected from the PCS or pad created from a team drive
|
||
data.teamId = common.initialTeam;
|
||
}
|
||
data.forceSave = 1;
|
||
delete common.initialTeam;
|
||
}
|
||
if (common.initialPath) {
|
||
if (!data.path) {
|
||
data.path = Array.isArray(common.initialPath) ? common.initialPath
|
||
: decodeURIComponent(common.initialPath).split(',');
|
||
delete common.initialPath;
|
||
}
|
||
}
|
||
|
||
postMessage("SET_PAD_TITLE", data, function (obj) {
|
||
if (obj && obj.error) {
|
||
if (obj.error !== "EAUTH") { console.log("unable to set pad title"); }
|
||
return void cb(obj.error);
|
||
}
|
||
cb();
|
||
});
|
||
};
|
||
|
||
common.storeInTeam = function (data, cb) {
|
||
if (!data.href) { return void cb({error: 'EINVAL'}); }
|
||
var parsed = Hash.parsePadUrl(data.href);
|
||
var secret = Hash.getSecrets(parsed.type, parsed.hash, data.password);
|
||
if (!secret || !secret.channel) { return void cb ({error: 'EINVAL'}); }
|
||
|
||
if (parsed.type === 'drive') {
|
||
// Shared folder
|
||
var teamId = data.teamId === -1 ? undefined : data.teamId;
|
||
common.addSharedFolder(teamId, secret, cb);
|
||
return;
|
||
}
|
||
|
||
Nthen(function (waitFor) {
|
||
if (parsed.hashData.type !== 'pad') { return; }
|
||
// Set the correct owner and expiration time if we can find them
|
||
postMessage('GET_PAD_METADATA', {
|
||
channel: secret.channel
|
||
}, waitFor(function (obj) {
|
||
if (!obj || obj.error) { return; }
|
||
data.owners = obj.owners;
|
||
data.expire = +obj.expire;
|
||
}));
|
||
}).nThen(function () {
|
||
postMessage("SET_PAD_TITLE", {
|
||
teamId: data.teamId,
|
||
href: Hash.getRelativeHref(data.href),
|
||
title: data.title,
|
||
password: data.password,
|
||
channel: secret.channel,
|
||
path: data.path,
|
||
owners: data.owners,
|
||
expire: data.expire,
|
||
forceSave: 1
|
||
}, function (obj) {
|
||
if (obj && obj.error) { return void cb(obj.error); }
|
||
cb();
|
||
});
|
||
});
|
||
};
|
||
|
||
// Needed for the secure filepicker app
|
||
common.getSecureFilesList = function (query, cb) {
|
||
postMessage("GET_SECURE_FILES_LIST", query, function (list) {
|
||
cb(void 0, list);
|
||
});
|
||
};
|
||
// Get a template href from its id
|
||
common.getPadData = function (id, cb) {
|
||
postMessage("GET_PAD_DATA", id, function (data) {
|
||
cb(void 0, data);
|
||
});
|
||
};
|
||
|
||
|
||
// Admin
|
||
common.adminRpc = function (data, cb) {
|
||
postMessage("ADMIN_RPC", data, cb);
|
||
};
|
||
common.addAdminMailbox = function (data, cb) {
|
||
postMessage("ADMIN_ADD_MAILBOX", data, cb);
|
||
};
|
||
|
||
// Network
|
||
common.onNetworkDisconnect = Util.mkEvent();
|
||
common.onNetworkReconnect = Util.mkEvent();
|
||
common.onNewVersionReconnect = Util.mkEvent();
|
||
|
||
// Messaging (friend requests)
|
||
var messaging = common.messaging = {};
|
||
messaging.answerFriendRequest = function (data, cb) {
|
||
postMessage("ANSWER_FRIEND_REQUEST", data, cb);
|
||
};
|
||
messaging.sendFriendRequest = function (data, cb) {
|
||
postMessage("SEND_FRIEND_REQUEST", data, cb);
|
||
};
|
||
|
||
// Team
|
||
common.anonGetPreviewContent = function (data, cb) {
|
||
postMessage("ANON_GET_PREVIEW_CONTENT", data, cb);
|
||
};
|
||
|
||
// Onlyoffice
|
||
var onlyoffice = common.onlyoffice = {};
|
||
onlyoffice.execCommand = function (data, cb) {
|
||
postMessage("OO_COMMAND", data, cb);
|
||
};
|
||
onlyoffice.onEvent = Util.mkEvent();
|
||
|
||
// Cursor
|
||
var cursor = common.cursor = {};
|
||
cursor.execCommand = function (data, cb) {
|
||
postMessage("CURSOR_COMMAND", data, cb);
|
||
};
|
||
cursor.onEvent = Util.mkEvent();
|
||
|
||
// Mailbox
|
||
var mailbox = common.mailbox = {};
|
||
mailbox.execCommand = function (data, cb) {
|
||
postMessage("MAILBOX_COMMAND", data, cb);
|
||
};
|
||
mailbox.onEvent = Util.mkEvent();
|
||
|
||
// Universal
|
||
var universal = common.universal = {};
|
||
universal.execCommand = function (data, cb) {
|
||
postMessage("UNIVERSAL_COMMAND", data, cb);
|
||
};
|
||
universal.onEvent = Util.mkEvent();
|
||
|
||
|
||
// Pad RPC
|
||
var pad = common.padRpc = {};
|
||
pad.joinPad = function (data) {
|
||
postMessage("JOIN_PAD", data);
|
||
};
|
||
pad.leavePad = function (data, cb) {
|
||
postMessage("LEAVE_PAD", data, cb);
|
||
};
|
||
pad.sendPadMsg = function (data, cb) {
|
||
postMessage("SEND_PAD_MSG", data, cb);
|
||
};
|
||
pad.onReadyEvent = Util.mkEvent();
|
||
pad.onMessageEvent = Util.mkEvent();
|
||
pad.onJoinEvent = Util.mkEvent();
|
||
pad.onLeaveEvent = Util.mkEvent();
|
||
pad.onDisconnectEvent = Util.mkEvent();
|
||
pad.onConnectEvent = Util.mkEvent();
|
||
pad.onErrorEvent = Util.mkEvent();
|
||
pad.onMetadataEvent = Util.mkEvent();
|
||
|
||
pad.requestAccess = function (data, cb) {
|
||
postMessage("REQUEST_PAD_ACCESS", data, cb);
|
||
};
|
||
pad.giveAccess = function (data, cb) {
|
||
postMessage("GIVE_PAD_ACCESS", data, cb);
|
||
};
|
||
|
||
common.setPadMetadata = function (data, cb) {
|
||
postMessage('SET_PAD_METADATA', data, cb);
|
||
};
|
||
common.getPadMetadata = function (data, cb) {
|
||
postMessage('GET_PAD_METADATA', data, cb);
|
||
};
|
||
|
||
common.burnPad = function (data) {
|
||
postMessage('BURN_PAD', data);
|
||
};
|
||
|
||
common.changePadPassword = function (Crypt, Crypto, data, cb) {
|
||
var href = data.href;
|
||
var newPassword = data.password;
|
||
var teamId = data.teamId;
|
||
if (!href) { return void cb({ error: 'EINVAL_HREF' }); }
|
||
var parsed = Hash.parsePadUrl(href);
|
||
if (!parsed.hash) { return void cb({ error: 'EINVAL_HREF' }); }
|
||
|
||
var warning = false;
|
||
var newHash, newRoHref;
|
||
var oldChannel;
|
||
var oldSecret;
|
||
var oldMetadata;
|
||
var newSecret;
|
||
var privateData;
|
||
|
||
if (parsed.hashData.version >= 2) {
|
||
newSecret = Hash.getSecrets(parsed.type, parsed.hash, newPassword);
|
||
if (!(newSecret.keys && newSecret.keys.editKeyStr)) {
|
||
return void cb({error: 'EAUTH'});
|
||
}
|
||
newHash = Hash.getEditHashFromKeys(newSecret);
|
||
} else {
|
||
newHash = Hash.createRandomHash(parsed.type, newPassword);
|
||
newSecret = Hash.getSecrets(parsed.type, newHash, newPassword);
|
||
}
|
||
var newHref = '/' + parsed.type + '/#' + newHash;
|
||
|
||
var isSharedFolder = parsed.type === 'drive';
|
||
|
||
var optsGet = {};
|
||
var optsPut = {
|
||
password: newPassword,
|
||
metadata: {},
|
||
initialState: isSharedFolder ? '{}' : undefined
|
||
};
|
||
|
||
var cryptgetVal;
|
||
|
||
Nthen(function (waitFor) {
|
||
if (parsed.hashData && parsed.hashData.password) {
|
||
common.getPadAttribute('password', waitFor(function (err, password) {
|
||
optsGet.password = password;
|
||
}), href);
|
||
}
|
||
}).nThen(function (waitFor) {
|
||
oldSecret = Hash.getSecrets(parsed.type, parsed.hash, optsGet.password);
|
||
oldChannel = oldSecret.channel;
|
||
common.getPadMetadata({channel: oldChannel}, waitFor(function (metadata) {
|
||
oldMetadata = metadata;
|
||
}));
|
||
common.getMetadata(waitFor(function (err, data) {
|
||
if (err) {
|
||
waitFor.abort();
|
||
return void cb({ error: err });
|
||
}
|
||
privateData = data.priv;
|
||
}));
|
||
}).nThen(function (waitFor) {
|
||
// Get owners, mailbox and expiration time
|
||
var owners = oldMetadata.owners;
|
||
optsPut.metadata.owners = owners;
|
||
|
||
// Check if we're allowed to change the password
|
||
var edPublic = teamId ? (privateData.teams[teamId] || {}).edPublic : privateData.edPublic;
|
||
var isOwner = Array.isArray(owners) && edPublic && owners.indexOf(edPublic) !== -1;
|
||
if (!isOwner) {
|
||
// We're not an owner, we shouldn't be able to change the password!
|
||
waitFor.abort();
|
||
return void cb({ error: 'EPERM' });
|
||
}
|
||
|
||
var mailbox = oldMetadata.mailbox;
|
||
if (mailbox) {
|
||
// Create the encryptors to be able to decrypt and re-encrypt the mailboxes
|
||
var oldCrypto = Crypto.createEncryptor(oldSecret.keys);
|
||
var newCrypto = Crypto.createEncryptor(newSecret.keys);
|
||
|
||
var m;
|
||
if (typeof(mailbox) === "string") {
|
||
try {
|
||
m = newCrypto.encrypt(oldCrypto.decrypt(mailbox, true, true));
|
||
} catch (e) {}
|
||
} else if (mailbox && typeof(mailbox) === "object") {
|
||
m = {};
|
||
Object.keys(mailbox).forEach(function (ed) {
|
||
console.log(mailbox[ed]);
|
||
try {
|
||
m[ed] = newCrypto.encrypt(oldCrypto.decrypt(mailbox[ed], true, true));
|
||
} catch (e) {
|
||
console.error(e);
|
||
}
|
||
});
|
||
}
|
||
optsPut.metadata.mailbox = m;
|
||
}
|
||
|
||
var expire = oldMetadata.expire;
|
||
if (expire) {
|
||
optsPut.metadata.expire = (expire - (+new Date())) / 1000; // Lifetime in seconds
|
||
}
|
||
}).nThen(function (waitFor) {
|
||
Crypt.get(parsed.hash, waitFor(function (err, val) {
|
||
if (err) {
|
||
waitFor.abort();
|
||
return void cb({ error: err });
|
||
}
|
||
cryptgetVal = val;
|
||
if (isSharedFolder) {
|
||
var parsed = JSON.parse(val || '{}');
|
||
var oldKey = parsed.version === 2 && oldSecret.keys.secondaryKey;
|
||
var newKey = newSecret.keys.secondaryKey;
|
||
UserObject.reencrypt(oldKey, newKey, parsed);
|
||
cryptgetVal = JSON.stringify(parsed);
|
||
}
|
||
}), optsGet);
|
||
}).nThen(function (waitFor) {
|
||
Crypt. |