mirror of https://github.com/xwiki-labs/cryptpad
Integration API prototype
This commit is contained in:
parent
a5d5dba9f2
commit
723ecc8bd6
|
@ -26,7 +26,7 @@ Default.commonCSP = function (Env) {
|
||||||
if you are deploying to production, you'll probably want to remove
|
if you are deploying to production, you'll probably want to remove
|
||||||
the ws://* directive
|
the ws://* directive
|
||||||
*/
|
*/
|
||||||
"connect-src 'self' blob: " + (/^https:/.test(domain)? 'wss:': domain.replace('http://', 'ws://')) + ' ' + domain + sandbox + accounts_api,
|
"connect-src 'self' localhost blob: " + (/^https:/.test(domain)? 'wss:': domain.replace('http://', 'ws://')) + ' ' + domain + sandbox + accounts_api,
|
||||||
|
|
||||||
// data: is used by codemirror
|
// data: is used by codemirror
|
||||||
"img-src 'self' data: blob:" + domain,
|
"img-src 'self' data: blob:" + domain,
|
||||||
|
|
|
@ -220,6 +220,8 @@ module.exports.create = function (config) {
|
||||||
|
|
||||||
curvePrivate: curve.secretKey,
|
curvePrivate: curve.secretKey,
|
||||||
curvePublic: Nacl.util.encodeBase64(curve.publicKey),
|
curvePublic: Nacl.util.encodeBase64(curve.publicKey),
|
||||||
|
|
||||||
|
selfDestructTo: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
|
|
|
@ -63,6 +63,11 @@ module.exports.create = function (Env, cb) {
|
||||||
error: err,
|
error: err,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Env.selfDestructTo && Env.selfDestructTo[channelName]) {
|
||||||
|
clearTimeout(Env.selfDestructTo[channelName]);
|
||||||
|
}
|
||||||
|
|
||||||
if (!metadata || (metadata && !metadata.restricted)) {
|
if (!metadata || (metadata && !metadata.restricted)) {
|
||||||
// the channel doesn't have metadata, or it does and it's not restricted
|
// the channel doesn't have metadata, or it does and it's not restricted
|
||||||
// either way, let them join.
|
// either way, let them join.
|
||||||
|
|
|
@ -133,8 +133,14 @@ const expireChannel = function (Env, channel) {
|
||||||
* cleans up memory structures which are managed entirely by the historyKeeper
|
* cleans up memory structures which are managed entirely by the historyKeeper
|
||||||
*/
|
*/
|
||||||
const dropChannel = HK.dropChannel = function (Env, chanName) {
|
const dropChannel = HK.dropChannel = function (Env, chanName) {
|
||||||
|
let meta = Env.metadata_cache[chanName];
|
||||||
delete Env.metadata_cache[chanName];
|
delete Env.metadata_cache[chanName];
|
||||||
delete Env.channel_cache[chanName];
|
delete Env.channel_cache[chanName];
|
||||||
|
if (meta && meta.selfdestruct && Env.selfDestructTo) {
|
||||||
|
Env.selfDestructTo[chanName] = setTimeout(function () {
|
||||||
|
expireChannel(Env, chanName); // XXX add new function?
|
||||||
|
}, 30*1000); // XXX CONSTANT XXX XXX XXX
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* checkExpired
|
/* checkExpired
|
||||||
|
|
|
@ -164,6 +164,10 @@ app.get(mainPagePattern, Express.static(Path.resolve('customize.dist')));
|
||||||
app.use("/blob", Express.static(Env.paths.blob, {
|
app.use("/blob", Express.static(Env.paths.blob, {
|
||||||
maxAge: Env.DEV_MODE? "0d": "365d"
|
maxAge: Env.DEV_MODE? "0d": "365d"
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
app.head("/datastore", Express.static(Env.paths.data, {
|
||||||
|
maxAge: "0d"
|
||||||
|
}));
|
||||||
app.use("/datastore", Express.static(Env.paths.data, {
|
app.use("/datastore", Express.static(Env.paths.data, {
|
||||||
maxAge: "0d"
|
maxAge: "0d"
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -6,21 +6,29 @@ define([
|
||||||
'/common/sframe-common-outer.js'
|
'/common/sframe-common-outer.js'
|
||||||
], function (nThen, ApiConfig, DomReady, SFCommonO) {
|
], function (nThen, ApiConfig, DomReady, SFCommonO) {
|
||||||
|
|
||||||
|
var isIntegration = Boolean(window.CP_integration_outer);
|
||||||
|
var integration = window.CP_integration_outer || {};
|
||||||
|
|
||||||
var hash, href;
|
var hash, href;
|
||||||
nThen(function (waitFor) {
|
nThen(function (waitFor) {
|
||||||
DomReady.onReady(waitFor());
|
DomReady.onReady(waitFor());
|
||||||
}).nThen(function (waitFor) {
|
}).nThen(function (waitFor) {
|
||||||
var obj = SFCommonO.initIframe(waitFor, true);
|
var obj = SFCommonO.initIframe(waitFor, true, integration.pathname);
|
||||||
href = obj.href;
|
href = obj.href;
|
||||||
hash = obj.hash;
|
hash = obj.hash;
|
||||||
|
if (isIntegration) {
|
||||||
|
href = integration.href;
|
||||||
|
hash = integration.hash;
|
||||||
|
}
|
||||||
}).nThen(function (/*waitFor*/) {
|
}).nThen(function (/*waitFor*/) {
|
||||||
SFCommonO.start({
|
SFCommonO.start({
|
||||||
cache: true,
|
cache: !isIntegration,
|
||||||
noDrive: true,
|
noDrive: true,
|
||||||
hash: hash,
|
hash: hash,
|
||||||
href: href,
|
href: href,
|
||||||
useCreationScreen: true,
|
useCreationScreen: !isIntegration,
|
||||||
messaging: true
|
messaging: true,
|
||||||
|
integration: isIntegration
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -15,6 +15,7 @@ define([
|
||||||
'pad',
|
'pad',
|
||||||
'slide',
|
'slide',
|
||||||
'whiteboard',
|
'whiteboard',
|
||||||
|
'integration'
|
||||||
].map(function (x) {
|
].map(function (x) {
|
||||||
return `/${x}/`;
|
return `/${x}/`;
|
||||||
});
|
});
|
||||||
|
@ -695,7 +696,8 @@ define([
|
||||||
fromContent: Cryptpad.fromContent,
|
fromContent: Cryptpad.fromContent,
|
||||||
burnAfterReading: burnAfterReading,
|
burnAfterReading: burnAfterReading,
|
||||||
storeInTeam: Cryptpad.initialTeam || (Cryptpad.initialPath ? -1 : undefined),
|
storeInTeam: Cryptpad.initialTeam || (Cryptpad.initialPath ? -1 : undefined),
|
||||||
supportsWasm: Utils.Util.supportsWasm()
|
supportsWasm: Utils.Util.supportsWasm(),
|
||||||
|
integration: cfg.integration
|
||||||
};
|
};
|
||||||
if (window.CryptPad_newSharedFolder) {
|
if (window.CryptPad_newSharedFolder) {
|
||||||
additionalPriv.newSharedFolder = window.CryptPad_newSharedFolder;
|
additionalPriv.newSharedFolder = window.CryptPad_newSharedFolder;
|
||||||
|
@ -1966,6 +1968,8 @@ define([
|
||||||
placeholder.remove();
|
placeholder.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var replaceHash = function (hash) {
|
var replaceHash = function (hash) {
|
||||||
// The pad has just been created but is not stored yet. We'll switch
|
// The pad has just been created but is not stored yet. We'll switch
|
||||||
// to hidden hash once the pad is stored
|
// to hidden hash once the pad is stored
|
||||||
|
@ -2059,6 +2063,11 @@ define([
|
||||||
var rtConfig = {
|
var rtConfig = {
|
||||||
metadata: {}
|
metadata: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (cfg.integration) {
|
||||||
|
rtConfig.metadata.selfdestruct = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (data.team) {
|
if (data.team) {
|
||||||
Cryptpad.initialTeam = data.team.id;
|
Cryptpad.initialTeam = data.team.id;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,196 @@
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
var factory = function (/*Hash*/) {
|
||||||
|
|
||||||
|
// This API is used to load a CryptPad editor for a provided document in
|
||||||
|
// an external platform.
|
||||||
|
// The external platform needs to store a session key and make it
|
||||||
|
// available to all users who needs to access the realtime editor.
|
||||||
|
|
||||||
|
var getTxid = function () {
|
||||||
|
return Math.random().toString(16).replace('0.', '');
|
||||||
|
};
|
||||||
|
|
||||||
|
var makeChan = function (iframe, iOrigin) {
|
||||||
|
var handlers = {};
|
||||||
|
var commands = {};
|
||||||
|
|
||||||
|
var iWindow = iframe.contentWindow;
|
||||||
|
var _sendCb = function (txid, args) {
|
||||||
|
iWindow.postMessage({ ack: txid, args: args}, iOrigin);
|
||||||
|
};
|
||||||
|
var onMsg = function (ev) {
|
||||||
|
if (ev.source !== iWindow) { return; }
|
||||||
|
var data = ev.data;
|
||||||
|
|
||||||
|
// On ack
|
||||||
|
if (data.ack) {
|
||||||
|
if (handlers[data.ack]) {
|
||||||
|
handlers[data.ack](data.args);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// On new command
|
||||||
|
var msg = data.msg;
|
||||||
|
var txid = data.txid;
|
||||||
|
if (commands[msg.q]) {
|
||||||
|
console.warn('OUTER RECEIVED QUERY', msg.q, msg.data);
|
||||||
|
commands[msg.q](msg.data, function (args) {
|
||||||
|
_sendCb(txid, args);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
window.addEventListener('message', onMsg);
|
||||||
|
|
||||||
|
var send = function (q, data, cb) {
|
||||||
|
var txid = getTxid();
|
||||||
|
if (cb) { handlers[txid] = cb; }
|
||||||
|
|
||||||
|
console.warn('OUTER SENT QUERY', q, data);
|
||||||
|
iWindow.postMessage({ msg: {
|
||||||
|
q: q,
|
||||||
|
data: data,
|
||||||
|
}, txid: txid}, iOrigin);
|
||||||
|
setTimeout(function () {
|
||||||
|
delete handlers[txid];
|
||||||
|
}, 60000);
|
||||||
|
};
|
||||||
|
var on = function (q, handler) {
|
||||||
|
if (typeof(handler) !== "function") { return; }
|
||||||
|
commands[q] = handler;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
send: send,
|
||||||
|
on: on
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var start = function (config, chan) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
setTimeout(function () {
|
||||||
|
var key = config.document.key;
|
||||||
|
|
||||||
|
chan.on('SAVE', function (data) {
|
||||||
|
config.events.onSave(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
var onKeyValidated = function () {
|
||||||
|
chan.send('START', {
|
||||||
|
key: key,
|
||||||
|
document: config.document.url,
|
||||||
|
}, function (obj) {
|
||||||
|
if (obj && obj.error) { reject(obj.error); return console.error(obj.error); }
|
||||||
|
console.log('OUTER START SUCCESS');
|
||||||
|
resolve({});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
chan.send('GET_SESSION', {
|
||||||
|
key: key
|
||||||
|
}, function (obj) {
|
||||||
|
if (obj && obj.error) { reject(obj.error); return console.error(obj.error); }
|
||||||
|
if (obj.key !== key) {
|
||||||
|
key = obj.key;
|
||||||
|
config.events.onNewKey(key);
|
||||||
|
}
|
||||||
|
onKeyValidated();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a CryptPad collaborative editor for the provided document.
|
||||||
|
*
|
||||||
|
* @param {string} cryptpadURL The URL of the CryptPad server.
|
||||||
|
* @param {string} containerID (optional) The ID of the HTML element containing the iframe.
|
||||||
|
* @param {object} config The object containing configuration parameters.
|
||||||
|
* @param {object} config.document The document to load.
|
||||||
|
* @param {string} document.url The document URL.
|
||||||
|
* @param {string} document.key The collaborative session key.
|
||||||
|
* @param {object} config.events Event handlers.
|
||||||
|
* @param {function} events.onSave The save function to store the document when edited.
|
||||||
|
* @param {function} events.onNewKey The function called when a new key is used.
|
||||||
|
* @param {string} config.documentType The editor to load in CryptPad.
|
||||||
|
* @return {promise}
|
||||||
|
*/
|
||||||
|
var init = function (cryptpadURL, containerId, config) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
setTimeout(function () {
|
||||||
|
|
||||||
|
if (!cryptpadURL || typeof(cryptpadURL) !== "string") {
|
||||||
|
return reject('Missing arg: cryptpadURL');
|
||||||
|
}
|
||||||
|
var container;
|
||||||
|
if (containerId) {
|
||||||
|
container = document.getElementById('containerId');
|
||||||
|
}
|
||||||
|
if (!container) {
|
||||||
|
console.warn('No container provided, append to body');
|
||||||
|
container = document.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config) { return reject('Missing args: no data provided'); }
|
||||||
|
['document.url', 'document.key', 'documentType',
|
||||||
|
'events.onSave', 'events.onNewKey'].some(function (k) {
|
||||||
|
var s = k.split('.');
|
||||||
|
var c = config;
|
||||||
|
return s.some(function (key) {
|
||||||
|
if (!c[key]) {
|
||||||
|
reject(`Missing args: no "config.${k}" provided`);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
c = c[key];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
cryptpadURL = cryptpadURL.replace(/(\/)+$/, '');
|
||||||
|
var url = cryptpadURL + '/integration/';
|
||||||
|
var parsed;
|
||||||
|
try {
|
||||||
|
parsed = new URL(url);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
return reject('Invalid arg: cryptpadURL');
|
||||||
|
}
|
||||||
|
|
||||||
|
var iframe = document.createElement('iframe');
|
||||||
|
iframe.setAttribute('id', 'cryptpad-editor');
|
||||||
|
iframe.setAttribute("src", url);
|
||||||
|
container.appendChild(iframe);
|
||||||
|
|
||||||
|
var onMsg = function (msg) {
|
||||||
|
var data = typeof(msg.data) === "string" ? JSON.parse(msg.data) : msg.data;
|
||||||
|
if (!data || data.q !== 'INTEGRATION_READY') { return; }
|
||||||
|
window.removeEventListener('message', onMsg);
|
||||||
|
var chan = makeChan(iframe, parsed.origin);
|
||||||
|
start(config, chan).then(resolve).catch(reject);
|
||||||
|
};
|
||||||
|
window.addEventListener('message', onMsg);
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return init;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (typeof(module) !== 'undefined' && module.exports) {
|
||||||
|
module.exports = factory();
|
||||||
|
} else if ((typeof(define) !== 'undefined' && define !== null) && (define.amd !== null)) {
|
||||||
|
define([], function () {
|
||||||
|
return factory();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
window.CryptPadAPI = factory();
|
||||||
|
}
|
||||||
|
}());
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
@import (reference) '../../customize/src/less2/include/framework.less';
|
||||||
|
|
||||||
|
&.cp-app-openin {
|
||||||
|
.framework_min_main();
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
header {
|
||||||
|
height: 100px;
|
||||||
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
border-bottom: 1px solid white;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > iframe {
|
||||||
|
position: fixed;
|
||||||
|
top: 100px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
border: none;
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 100px);
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<!-- If this file is not called customize.dist/src/template.html, it is generated -->
|
||||||
|
<head>
|
||||||
|
<title data-localization="main_title">CryptPad: Collaboration suite, encrypted and open-source</title>
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||||
|
<link rel="icon" type="image/png" href="/customize/favicon/main-favicon.png" id="favicon"/>
|
||||||
|
<script src="/customize/pre-loading.js?ver=1.1"></script>
|
||||||
|
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
|
||||||
|
<script async data-bootload="/integration/main.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
|
||||||
|
<link href="/customize/src/outer.css?ver=1.3.2" rel="stylesheet" type="text/css">
|
||||||
|
</head>
|
||||||
|
<body class="html cp-app-integration">
|
||||||
|
<iframe-placeholder>
|
|
@ -0,0 +1,153 @@
|
||||||
|
define([
|
||||||
|
'/common/sframe-common-outer.js',
|
||||||
|
'/common/common-hash.js',
|
||||||
|
'/common/cryptget.js',
|
||||||
|
'/bower_components/nthen/index.js',
|
||||||
|
], function (SCO, Hash, Crypt, nThen) {
|
||||||
|
|
||||||
|
var getTxid = function () {
|
||||||
|
return Math.random().toString(16).replace('0.', '');
|
||||||
|
};
|
||||||
|
var init = function () {
|
||||||
|
console.warn('INIT');
|
||||||
|
var p = window.parent;
|
||||||
|
var txid = getTxid();
|
||||||
|
p.postMessage(JSON.stringify({ q: 'INTEGRATION_READY', txid: txid }), '*');
|
||||||
|
|
||||||
|
var makeChan = function () {
|
||||||
|
var handlers = {};
|
||||||
|
var commands = {};
|
||||||
|
|
||||||
|
var _sendCb = function (txid, args) {
|
||||||
|
p.postMessage({ ack: txid, args: args}, '*');
|
||||||
|
};
|
||||||
|
var onMsg = function (ev) {
|
||||||
|
if (ev.source !== p) { return; }
|
||||||
|
var data = ev.data;
|
||||||
|
|
||||||
|
// On ack
|
||||||
|
if (data.ack) {
|
||||||
|
if (handlers[data.ack]) {
|
||||||
|
handlers[data.ack](data.args);
|
||||||
|
delete handlers[data.ack];
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// On new command
|
||||||
|
var msg = data.msg;
|
||||||
|
var txid = data.txid;
|
||||||
|
if (commands[msg.q]) {
|
||||||
|
commands[msg.q](msg.data, function (args) {
|
||||||
|
_sendCb(txid, args);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
window.addEventListener('message', onMsg);
|
||||||
|
|
||||||
|
var send = function (q, data, cb) {
|
||||||
|
var txid = getTxid();
|
||||||
|
if (cb) { handlers[txid] = cb; }
|
||||||
|
p.postMessage({ msg: {
|
||||||
|
q: q,
|
||||||
|
data: data,
|
||||||
|
}, txid: txid}, '*');
|
||||||
|
setTimeout(function () {
|
||||||
|
delete handlers[txid];
|
||||||
|
}, 60000);
|
||||||
|
};
|
||||||
|
var on = function (q, handler) {
|
||||||
|
if (typeof(handler) !== "function") { return; }
|
||||||
|
commands[q] = handler;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
send: send,
|
||||||
|
on: on
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var chan = makeChan();
|
||||||
|
|
||||||
|
var isNew = false;
|
||||||
|
// Make a HEAD request to the servre to check if a file exists in datastore
|
||||||
|
// XXX update nginx config
|
||||||
|
var checkSession = function (oldKey, cb) {
|
||||||
|
var channel = Hash.hrefToHexChannelId(Hash.hashToHref(oldKey));
|
||||||
|
var prefix = channel.slice(0,2);
|
||||||
|
var url = `/datastore/${prefix}/${channel}.ndjson`;
|
||||||
|
|
||||||
|
var http = new XMLHttpRequest();
|
||||||
|
http.open('HEAD', url);
|
||||||
|
http.onreadystatechange = function() {
|
||||||
|
if (this.readyState === this.DONE) {
|
||||||
|
console.error(this.status);
|
||||||
|
if (this.status === 200) {
|
||||||
|
return cb({state: true});
|
||||||
|
}
|
||||||
|
if (this.status === 404) {
|
||||||
|
return cb({state: false});
|
||||||
|
}
|
||||||
|
cb({error: 'Internal server error'});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
http.send();
|
||||||
|
};
|
||||||
|
chan.on('GET_SESSION', function (data, cb) {
|
||||||
|
var getHash = function () {
|
||||||
|
isNew = true;
|
||||||
|
return Hash.createRandomHash('integration');
|
||||||
|
};
|
||||||
|
var oldKey = data.sessionKey;
|
||||||
|
if (!oldKey) { return void cb({ key: getHash() }); }
|
||||||
|
|
||||||
|
checkSession(oldKey, function (obj) {
|
||||||
|
if (!obj || obj.error) { return cb(obj); }
|
||||||
|
cb({
|
||||||
|
key: obj.state ? oldKey : getHash()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
chan.on('START', function (data) {
|
||||||
|
console.warn('INNER START', data);
|
||||||
|
nThen(function (w) {
|
||||||
|
if (!isNew) { return; }
|
||||||
|
|
||||||
|
// XXX initial content TBD
|
||||||
|
var content = JSON.stringify({
|
||||||
|
content: data.document,
|
||||||
|
highlightMode: "gfm"
|
||||||
|
}); // XXX only for code
|
||||||
|
|
||||||
|
console.error('CRYPTPUT', data.sessionKey);
|
||||||
|
Crypt.put(data.sessionKey, content, w(), {
|
||||||
|
metadata: {
|
||||||
|
selfdestruct: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).nThen(function () {
|
||||||
|
var href = Hash.hashToHref(data.sessionKey, data.application);
|
||||||
|
console.error(Hash.hrefToHexChannelId(href));
|
||||||
|
window.CP_integration_outer = {
|
||||||
|
pathname: `/${data.application}/`,
|
||||||
|
hash: data.sessionKey,
|
||||||
|
href: href
|
||||||
|
};
|
||||||
|
require(['/common/sframe-app-outer.js'], function () {
|
||||||
|
console.warn('SAO REQUIRED');
|
||||||
|
delete window.CP_integration_outer;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
init();
|
||||||
|
/*
|
||||||
|
nThen(function (waitFor) {
|
||||||
|
}).nThen(function () {
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
|
});
|
|
@ -0,0 +1,28 @@
|
||||||
|
@import (reference) '../../customize/src/less2/include/framework.less';
|
||||||
|
|
||||||
|
&.cp-app-openin {
|
||||||
|
.framework_min_main();
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
header {
|
||||||
|
height: 100px;
|
||||||
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
border-bottom: 1px solid white;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > iframe {
|
||||||
|
position: fixed;
|
||||||
|
top: 100px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
border: none;
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 100px);
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<!-- If this file is not called customize.dist/src/template.html, it is generated -->
|
||||||
|
<head>
|
||||||
|
<title data-localization="main_title">CryptPad: Collaboration suite, encrypted and open-source</title>
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||||
|
<link rel="icon" type="image/png" href="/customize/favicon/main-favicon.png" id="favicon"/>
|
||||||
|
<script async data-bootload="/nextcloud/main.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
|
||||||
|
<style>
|
||||||
|
#main {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
#cryptpad-editor {
|
||||||
|
border: none;
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 100px);
|
||||||
|
position: absolute;
|
||||||
|
top: 100px;
|
||||||
|
left: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="html cp-app-openin">
|
||||||
|
<div id="main">Pew pew pew</div>
|
|
@ -0,0 +1,48 @@
|
||||||
|
var url = 'http://localhost:3000';
|
||||||
|
define([
|
||||||
|
'jquery',
|
||||||
|
url + '/cryptpad-api.js'
|
||||||
|
], function ($, Api) {
|
||||||
|
if (window.top !== window) { return; }
|
||||||
|
$(function () {
|
||||||
|
|
||||||
|
console.log(Api);
|
||||||
|
var permaKey = '/2/integration/edit/X3RlrgR2JhA0rI+PJ3rXufsQ/'; // XXX
|
||||||
|
var key = window.location.hash ? window.location.hash.slice(1)
|
||||||
|
: permaKey;
|
||||||
|
|
||||||
|
// Test doc
|
||||||
|
var mystring = "Hello World!";
|
||||||
|
var blob = new Blob([mystring], {
|
||||||
|
type: 'text/markdown'
|
||||||
|
});
|
||||||
|
var docUrl = URL.createObjectURL(blob);
|
||||||
|
|
||||||
|
|
||||||
|
var onSave = function (data) {
|
||||||
|
console.log('APP ONSAVE', data);
|
||||||
|
};
|
||||||
|
var onNewKey = function (newKey) {
|
||||||
|
window.location.hash = newKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Api(url, null, {
|
||||||
|
document: {
|
||||||
|
url: docUrl,
|
||||||
|
key: key
|
||||||
|
},
|
||||||
|
documentType: 'code', // appname
|
||||||
|
events: {
|
||||||
|
onSave: onSave,
|
||||||
|
onNewKey: onNewKey
|
||||||
|
}
|
||||||
|
}).then(function () {
|
||||||
|
console.log('SUCCESS');
|
||||||
|
}).catch(function (e) {
|
||||||
|
console.error('ERROR', e);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue