mirror of
https://github.com/cryptpad/cryptpad.git
synced 2026-09-14 11:05:41 +05:00
commit
d55d360eb7
@ -38,11 +38,10 @@ var getStoredLanguage = function () { return localStorage && localStorage.getIte
|
||||
var getBrowserLanguage = function () { return navigator.language || navigator.userLanguage || ''; };
|
||||
var getLanguage = Messages._getLanguage = function () {
|
||||
if (window.cryptpadLanguage) { return window.cryptpadLanguage; }
|
||||
try {
|
||||
if (getStoredLanguage()) { return getStoredLanguage(); }
|
||||
} catch (e) { console.log(e); }
|
||||
var l = getBrowserLanguage();
|
||||
// Edge returns 'fr-FR' --> transform it to 'fr' and check again
|
||||
try {
|
||||
l = getStoredLanguage() || getBrowserLanguage();
|
||||
} catch (e) { console.log(e); }
|
||||
return map[l] ? l :
|
||||
(map[l.split('-')[0]] ? l.split('-')[0] :
|
||||
(map[l.split('_')[0]] ? l.split('_')[0] : 'en'));
|
||||
|
||||
@ -67,7 +67,7 @@ module.exports.create = function (Env, cb) {
|
||||
}
|
||||
|
||||
if (metadata && metadata.selfdestruct && metadata.selfdestruct !== Env.id) {
|
||||
HK.expireChannel(Env, channelName);
|
||||
HK.removeChannel(Env, channelName);
|
||||
return void cb('ESELFDESTRUCT');
|
||||
}
|
||||
|
||||
|
||||
@ -136,6 +136,13 @@ const expireChannel = HK.expireChannel = function (Env, channel) {
|
||||
});
|
||||
};
|
||||
|
||||
const removeChannel = HK.removeChannel = function (Env, channel) {
|
||||
if (!Env.store) { return; }
|
||||
Env.store.archiveChannel(channel, void 0, () => {});
|
||||
delete Env.metadata_cache[channel];
|
||||
delete Env.channel_cache[channel];
|
||||
};
|
||||
|
||||
/* dropChannel
|
||||
* cleans up memory structures which are managed entirely by the historyKeeper
|
||||
*/
|
||||
@ -145,7 +152,7 @@ const dropChannel = HK.dropChannel = function (Env, chanName) {
|
||||
delete Env.channel_cache[chanName];
|
||||
if (meta && meta.selfdestruct && Env.selfDestructTo) {
|
||||
Env.selfDestructTo[chanName] = setTimeout(function () {
|
||||
expireChannel(Env, chanName);
|
||||
removeChannel(Env, chanName);
|
||||
}, TEMPORARY_CHANNEL_LIFETIME);
|
||||
}
|
||||
if (Env.store) { Env.store.closeChannel(chanName, function () {}); }
|
||||
@ -698,6 +705,7 @@ const handleGetHistory = function (Env, Server, seq, userId, parsed) {
|
||||
}, (err, reason) => {
|
||||
// Any error but ENOENT: abort
|
||||
// ENOENT is allowed in case we want to create a new pad
|
||||
if (err && err.error) { err = err.error; }
|
||||
if (err && err.code !== 'ENOENT') {
|
||||
if (err.message === "EUNKNOWN") {
|
||||
Log.error("HK_GET_HISTORY", {
|
||||
@ -713,7 +721,7 @@ const handleGetHistory = function (Env, Server, seq, userId, parsed) {
|
||||
stack: err && err.stack,
|
||||
}); }
|
||||
// FIXME err.message isn't useful for users
|
||||
const parsedMsg = {error:err.message, channel: channelName, txid: txid};
|
||||
const parsedMsg = {error:err.message || 'ERROR', channel: channelName, txid: txid};
|
||||
Server.send(userId, [0, HISTORY_KEEPER_ID, 'MSG', userId, JSON.stringify(parsedMsg)]);
|
||||
return;
|
||||
}
|
||||
|
||||
9
package-lock.json
generated
9
package-lock.json
generated
@ -18,7 +18,7 @@
|
||||
"chainpad": "^5.2.6",
|
||||
"chainpad-crypto": "^0.2.5",
|
||||
"chainpad-listmap": "^1.1.0",
|
||||
"chainpad-netflux": "^1.2.0",
|
||||
"chainpad-netflux": "^1.2.2",
|
||||
"chainpad-server": "^5.2.4",
|
||||
"ckeditor": "npm:ckeditor4@~4.22.1",
|
||||
"codemirror": "^5.19.0",
|
||||
@ -1443,9 +1443,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/chainpad-netflux": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/chainpad-netflux/-/chainpad-netflux-1.2.0.tgz",
|
||||
"integrity": "sha512-j3qzrL/tugpTNQTk1I7VMZuQJHAYRNmFaiAxLbEFre/gLIPPJqM4gHXuyTU2OFzIFSd5m5i4G3+GwZ32jLV3cA==",
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/chainpad-netflux/-/chainpad-netflux-1.2.2.tgz",
|
||||
"integrity": "sha512-fcKugW29BE4wo4l3WYLc56yeFznu15bGi6tU3uPtsLGSExXGqNwS+3kmpzI0AFAsuoI0OKPeT4uLX4YzKT/D+A==",
|
||||
"license": "LGPL-2.1",
|
||||
"dependencies": {
|
||||
"netflux-websocket": "^1.2.0"
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
"chainpad": "^5.2.6",
|
||||
"chainpad-crypto": "^0.2.5",
|
||||
"chainpad-listmap": "^1.1.0",
|
||||
"chainpad-netflux": "^1.2.0",
|
||||
"chainpad-netflux": "^1.2.2",
|
||||
"chainpad-server": "^5.2.4",
|
||||
"ckeditor": "npm:ckeditor4@~4.22.1",
|
||||
"codemirror": "^5.19.0",
|
||||
|
||||
@ -398,6 +398,10 @@ define([
|
||||
};
|
||||
|
||||
var onUploaded = function (ev, data, err) {
|
||||
if (!ev && err) {
|
||||
console.error(err);
|
||||
return void UI.warn(Messages.error);
|
||||
}
|
||||
if (ev.newTemplate) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
@ -555,7 +559,7 @@ define([
|
||||
|
||||
var saveToServer = function (blob, title) {
|
||||
if (APP.cantCheckpoint) { return; } // TOO_LARGE
|
||||
var text = getContent();
|
||||
var text = !blob && getContent();
|
||||
if (!text && !blob) {
|
||||
setEditable(false, true);
|
||||
sframeChan.query('Q_CLEAR_CACHE_CHANNELS', [
|
||||
@ -949,7 +953,9 @@ define([
|
||||
|
||||
const realParticipants = Object.entries(content.ids).map(([id, user]) => {
|
||||
const nId = id.slice(0,32);
|
||||
const username = (users[nId] || {}).name || Messages.anonymous;
|
||||
const username = Util.find(privateData, ['integrationConfig', 'user', 'name']) ||
|
||||
(users[nId] || {}).name || Messages.anonymous;
|
||||
|
||||
return {
|
||||
id: String(user.ooid) + user.index,
|
||||
idOriginal: String(user.ooid),
|
||||
@ -1469,6 +1475,20 @@ define([
|
||||
});
|
||||
}
|
||||
break;
|
||||
case "forceSaveStart":
|
||||
if (APP.integrationSave) {
|
||||
APP.integrationSave(obj => {
|
||||
if (obj?.error) {
|
||||
console.error(obj.error);
|
||||
return void UI.warn(Messages.error);
|
||||
}
|
||||
content.integrationSave = `${myUniqueOOId}-${+new Date()}`;
|
||||
APP.integrationSaved = content.integrationSave;
|
||||
APP.onLocal();
|
||||
UI.log(Messages.saved);
|
||||
});
|
||||
}
|
||||
break;
|
||||
case "getLock":
|
||||
handleLock(obj, send);
|
||||
break;
|
||||
@ -1677,16 +1697,24 @@ define([
|
||||
|
||||
var lang = (window.cryptpadLanguage || navigator.language || navigator.userLanguage || '').slice(0,2);
|
||||
|
||||
let username = Util.find(privateData, ['integrationConfig', 'user', 'name'])
|
||||
|| metadataMgr.getUserData().name
|
||||
|| Messages.anonymous;
|
||||
|
||||
let integrationConfig = privateData?.integrationConfig?._;
|
||||
//let ec = integrationConfig?.editorConfig;
|
||||
let dc = integrationConfig?.document;
|
||||
|
||||
// Config
|
||||
APP.ooconfig = {
|
||||
"document": {
|
||||
"fileType": file.type,
|
||||
"key": "fresh",
|
||||
"title": file.title,
|
||||
"url": url,
|
||||
"permissions": {
|
||||
"download": false,
|
||||
"print": true,
|
||||
document: {
|
||||
fileType: file.type,
|
||||
key: "fresh",
|
||||
title: dc?.title || file.title,
|
||||
url: url,
|
||||
permissions: {
|
||||
download: dc?.permissions?.download || false,
|
||||
print: dc?.permissions?.print || true,
|
||||
}
|
||||
},
|
||||
"documentType": file.doc,
|
||||
@ -1703,8 +1731,8 @@ define([
|
||||
},
|
||||
"user": {
|
||||
"id": String(myOOId), //"c0c3bf82-20d7-4663-bf6d-7fa39c598b1d",
|
||||
"firstname": metadataMgr.getUserData().name || Messages.anonymous,
|
||||
"name": metadataMgr.getUserData().name || Messages.anonymous,
|
||||
"firstname": username,
|
||||
"name": username
|
||||
},
|
||||
"mode": "edit",
|
||||
"lang": lang
|
||||
@ -2135,6 +2163,30 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null
|
||||
}, void 0, common.getCache());
|
||||
};
|
||||
|
||||
let copy = (a, b) => {
|
||||
Object.keys(b).forEach(k => {
|
||||
if (k === "user") { return; } // Don't change user values
|
||||
if (a[k]) {
|
||||
if (typeof(a[k]) === "object" && typeof(b[k]) === "object") {
|
||||
copy(a[k], b[k]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
a[k] = b[k];
|
||||
});
|
||||
};
|
||||
if (integrationConfig) {
|
||||
let ec = integrationConfig.editorConfig;
|
||||
let c = APP.ooconfig.editorConfig.customization;
|
||||
copy(APP.ooconfig.editorConfig, ec);
|
||||
// Open "goback" in new tabs because of csp and
|
||||
// iframes
|
||||
if (ec.editorConfig?.customization?.goback) {
|
||||
c.goback.blank = true;
|
||||
}
|
||||
c.forcesave = true;
|
||||
}
|
||||
|
||||
// Always hide right menu
|
||||
localStorage?.original.removeItem('sse-hide-right-settings');
|
||||
localStorage?.original.removeItem('de-hide-right-settings');
|
||||
@ -3180,9 +3232,9 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null
|
||||
return void UI.errorLoadingScreen(Messages.error);
|
||||
}
|
||||
var blob = new Blob([bin], {type: 'text/plain'});
|
||||
var file = getFileType();
|
||||
resetData(blob, file);
|
||||
//saveToServer(blob, title);
|
||||
//var file = getFileType();
|
||||
//resetData(blob, file);
|
||||
saveToServer(blob, title);
|
||||
Title.updateTitle(title);
|
||||
UI.removeLoadingScreen();
|
||||
});
|
||||
@ -3193,13 +3245,17 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null
|
||||
let cfg = privateData.integrationConfig || {};
|
||||
common.openIntegrationChannel(APP.onLocal);
|
||||
integrationChannel = common.getSframeChannel();
|
||||
let hasUnsavedChanges = false;
|
||||
var integrationSave = function (cb) {
|
||||
var ext = cfg.fileType;
|
||||
|
||||
var upload = Util.once(function (_blob) {
|
||||
integrationChannel.query('Q_INTEGRATION_SAVE', {
|
||||
blob: _blob
|
||||
}, cb, {
|
||||
}, obj => {
|
||||
if (!obj?.error) { hasUnsavedChanges = false; }
|
||||
cb(obj);
|
||||
}, {
|
||||
raw: true
|
||||
});
|
||||
});
|
||||
@ -3220,21 +3276,46 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null
|
||||
};
|
||||
var inte = common.createIntegration(integrationSave,
|
||||
integrationHasUnsavedChanges);
|
||||
if (inte) {
|
||||
if (inte && cfg.autosave) {
|
||||
evIntegrationSave.reg(function () {
|
||||
inte.changed();
|
||||
});
|
||||
} else {
|
||||
APP.integrationSave = integrationSave;
|
||||
APP.integrationSetSaved = () => {
|
||||
hasUnsavedChanges = false;
|
||||
};
|
||||
evIntegrationSave.reg(function () {
|
||||
hasUnsavedChanges = true;
|
||||
});
|
||||
}
|
||||
$(window).on('beforeunload', function (ev) {
|
||||
if (hasUnsavedChanges) { return false; }
|
||||
ev.returnValue = '';
|
||||
});
|
||||
integrationChannel.on('Q_INTEGRATION_NEEDSAVE', function (data, cb) {
|
||||
if (!cfg.autosave) { return; }
|
||||
integrationSave(function (obj) {
|
||||
if (obj && obj.error) { console.error(obj.error); }
|
||||
cb();
|
||||
});
|
||||
});
|
||||
if (privateData.initialState) {
|
||||
|
||||
/* test button
|
||||
if (!cfg.autosave) {
|
||||
let $save = common.createButton('save', true, {}, function () {
|
||||
$save.attr('disabled', 'disabled');
|
||||
integrationSave(() => {
|
||||
$save.removeAttr('disabled');
|
||||
});
|
||||
});
|
||||
$('body').prepend($save);
|
||||
}
|
||||
*/
|
||||
|
||||
if (privateData.initialState && (!content || !content.hashes || !Object.keys(content.hashes).length)) {
|
||||
var blob = privateData.initialState;
|
||||
let title = `document.${cfg.fileType}`;
|
||||
console.error(blob, title);
|
||||
return convertImportBlob(blob, title);
|
||||
}
|
||||
}
|
||||
@ -3369,6 +3450,7 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null
|
||||
var wasMigrating = content.migration;
|
||||
|
||||
var myLocks = getUserLock(getId(), true);
|
||||
//var integrationSave = content.integrationSave;
|
||||
|
||||
content = json.content;
|
||||
|
||||
@ -3379,6 +3461,15 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null
|
||||
checkCheckpoint();
|
||||
}
|
||||
|
||||
// Integration: mark the current content as saved
|
||||
// if manually saved by someone else
|
||||
if (content.integrationSave !== APP.integrationSaved) {
|
||||
APP.integrationSaved = content.integrationSave;
|
||||
if (APP.integrationSetSaved) {
|
||||
APP.integrationSetSaved();
|
||||
}
|
||||
}
|
||||
|
||||
var editor = getEditor();
|
||||
if (content.hashes) {
|
||||
var latest = getLastCp(true);
|
||||
|
||||
@ -467,6 +467,19 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
var initTempRpc = (clientId, cb) => {
|
||||
if (store.rpc) { return void cb(store.rpc); }
|
||||
var kp = Crypto.Nacl.sign.keyPair();
|
||||
var keys = {
|
||||
edPublic: Crypto.Nacl.util.encodeBase64(kp.publicKey),
|
||||
edPrivate: Crypto.Nacl.util.encodeBase64(kp.secretKey)
|
||||
};
|
||||
Pinpad.create(store.network, keys, function (e, call) {
|
||||
if (e) { return void cb({error: e}); }
|
||||
store.rpc = call;
|
||||
cb(call);
|
||||
});
|
||||
};
|
||||
var initRpc = function (clientId, data, cb) {
|
||||
if (!store.loggedIn) { return cb(); }
|
||||
if (store.rpc) { return void cb(account); }
|
||||
@ -1830,7 +1843,7 @@ define([
|
||||
Store.leavePad(null, data, function () {});
|
||||
};
|
||||
var conf = {
|
||||
Cache: Cache, // ICE pad cache
|
||||
Cache: store.neverCache ? undefined : Cache,
|
||||
onCacheStart: function () {
|
||||
postMessage(clientId, "PAD_CACHE");
|
||||
},
|
||||
@ -3160,7 +3173,7 @@ define([
|
||||
|
||||
// If we load CryptPad for the first time from an existing pad, don't create a
|
||||
// drive automatically.
|
||||
var onNoDrive = function (clientId, cb) {
|
||||
var onNoDrive = function (clientId, cb, initRpc) {
|
||||
var andThen = function () {
|
||||
// To be able to use all the features inside the pad, we need to
|
||||
// initialize the chat (messenger) and the cursor modules.
|
||||
@ -3171,9 +3184,16 @@ define([
|
||||
store.messenger = store.modules['messenger'];
|
||||
|
||||
// And now we're ready
|
||||
initAnonRpc(null, null, function () {
|
||||
cb({});
|
||||
});
|
||||
let getAnon = () => {
|
||||
initAnonRpc(null, null, function () {
|
||||
cb({});
|
||||
});
|
||||
};
|
||||
|
||||
if (initRpc) {
|
||||
return initTempRpc(clientId, getAnon);
|
||||
}
|
||||
getAnon();
|
||||
};
|
||||
|
||||
// We need an anonymous RPC to be able to check if the pad exists and to get
|
||||
@ -3256,7 +3276,8 @@ define([
|
||||
// First tab, no user hash, no anon hash and this app doesn't need a drive
|
||||
// ==> don't create a drive
|
||||
// Or "neverDrive" (integration into another platform?)
|
||||
// ==> don't create a drive
|
||||
// ==> don't create a drive BUT create temp RPC (we may need to upload)
|
||||
if (data.neverDrive) { store.neverCache = true; }
|
||||
if (data.neverDrive || (data.noDrive && !data.userHash && !data.anonHash)) {
|
||||
return void onNoDrive(clientId, function (obj) {
|
||||
if (obj && obj.error) {
|
||||
@ -3270,7 +3291,7 @@ define([
|
||||
}
|
||||
Feedback.send("NO_DRIVE", true);
|
||||
callback(obj);
|
||||
});
|
||||
}, !!data.neverDrive);
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
|
||||
@ -17,7 +17,9 @@ define([
|
||||
nThen(function (waitFor) {
|
||||
DomReady.onReady(waitFor());
|
||||
}).nThen(function (waitFor) {
|
||||
var obj = SFCommonO.initIframe(waitFor, true, integration.pathname);
|
||||
let lang = integration && integration.config && integration.config.editorConfig
|
||||
&& integration.config.editorConfig.lang;
|
||||
var obj = SFCommonO.initIframe(waitFor, true, integration.pathname, lang);
|
||||
href = obj.href;
|
||||
hash = obj.hash;
|
||||
if (isIntegration) {
|
||||
|
||||
@ -842,6 +842,13 @@ define([
|
||||
additionalPriv.initialState = cfg.initialState instanceof Blob ?
|
||||
cfg.initialState : undefined;
|
||||
|
||||
if (cfg.integrationConfig) {
|
||||
if (metaObj?.user && !metaObj.user.name) {
|
||||
metaObj.user.name = cfg.integrationConfig?.user?.name ||
|
||||
cfg.integrationConfig?.user?.firstname;
|
||||
}
|
||||
}
|
||||
|
||||
// Early access
|
||||
var priv = metaObj.priv;
|
||||
var _plan = typeof(priv.plan) === "undefined" ? Utils.LocalStore.getPremium() : priv.plan;
|
||||
@ -2242,7 +2249,7 @@ define([
|
||||
}
|
||||
};
|
||||
|
||||
// on server crash, try to save to Nextcloud
|
||||
// on server crash, try to save to the outer platform
|
||||
if (ready) { return integrationSave(reload); }
|
||||
|
||||
// if error during loading, reload without saving
|
||||
|
||||
@ -18,7 +18,9 @@
|
||||
var scripts = document.getElementsByTagName('script');
|
||||
for (var i = scripts.length - 1; i >= 0; i--) {
|
||||
var match = scripts[i].src.match(/(.*)web-apps\/apps\/api\/documents\/api.js/i);
|
||||
var match2 = scripts[i].src.match(/(.*)\/cryptpad-api.js/i);
|
||||
if (match) { return match[1]; }
|
||||
else if (match2) { return match2[1]; }
|
||||
}
|
||||
};
|
||||
|
||||
@ -86,6 +88,7 @@
|
||||
var start = function (config, chan) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
setTimeout(function () {
|
||||
var docID = config.document.key;
|
||||
var key = config.document.key;
|
||||
var blob;
|
||||
|
||||
@ -109,14 +112,31 @@
|
||||
xhr.send();
|
||||
};
|
||||
|
||||
let serializedConfig = () => {
|
||||
let _config = {};
|
||||
_config.editorConfig = config.editorConfig;
|
||||
_config.document = {
|
||||
permissions: config.document?.permissions,
|
||||
title: config.document?.title,
|
||||
info: config.document?.info,
|
||||
referenceData: config.document?.referenceData
|
||||
};
|
||||
return _config;
|
||||
};
|
||||
|
||||
var start = function () {
|
||||
config.document.key = key;
|
||||
//config.document.key = key;
|
||||
chan.send('START', {
|
||||
key: key,
|
||||
application: config.documentType,
|
||||
name: config.document.title,
|
||||
url: config.document.url,
|
||||
documentKey: docID,
|
||||
document: blob,
|
||||
ext: config.document.fileType,
|
||||
autosave: config.autosave || 10
|
||||
autosave: config.events.onSave && (config.autosave || 10),
|
||||
editorConfig: config.editorConfig || {},
|
||||
_config: serializedConfig()
|
||||
}, function (obj) {
|
||||
if (obj && obj.error) { reject(obj.error); return console.error(obj.error); }
|
||||
resolve({});
|
||||
@ -130,8 +150,17 @@
|
||||
blob = config.document.blob;
|
||||
return start();
|
||||
}
|
||||
// NOTE: Nextcloud will log us out if we try from the client
|
||||
// TODO: make sure the server plugin is installed if we don't
|
||||
// call getBlob()
|
||||
if (!config.events?.onSave) {
|
||||
return void start();
|
||||
}
|
||||
getBlob(function (err, _blob) {
|
||||
if (err) { reject(err); return console.error(err); }
|
||||
if (err) { // Can't get blob from client, try from server
|
||||
console.warn(err);
|
||||
return void start();
|
||||
}
|
||||
_blob.name = `document.${config.document.fileType}`;
|
||||
blob = _blob;
|
||||
start();
|
||||
@ -188,6 +217,7 @@
|
||||
|
||||
chan.on('ON_DOWNLOADAS', blob => {
|
||||
let url = URL.createObjectURL(blob);
|
||||
if (!config.events.onDownloadAs) { return; }
|
||||
config.events.onDownloadAs({
|
||||
data: {
|
||||
fileType: config.document && config.document.fileType,
|
||||
@ -198,6 +228,7 @@
|
||||
|
||||
chan.on('SAVE', function (data, cb) {
|
||||
blob = data;
|
||||
if (!config.events.onSave) { return void cb(); }
|
||||
config.events.onSave(data, cb);
|
||||
});
|
||||
chan.on('RELOAD', function () {
|
||||
@ -242,22 +273,28 @@
|
||||
*/
|
||||
var init = function (cryptpadURL, containerId, config) {
|
||||
// OnlyOffice shim: don't provide a URL
|
||||
if (!config && typeof(containerId) === "object") {
|
||||
if (typeof(config) !== "object" && typeof(containerId) === "object") {
|
||||
config = containerId;
|
||||
containerId = cryptpadURL;
|
||||
cryptpadURL = getInstanceURL();
|
||||
}
|
||||
|
||||
config.events = config.events || {};
|
||||
|
||||
// OnlyOffice shim
|
||||
let url = config.document.url;
|
||||
if (/^http:\/\/localhost\/cache\/files\//.test(url)) {
|
||||
url = url.replace(/(http:\/\/localhost\/cache\/files\/)/, getInstanceURL() + 'ooapi/');
|
||||
}
|
||||
config.document.url = url;
|
||||
if (config.documentType === "spreadsheet") {
|
||||
if (config.documentType === "spreadsheet" || config.documentType === "cell") {
|
||||
config.documentType = "sheet";
|
||||
}
|
||||
if (config.documentType === "text") {
|
||||
|
||||
if (config.documentType === "slide") {
|
||||
config.documentType = "presentation";
|
||||
}
|
||||
if (config.documentType === "word" || config.documentType === "text") {
|
||||
config.documentType = "doc";
|
||||
}
|
||||
|
||||
@ -308,8 +345,8 @@
|
||||
iframe.setAttribute('name', 'frameEditor');
|
||||
iframe.setAttribute('align', 'top');
|
||||
iframe.setAttribute("src", url);
|
||||
iframe.setAttribute("width", config.width);
|
||||
iframe.setAttribute("height", config.height);
|
||||
iframe.setAttribute("width", config.width || '100%');
|
||||
iframe.setAttribute("height", config.height || '100%');
|
||||
if (config.editorConfig) { // OnlyOffice
|
||||
container.replaceWith(iframe);
|
||||
container = iframe;
|
||||
|
||||
@ -3,10 +3,13 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
define([
|
||||
'/api/config',
|
||||
'/common/sframe-common-outer.js',
|
||||
'/common/common-hash.js',
|
||||
], function (SCO, Hash) {
|
||||
'/components/tweetnacl/nacl-fast.min.js'
|
||||
], function (Config, SCO, Hash) {
|
||||
|
||||
let Nacl = window.nacl;
|
||||
var getTxid = function () {
|
||||
return Math.random().toString(16).replace('0.', '');
|
||||
};
|
||||
@ -95,9 +98,17 @@ define([
|
||||
};
|
||||
http.send();
|
||||
};
|
||||
let sanitizeKey = key => {
|
||||
try {
|
||||
Nacl.util.decodeBase64(key);
|
||||
return key;
|
||||
} catch (e) {
|
||||
return Nacl.util.encodeBase64(Nacl.util.decodeUTF8(key)).replaceAll('=', '');
|
||||
}
|
||||
};
|
||||
chan.on('GET_SESSION', function (data, cb) {
|
||||
if (data.keepOld) {
|
||||
var key = data.key + "000000000000000000000000000000000";
|
||||
if (data.keepOld) { // they provide their own key, we must turn it into a hash
|
||||
var key = sanitizeKey(data.key) + "000000000000000000000000000000000";
|
||||
console.warn('KEY', key);
|
||||
return void cb({
|
||||
key: `/2/integration/edit/${key.slice(0,24)}/`
|
||||
@ -118,12 +129,6 @@ define([
|
||||
});
|
||||
});
|
||||
|
||||
var save = function (obj, cb) {
|
||||
chan.send('SAVE', obj.blob, function (err) {
|
||||
if (err) { return cb({error: err}); }
|
||||
cb();
|
||||
});
|
||||
};
|
||||
var reload = function (data) {
|
||||
chan.send('RELOAD', data);
|
||||
};
|
||||
@ -152,36 +157,122 @@ define([
|
||||
chan.send('ON_DOWNLOADAS', blob);
|
||||
};
|
||||
|
||||
chan.on('START', function (data) {
|
||||
console.warn('INNER START', data);
|
||||
var href = Hash.hashToHref(data.key, data.application);
|
||||
console.error(Hash.hrefToHexChannelId(href));
|
||||
window.CP_integration_outer = {
|
||||
pathname: `/${data.application}/`,
|
||||
hash: data.key,
|
||||
href: href,
|
||||
initialState: data.document,
|
||||
config: {
|
||||
fileType: data.ext,
|
||||
autosave: data.autosave
|
||||
},
|
||||
utils: {
|
||||
onReady: onReady,
|
||||
onDownloadAs,
|
||||
setDownloadAs,
|
||||
save: save,
|
||||
reload: reload,
|
||||
onHasUnsavedChanges: onHasUnsavedChanges,
|
||||
onInsertImage: onInsertImage
|
||||
|
||||
let getInstanceURL = function () {
|
||||
return Config.httpUnsafeOrigin;
|
||||
};
|
||||
let getBlobServer = function (documentURL, cb) {
|
||||
let xhr = new XMLHttpRequest();
|
||||
let data = encodeURIComponent(documentURL);
|
||||
let url = getInstanceURL() + '/ooapidl?url=' + data;
|
||||
xhr.open('GET', url, true);
|
||||
xhr.responseType = 'blob';
|
||||
//xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.onload = function () {
|
||||
if (this.status === 200) {
|
||||
var blob = this.response;
|
||||
// myBlob is now the blob that the object URL pointed to.
|
||||
cb(null, blob);
|
||||
} else {
|
||||
cb(this.status);
|
||||
}
|
||||
};
|
||||
let path = "/common/sframe-app-outer.js";
|
||||
if (['sheet', 'doc', 'presentation'].includes(data.application)) {
|
||||
path = '/common/onlyoffice/main.js';
|
||||
xhr.onerror = function (e) {
|
||||
cb(e.message);
|
||||
};
|
||||
xhr.send();
|
||||
};
|
||||
let saveBlobServer = function (cfg, blob, cb) {
|
||||
let {callbackUrl, name, key} = cfg;
|
||||
let xhr = new XMLHttpRequest();
|
||||
name = encodeURIComponent(name);
|
||||
callbackUrl = encodeURIComponent(callbackUrl);
|
||||
key = encodeURIComponent(key);
|
||||
let query = `name=${name}&cb=${callbackUrl}&key=${key}`;
|
||||
let url = getInstanceURL() + `/oosave?${query}`;
|
||||
xhr.open('POST', url, true);
|
||||
xhr.responseType = 'blob';
|
||||
//xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.onload = function () {
|
||||
console.error(this.status);
|
||||
if (this.status === 200) {
|
||||
cb();
|
||||
} else {
|
||||
cb(this.status);
|
||||
}
|
||||
};
|
||||
xhr.onerror = function (e) {
|
||||
cb(e.message);
|
||||
};
|
||||
xhr.send(blob);
|
||||
};
|
||||
chan.on('START', function (data, cb) {
|
||||
console.warn('INNER START', data);
|
||||
// data.key is a hash
|
||||
var href = Hash.hashToHref(data.key, data.application);
|
||||
if (data.editorConfig.lang) {
|
||||
var LS_LANG = "CRYPTPAD_LANG";
|
||||
localStorage.setItem(LS_LANG, data.editorConfig.lang);
|
||||
}
|
||||
require([path], function () {
|
||||
console.warn('SAO REQUIRED');
|
||||
delete window.CP_integration_outer;
|
||||
|
||||
let fileName = data.name || `document.${data.ext}`;
|
||||
var save = function (obj, cb) {
|
||||
let cbUrl = data.editorConfig.callbackUrl;
|
||||
if (!data.autosave && cbUrl) {
|
||||
saveBlobServer({
|
||||
callbackUrl: cbUrl,
|
||||
name: fileName,
|
||||
key: data.documentKey
|
||||
}, obj.blob, cb);
|
||||
return;
|
||||
}
|
||||
chan.send('SAVE', obj.blob, function (err) {
|
||||
if (err) { return cb({error: err}); }
|
||||
cb();
|
||||
});
|
||||
};
|
||||
|
||||
console.error(Hash.hrefToHexChannelId(href));
|
||||
let startApp = function (blob) {
|
||||
window.CP_integration_outer = {
|
||||
pathname: `/${data.application}/`,
|
||||
hash: data.key,
|
||||
href: href,
|
||||
initialState: blob,
|
||||
config: {
|
||||
fileName: data.name,
|
||||
fileType: data.ext,
|
||||
autosave: data.autosave,
|
||||
user: data.editorConfig.user,
|
||||
_: data._config
|
||||
},
|
||||
utils: {
|
||||
onReady: onReady,
|
||||
onDownloadAs,
|
||||
setDownloadAs,
|
||||
save: save,
|
||||
reload: reload,
|
||||
onHasUnsavedChanges: onHasUnsavedChanges,
|
||||
onInsertImage: onInsertImage
|
||||
}
|
||||
};
|
||||
let path = "/common/sframe-app-outer.js";
|
||||
if (['sheet', 'doc', 'presentation'].includes(data.application)) {
|
||||
path = '/common/onlyoffice/main.js';
|
||||
}
|
||||
require([path], function () {
|
||||
console.warn('SAO REQUIRED');
|
||||
delete window.CP_integration_outer;
|
||||
cb();
|
||||
});
|
||||
};
|
||||
|
||||
if (data.document) { return void startApp(data.document); }
|
||||
getBlobServer(data.url, (err, blob) => {
|
||||
if (err) {
|
||||
return void cb({error: err});
|
||||
}
|
||||
startApp(blob);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user