diff --git a/customize.dist/pages.js b/customize.dist/pages.js
index 5e26bbe83..5cd8a3a5f 100644
--- a/customize.dist/pages.js
+++ b/customize.dist/pages.js
@@ -501,5 +501,9 @@ define([
return loadingScreen();
};
+ Pages['/invite/'] = Pages['/invite/index.html'] = function () {
+ return loadingScreen();
+ };
+
return Pages;
});
diff --git a/customize.dist/template.js b/customize.dist/template.js
index ad00c5170..d187e9685 100644
--- a/customize.dist/template.js
+++ b/customize.dist/template.js
@@ -183,6 +183,8 @@ $(function () {
} else if (/^\/($|^\/index\.html$)/.test(pathname)) {
// TODO use different top bar
require([ '/customize/main.js', ], function () {});
+ } else if (/invite/.test(pathname)) {
+ require([ '/invite/main.js'], function () {});
} else {
require([ '/customize/main.js', ], function () {});
}
diff --git a/www/common/curve.js b/www/common/curve.js
new file mode 100644
index 000000000..62432a703
--- /dev/null
+++ b/www/common/curve.js
@@ -0,0 +1,37 @@
+define([
+ '/bower_components/tweetnacl/nacl-fast.min.js',
+], function () {
+ var Nacl = window.nacl;
+
+ var Curve = {};
+
+ // nacl.box(message, nonce, theirPublicKey, mySecretKey)
+ Curve.encrypt = function (message, theirPub, mySecret) {
+ var buffer = Nacl.util.decodeUTF8(message);
+
+ var nonce = Nacl.randomBytes(24);
+
+ var box = Nacl.box(buffer, nonce, theirPub, mySecret);
+
+ return [Nacl.util.encodeBase64(nonce), Nacl.util.encodeBase64(box)].join('|');
+ };
+
+ // nacl.box.open(box, nonce, theirPublicKey, mySecretKey)
+ Curve.decrypt = function (packed, theirPub, mySecret) {
+ var unpacked = packed.split('|');
+ var nonce = Nacl.util.decodeBase64(unpacked[0]);
+
+ var box = Nacl.util.decodeBase64(unpacked[1]);
+
+ var message = Nacl.box.open(box, nonce, theirPub, mySecret);
+
+ return Nacl.util.encodeUTF8(message);
+ };
+
+ Curve.createEncryptor = function () {
+ console.log("PEWPEW");
+ throw new Error("E_NOT_IMPL");
+ };
+
+ return Curve;
+});
diff --git a/www/invite/index.html b/www/invite/index.html
new file mode 100644
index 000000000..9aed29ca5
--- /dev/null
+++ b/www/invite/index.html
@@ -0,0 +1,20 @@
+
+
+
+
+ Cryptpad: Zero Knowledge, Collaborative Real Time Editing
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/www/invite/main.js b/www/invite/main.js
new file mode 100644
index 000000000..900c02e58
--- /dev/null
+++ b/www/invite/main.js
@@ -0,0 +1,94 @@
+define([
+ 'jquery',
+ '/common/cryptpad-common.js',
+ '/bower_components/chainpad-listmap/chainpad-listmap.js',
+ '/common/curve.js',
+ 'less!/invite/main.less',
+], function ($, Cryptpad, Listmap, Curve) {
+ var APP = window.APP = {};
+
+ var Nacl = window.nacl;
+
+ var alice = Nacl.box.keyPair();
+ var bob = Nacl.box.keyPair();
+
+ var packed = Curve.encrypt('pewpew', bob.publicKey, alice.secretKey);
+ console.log(packed);
+
+ var message = Curve.decrypt(packed, alice.publicKey, bob.secretKey);
+
+ console.log(message);
+
+ Cryptpad.removeLoadingScreen();
+ Cryptpad.alert(message);
+
+ return {};
+
+ //var Messages = Cryptpad.Messages;
+ var onReady = function () {
+
+ if (!APP.initialized) {
+ APP.initialized = true;
+ }
+ };
+
+ var onInit = function () {};
+
+ var onDisconnect = function () {};
+ var onChange = function () {};
+
+ var andThen = function (profileHash) {
+ var secret = Cryptpad.getSecrets('profile', profileHash);
+ var readOnly = APP.readOnly = secret.keys && !secret.keys.editKeyStr;
+ var listmapConfig = {
+ data: {},
+ websocketURL: Cryptpad.getWebsocketURL(),
+ channel: secret.channel,
+ readOnly: readOnly,
+ validateKey: secret.keys.validateKey || undefined,
+ crypto: Crypto.createEncryptor(secret.keys),
+ userName: 'profile',
+ logLevel: 1,
+ };
+ var lm = APP.lm = Listmap.create(listmapConfig);
+ lm.proxy.on('create', onInit)
+ .on('ready', onReady)
+ .on('disconnect', onDisconnect)
+ .on('change', [], onChange);
+ };
+
+ $(function () {
+ var $main = $('#mainBlock');
+ // Language selector
+ var $sel = $('#language-selector');
+ Cryptpad.createLanguageSelector(undefined, $sel);
+ $sel.find('button').addClass('btn').addClass('btn-secondary');
+ $sel.show();
+
+ // User admin menu
+ var $userMenu = $('#user-menu');
+ var userMenuCfg = {
+ $initBlock: $userMenu
+ };
+ var $userAdmin = Cryptpad.createUserAdminMenu(userMenuCfg);
+ $userAdmin.find('button').addClass('btn').addClass('btn-secondary');
+
+ $(window).click(function () {
+ $('.cryptpad-dropdown').hide();
+ });
+
+ // main block is hidden in case javascript is disabled
+ $main.removeClass('hidden');
+
+ APP.$container = $('#container');
+
+ Cryptpad.ready(function () {
+ Cryptpad.reportAppUsage();
+
+ if (window.location.hash) {
+ return void andThen(window.location.hash.slice(1));
+ }
+ });
+ });
+
+});
diff --git a/www/invite/main.less b/www/invite/main.less
new file mode 100644
index 000000000..d3d3f2e07
--- /dev/null
+++ b/www/invite/main.less
@@ -0,0 +1,137 @@
+.cp {
+ #mainBlock {
+ z-index: 1;
+ width: 1000px;
+ max-width: 90%;
+ margin: auto;
+ #container {
+ font-size: 25px;
+ width: 100%;
+ }
+ }
+ #header {
+ display: flex;
+ #rightside {
+ flex: 1;
+ display: flex;
+ flex-flow: column;
+ }
+ }
+ #avatar {
+ width: 300px;
+ //height: 350px;
+ margin: 10px;
+ margin-right: 20px;
+ text-align: center;
+ &> span {
+ display: inline-block;
+ text-align: center;
+ height: 300px;
+ width: 300px;
+ border: 1px solid black;
+ border-radius: 10px;
+ overflow: hidden;
+ position: relative;
+ .delete {
+ right: 0;
+ position: absolute;
+ opacity: 0.7;
+ &:hover {
+ opacity: 1;
+ }
+ }
+ }
+ img {
+ max-width: 100%;
+ max-height: 100%;
+ vertical-align: top;
+ }
+ media-tag {
+ height: 100%;
+ width: 100%;
+ display: inline-flex;
+ justify-content: center;
+ align-items: center;
+ img {
+ min-width: 100%;
+ min-height: 100%;
+ max-width: none;
+ max-height: none;
+ flex-shrink: 0;
+ }
+ }
+ button {
+ height: 40px;
+ margin: 5px;
+ }
+ }
+ #displayName, #link {
+ width: 100%;
+ height: 40px;
+ margin: 10px 0;
+ input {
+ width: 100%;
+ font-size: 20px;
+ box-sizing: border-box;
+ padding-right: 30px;
+ }
+ input:focus ~ .edit {
+ display: none;
+ }
+ .edit {
+ position: absolute;
+ margin-left: -25px;
+ margin-top: 8px;
+ }
+ .temp {
+ font-weight: 400;
+ font-family: sans-serif;
+ }
+ .displayName {
+ font-weight: bold;
+ font-size: 30px;
+ }
+ .displayName, .link {
+ line-height: 40px;
+ }
+ }
+ #description {
+ position: relative;
+ font-size: 16px;
+ border: 1px solid #DDD;
+ margin-bottom: 20px;
+ .rendered {
+ padding: 0 15px;
+ }
+ .ok, .spin {
+ position: absolute;
+ top: 2px;
+ right: 2px;
+ display: none;
+ z-index: 1000;
+ }
+ textarea {
+ width: 100%;
+ height: 300px;
+ }
+ .CodeMirror {
+ border: 1px solid #DDD;
+ font-family: monospace;
+ font-size: 16px;
+ line-height: initial;
+ pre {
+ margin: 0;
+ font-family: inherit;
+ font-size: inherit;
+ line-height: inherit;
+ }
+ }
+ }
+ #createProfile {
+ height: 100%;
+ display: flex;
+ flex-flow: column;
+ align-items: center;
+ justify-content: center;
+ }
+}