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; + } +}