diff --git a/customize.dist/fonts/cptools/fonts/cptools.svg b/customize.dist/fonts/cptools/fonts/cptools.svg index f7fe0879f..93eef8d38 100644 --- a/customize.dist/fonts/cptools/fonts/cptools.svg +++ b/customize.dist/fonts/cptools/fonts/cptools.svg @@ -25,4 +25,5 @@ + \ No newline at end of file diff --git a/customize.dist/fonts/cptools/fonts/cptools.ttf b/customize.dist/fonts/cptools/fonts/cptools.ttf index 1dac2ff87..18338a9ee 100644 Binary files a/customize.dist/fonts/cptools/fonts/cptools.ttf and b/customize.dist/fonts/cptools/fonts/cptools.ttf differ diff --git a/customize.dist/fonts/cptools/fonts/cptools.woff b/customize.dist/fonts/cptools/fonts/cptools.woff index 4f01d5d15..d8f56ba86 100644 Binary files a/customize.dist/fonts/cptools/fonts/cptools.woff and b/customize.dist/fonts/cptools/fonts/cptools.woff differ diff --git a/customize.dist/fonts/cptools/style.css b/customize.dist/fonts/cptools/style.css index 952207f15..349b62f2b 100644 --- a/customize.dist/fonts/cptools/style.css +++ b/customize.dist/fonts/cptools/style.css @@ -1,9 +1,9 @@ @font-face { font-family: 'cptools'; src: - url('fonts/cptools.ttf?yr9e7c') format('truetype'), - url('fonts/cptools.woff?yr9e7c') format('woff'), - url('fonts/cptools.svg?yr9e7c#cptools') format('svg'); + url('fonts/cptools.ttf?cljhos') format('truetype'), + url('fonts/cptools.woff?cljhos') format('woff'), + url('fonts/cptools.svg?cljhos#cptools') format('svg'); font-weight: normal; font-style: normal; } @@ -24,6 +24,9 @@ -moz-osx-font-smoothing: grayscale; } +.cptools-folder-upload:before { + content: "\e912"; +} .cptools-folder-no-color:before { content: "\e900"; } diff --git a/customize.dist/src/less2/include/notifications.less b/customize.dist/src/less2/include/notifications.less index b19a9c86b..f27d6ed60 100644 --- a/customize.dist/src/less2/include/notifications.less +++ b/customize.dist/src/less2/include/notifications.less @@ -1,4 +1,5 @@ @import (reference) "./colortheme-all.less"; +@import (reference) "./avatar.less"; .notifications_main() { --LessLoader_require: LessLoader_currentFile(); @@ -53,6 +54,19 @@ } } } + .cp-notifications-requestedit-verified { + display: flex; + align-items: center; + &> span.cp-avatar { + .avatar_main(30px); + } + &> span { + margin-right: 10px; + } + &> p { + margin: 0; + } + } } diff --git a/customize.dist/src/less2/include/support.less b/customize.dist/src/less2/include/support.less index 56dcccd8f..0a352ec32 100644 --- a/customize.dist/src/less2/include/support.less +++ b/customize.dist/src/less2/include/support.less @@ -44,6 +44,7 @@ } pre { margin-bottom: 0; + white-space: pre-wrap; &.cp-support-message-content { margin-top: 10px; margin-bottom: 10px; diff --git a/package-lock.json b/package-lock.json index 30b43f03e..7a91644fa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "cryptpad", - "version": "2.23.0", + "version": "2.25.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -573,16 +573,16 @@ "dev": true }, "jshint": { - "version": "2.9.7", - "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.7.tgz", - "integrity": "sha512-Q8XN38hGsVQhdlM+4gd1Xl7OB1VieSuCJf+fEJjpo59JH99bVJhXRXAh26qQ15wfdd1VPMuDWNeSWoNl53T4YA==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.10.2.tgz", + "integrity": "sha512-e7KZgCSXMJxznE/4WULzybCMNXNAd/bf5TSrvVEq78Q/K8ZwFpmBqQeDtNiHc3l49nV4E/+YeHU/JZjSUIrLAA==", "dev": true, "requires": { "cli": "~1.0.0", "console-browserify": "1.1.x", "exit": "0.1.x", "htmlparser2": "3.8.x", - "lodash": "~4.17.10", + "lodash": "~4.17.11", "minimatch": "~3.0.2", "shelljs": "0.3.x", "strip-json-comments": "1.0.x" @@ -697,9 +697,9 @@ } }, "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "version": "4.17.14", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz", + "integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==", "dev": true }, "lodash.clonedeep": { @@ -709,10 +709,9 @@ "dev": true }, "lodash.merge": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz", - "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==", - "dev": true + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, "lodash.sortby": { "version": "4.7.0", diff --git a/package.json b/package.json index 1a6462d84..585e8b8fc 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ }, "devDependencies": { "flow-bin": "^0.59.0", - "jshint": "~2.9.1", + "jshint": "^2.10.2", "less": "2.7.1", "lesshint": "^4.5.0", "selenium-webdriver": "^3.6.0" diff --git a/www/admin/inner.js b/www/admin/inner.js index e2edb9ad5..4c335dd12 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -199,13 +199,13 @@ define([ // A ticket has been closed by the admins... if (!$ticket.length) { return; } $ticket.addClass('cp-support-list-closed'); - $ticket.append(Support.makeCloseMessage(common, content, hash)); + $ticket.append(APP.support.makeCloseMessage(content, hash)); return; } if (msg.type !== 'TICKET') { return; } if (!$ticket.length) { - $ticket = Support.makeTicket($div, common, content, function () { + $ticket = APP.support.makeTicket($div, content, function () { var error = false; hashesById[id].forEach(function (d) { common.mailbox.dismiss(d, function (err) { @@ -218,7 +218,7 @@ define([ if (!error) { $ticket.remove(); } }); } - $ticket.append(Support.makeMessage(common, content, hash, true)); + $ticket.append(APP.support.makeMessage(content, hash)); } }); return $div; @@ -349,6 +349,7 @@ define([ APP.privateKey = privateData.supportPrivateKey; APP.origin = privateData.origin; APP.readOnly = privateData.readOnly; + APP.support = Support.create(common, true); // Content var $rightside = APP.$rightside; diff --git a/www/code/inner.js b/www/code/inner.js index 9e4d0a207..b061e36fa 100644 --- a/www/code/inner.js +++ b/www/code/inner.js @@ -363,7 +363,15 @@ define([ }); framework.setFileExporter(CodeMirror.getContentExtension, CodeMirror.fileExporter); - framework.setFileImporter({}, CodeMirror.fileImporter); + framework.setFileImporter({}, function () { + /* setFileImporter currently takes a function with the following signature: + (content, file) => {} + I used 'apply' with 'arguments' to avoid breaking things if this API ever changes. + */ + var ret = CodeMirror.fileImporter.apply(null, Array.prototype.slice.call(arguments)); + previewPane.modeChange(ret.mode); + return ret; + }); framework.setNormalizer(function (c) { return { diff --git a/www/common/curve-put.js b/www/common/curve-put.js deleted file mode 100644 index 450b62564..000000000 --- a/www/common/curve-put.js +++ /dev/null @@ -1,51 +0,0 @@ -define([ - '/common/curve.js', - '/bower_components/chainpad-listmap/chainpad-listmap.js', -], function (Curve, Listmap) { - var Edit = {}; - - Edit.create = function (config, cb) { //network, channel, theirs, mine, cb) { - var network = config.network; - var channel = config.channel; - var keys = config.keys; - - try { - var encryptor = Curve.createEncryptor(keys); - var lm = Listmap.create({ - network: network, - data: {}, - channel: channel, - readOnly: false, - validateKey: keys.validateKey || undefined, - crypto: encryptor, - userName: 'lol', - logLevel: 1, - }); - - var done = function () { - // TODO make this abort and disconnect the session after the - // user has finished making changes to the object, and they - // have propagated. - }; - - lm.proxy - .on('create', function () { - console.log('created'); - }) - .on('ready', function () { - console.log('ready'); - cb(lm, done); - }) - .on('disconnect', function () { - console.log('disconnected'); - }) - .on('change', [], function (o, n, p) { - console.log(o, n, p); - }); - } catch (e) { - console.error(e); - } - }; - - return Edit; -}); diff --git a/www/common/notifications.js b/www/common/notifications.js index e57228265..7ab504fb6 100644 --- a/www/common/notifications.js +++ b/www/common/notifications.js @@ -94,6 +94,18 @@ define([ } }; + // New support message from the admins + handlers['SUPPORT_MESSAGE'] = function (common, data) { + var content = data.content; + content.getFormatText = function () { + return Messages.support_notification; + }; + content.handler = function () { + common.openURL('/support/'); + defaultDismiss(common, data)(); + }; + }; + handlers['REQUEST_PAD_ACCESS'] = function (common, data) { var content = data.content; var msg = content.msg; @@ -103,18 +115,50 @@ define([ // Display the notification content.getFormatText = function () { - return 'Edit access request: ' + msg.content.title + ' - ' + msg.content.user.displayName; - }; // XXX + return Messages._getKey('requestEdit_request', [msg.content.title, msg.content.user.displayName]); + }; // if not archived, add handlers content.handler = function () { - UI.confirm("Give edit rights?", function (yes) { + var metadataMgr = common.getMetadataMgr(); + var priv = metadataMgr.getPrivateData(); + + var link = h('a', { + href: '#' + }, Messages.requestEdit_viewPad); + var verified = h('p.cp-notifications-requestedit-verified'); + var $verified = $(verified); + + if (priv.friends && priv.friends[msg.author]) { + var f = priv.friends[msg.author]; + $verified.append(h('span.fa.fa-certificate')); + var $avatar = $(h('span.cp-avatar')).appendTo($verified); + $verified.append(h('p', Messages._getKey('requestEdit_fromFriend', [f.displayName]))); + common.displayAvatar($avatar, f.avatar, f.displayName); + } else { + $verified.append(Messages.requestEdit_fromStranger); + } + + var div = h('div', [ + UI.setHTML(h('p'), Messages._getKey('requestEdit_confirm', [msg.content.title, msg.content.user.displayName])), + verified, + link + ]); + $(link).click(function (e) { + e.preventDefault(); + e.stopPropagation(); + common.openURL(msg.content.href); + }); + UI.confirm(div, function (yes) { if (!yes) { return; } common.getSframeChannel().event('EV_GIVE_ACCESS', { channel: msg.content.channel, user: msg.content.user }); defaultDismiss(common, data)(); + }, { + ok: Messages.friendRequest_accept, + cancel: Messages.later }); }; @@ -134,8 +178,8 @@ define([ // Display the notification content.getFormatText = function () { - return 'Edit access received: ' + msg.content.title + ' from ' + msg.content.user.displayName; - }; // XXX + return Messages._getKey('requestEdit_accepted', [msg.content.title, msg.content.user.displayName]); + }; // if not archived, add handlers content.handler = function () { diff --git a/www/common/onlyoffice/app-oo.less b/www/common/onlyoffice/app-oo.less index 60510914d..c7bd64e01 100644 --- a/www/common/onlyoffice/app-oo.less +++ b/www/common/onlyoffice/app-oo.less @@ -44,6 +44,7 @@ body.cp-app-sheet, body.cp-app-oodoc, body.cp-app-ooslide { height: 100%; background-color: lightgrey; display: flex; + min-height: 0; } #cp-app-oo-editor { flex: 1; diff --git a/www/common/outer/mailbox-handlers.js b/www/common/outer/mailbox-handlers.js index 42997b3e0..9d383caa1 100644 --- a/www/common/outer/mailbox-handlers.js +++ b/www/common/outer/mailbox-handlers.js @@ -201,6 +201,14 @@ define([ } }; + // Hide duplicates when receiving a SUPPORT_MESSAGE notification + var supportMessage = false; + handlers['SUPPORT_MESSAGE'] = function (ctx, box, data, cb) { + if (supportMessage) { return void cb(true); } + supportMessage = true; + cb(); + }; + // Incoming edit rights request: add data before sending it to inner handlers['REQUEST_PAD_ACCESS'] = function (ctx, box, data, cb) { var msg = data.msg; @@ -214,17 +222,19 @@ define([ if (!res.length) { return void cb(true); } var edPublic = ctx.store.proxy.edPublic; - var title; + var title, href; if (!res.some(function (obj) { if (obj.data && Array.isArray(obj.data.owners) && obj.data.owners.indexOf(edPublic) !== -1 && obj.data.href) { + href = obj.data.href; title = obj.data.filename || obj.data.title; return true; } })) { return void cb(true); } content.title = title; + content.href = href; cb(false); }; diff --git a/www/common/outer/mailbox.js b/www/common/outer/mailbox.js index 24d14345f..081f64cc3 100644 --- a/www/common/outer/mailbox.js +++ b/www/common/outer/mailbox.js @@ -245,8 +245,11 @@ proxy.mailboxes = { }); box.queue = []; }; + var lastReceivedHash; // Don't send a duplicate of the last known hash on reconnect box.onMessage = cfg.onMessage = function (msg, user, vKey, isCp, hash, author) { if (hash === m.lastKnownHash) { return; } + if (hash === lastReceivedHash) { return; } + lastReceivedHash = hash; try { msg = JSON.parse(msg); } catch (e) { @@ -364,6 +367,7 @@ proxy.mailboxes = { txid: txid, complete: true }, [req.cId]); + delete ctx.req[txid]; } }); }; diff --git a/www/common/outer/userObject.js b/www/common/outer/userObject.js index e12883eb5..4f235366a 100644 --- a/www/common/outer/userObject.js +++ b/www/common/outer/userObject.js @@ -506,8 +506,14 @@ define([ var fixRoot = function (elem) { if (typeof(files[ROOT]) !== "object") { debug("ROOT was not an object"); files[ROOT] = {}; } var element = elem || files[ROOT]; + if (!element) { return console.error("Invalid element in root"); } var nbMetadataFolders = 0; for (var el in element) { + if (element[el] === null) { + console.error('element[%s] is null', el); + delete element[el]; + continue; + } if (exp.isFolderData(element[el])) { if (nbMetadataFolders !== 0) { debug("Multiple metadata files in folder"); diff --git a/www/common/sframe-common-codemirror.js b/www/common/sframe-common-codemirror.js index ebf7d752e..8a0e2de63 100644 --- a/www/common/sframe-common-codemirror.js +++ b/www/common/sframe-common-codemirror.js @@ -323,7 +323,7 @@ define([ var mode; if (!mime) { var ext = /.+\.([^.]+)$/.exec(file.name); - if (ext[1]) { + if (ext && ext[1]) { mode = CMeditor.findModeByExtension(ext[1]); mode = mode && mode.mode || null; } @@ -339,7 +339,8 @@ define([ exp.setMode('text'); $toolbarContainer.find('#language-mode').val('text'); } - return { content: content }; + // return the mode so that the code editor can decide how to display the new content + return { content: content, mode: mode }; }; exp.setValueAndCursor = function (oldDoc, remoteDoc) { diff --git a/www/common/toolbar3.js b/www/common/toolbar3.js index 53aa93f4f..6c262e2d1 100644 --- a/www/common/toolbar3.js +++ b/www/common/toolbar3.js @@ -585,7 +585,7 @@ MessengerUI, Messages) { var $requestBlock = $('', { 'class': 'fa fa-lock cp-toolbar-share-button', - title: 'REQUEST ACCESS' // XXX + title: Messages.requestEdit_button }).hide(); // If we have access to the owner's mailbox, display the button and enable it @@ -593,10 +593,16 @@ MessengerUI, Messages) { // true ==> send the request Common.getSframeChannel().query('Q_REQUEST_ACCESS', false, function (err, obj) { if (obj && obj.state) { + var locked = false; $requestBlock.show().click(function () { + if (locked) { return; } + locked = true; Common.getSframeChannel().query('Q_REQUEST_ACCESS', true, function (err, obj) { if (obj && obj.state) { - UI.log('sent'); // XXX + UI.log(Messages.requestEdit_sent); + $requestBlock.hide(); + } else { + locked = false; } }); }); diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json index 7c5a2ee5b..297c87390 100644 --- a/www/common/translations/messages.json +++ b/www/common/translations/messages.json @@ -1111,5 +1111,17 @@ "notifications_cat_friends": "Friend requests", "notifications_cat_pads": "Shared with me", "notifications_cat_archived": "History", - "notifications_dismissAll": "Dismiss all" + "notifications_dismissAll": "Dismiss all", + "support_notification": "An administrator has responded to your support ticket", + "requestEdit_button": "Request edit rights", + "requestEdit_dialog": "Are you sure you'd like to ask the owner of this pad for the ability to edit?", + "requestEdit_confirm": "{1} has asked for the ability to edit the pad {0}. Would you like to grant them access?", + "requestEdit_fromFriend": "You are friends with {0}", + "requestEdit_fromStranger": "You are not friends with {0}", + "requestEdit_viewPad": "Open the pad in a new tab", + "later": "Decide later", + "requestEdit_request": "{1} wants to edit the pad {0}", + "requestEdit_accepted": "{1} granted you edit rights for the pad {0}", + "requestEdit_sent": "Request sent", + "uploadFolderButton": "Upload folder" } diff --git a/www/common/translations/messages.ru.json b/www/common/translations/messages.ru.json index e8f61dfe2..ca1a1f143 100644 --- a/www/common/translations/messages.ru.json +++ b/www/common/translations/messages.ru.json @@ -389,5 +389,64 @@ "fc_empty": "Удалить корзину", "fc_prop": "Свойства", "fc_hashtag": "Теги", - "fc_sizeInKilobytes": "Размер в килобайтах" + "fc_sizeInKilobytes": "Размер в килобайтах", + "poll_title": "Приватный выбор даты", + "fm_moveNestedSF": "Нельзя помещать одну общую папку в другую. Папка {0} не была перемещена.", + "fc_color": "Изменить цвет", + "fc_expandAll": "Расширить все", + "fc_collapseAll": "Скрыть все", + "fc_remove": "Удалить из вашего CryptDrive", + "fo_moveUnsortedError": "Вы не можете переместить папку в список черновиков", + "fo_existingNameError": "Это имя уже используется в данной директории. Пожалуйста выберите другое.", + "fo_unableToRestore": "Невозможно восстановить этот файл в исходное местоположение. Вы можете попытаться переместить его в другое место.", + "login_login": "Войти", + "login_makeAPad": "Создать анонимный пэд", + "login_nologin": "Просмотреть локальные пэды", + "login_register": "Зарегистрироваться", + "logoutButton": "Выйти", + "settingsButton": "Настройки", + "login_username": "Имя пользователя", + "login_password": "Пароль", + "login_confirm": "Подтвердите ваш пароль", + "login_remember": "Запомнить меня", + "login_hashing": "Ваш пароль хэшируется, это может занять некое время.", + "login_hello": "Привет {0},", + "login_helloNoName": "Привет,", + "fm_info_sharedFolder": "Это общая папка. Вы не вошли в систему, поэтому можете получить к ней доступ только в режиме только для чтения.Sign up или Log in для импорта на CryptDrive и его изменения.", + "fo_moveFolderToChildError": "Вы не можете переместить папку в одну из нее следующую", + "fo_unavailableName": "Файл или папка с таким же именем уже существуют в новом месте. Переименуйте элемент и повторите попытку.", + "fs_migration": "Ваш CryptDrive обновляется до новой версии. В результате, текущая страница должна быть перезагружена. перезагрузите эту страницу, чтобы продолжить ей пользоваться..", + "login_accessDrive": "Доступ к хранилищу", + "login_orNoLogin": "или", + "login_noSuchUser": "Неверный логин или пароль. Попробуйте еще раз или зарегистрируйтесь", + "login_invalUser": "Неоьходимо имя пользователя", + "login_invalPass": "Необходим пароль", + "login_unhandledError": "Произошла неожиданная ошибка :(", + "register_importRecent": "Импортировать пэды из вашей анонимной сессии", + "register_passwordsDontMatch": "Пароли не совпадают!", + "register_passwordTooShort": "Длина пароля должна составлять не менее {0} символов.", + "register_mustAcceptTerms": "Вы должны принять условия пользования.", + "register_mustRememberPass": "Мы не сможем сбросить ваш пароль, если вы его забудете. Очень важно, чтобы вы его запомнили! Пожалуйста, отметьте флажок для подтверждения.", + "register_whyRegister": "Почему стоит зарегистрироваться?", + "register_header": "Добро пожаловать в CryptPad", + "register_writtenPassword": "Я записал свое имя пользователя и пароль, продолжить", + "register_cancel": "Назад", + "register_alreadyRegistered": "Этот пользователь уже существует, вы хотите войти?", + "settings_cat_account": "Учетная запись", + "settings_cat_drive": "КриптДрайв", + "settings_cat_cursor": "курсор", + "settings_cat_code": "Код", + "settings_cat_pad": "Текст с форматированием", + "settings_cat_creation": "новый пэд", + "settings_cat_subscription": "Подписка", + "settings_title": "Настройки", + "settings_save": "Сохранить", + "settings_backupHint": "Резервное копирование или восстановление всего содержимого CryptDrive. Он не будет содержать содержимое ваших пэдов, только ключи для доступа к ним.", + "settings_restore": "Восстановить", + "settings_exportDescription": "Пожалуйста, подождите, пока мы загружаем и расшифровываем ваши документы. Это может занять несколько минут. Закрытие вкладки прервет процесс.", + "settings_exportFailed": "Если загрузка пэда занимает более 1 минуты, он не будет включен в экспорт. Отображается ссылка на любой блокнот, который не был экспортирован.", + "settings_exportWarning": "Примечание: этот инструмент все еще находится в бета-версии и может иметь проблемы со масштабируемостью. Для повышения производительности рекомендуется оставить данную вкладку сфокусированной.", + "settings_exportCancel": "Вы уверены, что хотите отменить экспорт? В следующий раз вам придется начинать все сначала.", + "settings_export_reading": "Читаем ваше хранилище...", + "settings_export_download": "Скачиваем и расшифровываем ваши документы..." } diff --git a/www/drive/inner.js b/www/drive/inner.js index f393cac3f..f69c36060 100644 --- a/www/drive/inner.js +++ b/www/drive/inner.js @@ -512,13 +512,14 @@ define([ // Tags used: display Tags category if (Object.keys(manager.getTagsList()).length) { displayedCategories.push(TAGS); } - var virtualCategories = [SEARCH, RECENT, OWNED, TAGS, SHARED_FOLDER]; + var virtualCategories = [SEARCH, RECENT, OWNED, TAGS]; if (!APP.loggedIn) { $tree.hide(); if (APP.newSharedFolder) { // ANON_SHARED_FOLDER displayedCategories = [SHARED_FOLDER]; + virtualCategories.push(SHARED_FOLDER); currentPath = [SHARED_FOLDER, ROOT]; } else { displayedCategories = [FILES_DATA]; diff --git a/www/invite/index.html b/www/invite/index.html deleted file mode 100644 index 5200564ce..000000000 --- a/www/invite/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - CryptPad: Zero Knowledge, Collaborative Real Time Editing - - - - - - - - - - - - OOPS In order to do encryption in your browser, Javascript is really really required. - OUPS Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est vraiment nécessaire. - - diff --git a/www/invite/main.js b/www/invite/main.js deleted file mode 100644 index 97f64ab8e..000000000 --- a/www/invite/main.js +++ /dev/null @@ -1,88 +0,0 @@ -define([ - 'jquery', - '/common/cryptpad-common.js', - '/common/common-interface.js', - //'/common/common-hash.js', - //'/bower_components/chainpad-listmap/chainpad-listmap.js', - //'/common/curve.js', - 'less!/invite/main.less', -], function ($, Cryptpad, UI/*, Hash , Listmap, Curve*/) { - var Messages = Cryptpad.Messages; - var comingSoon = function () { - return $('', { - 'class': 'coming-soon', - }) - .text(Messages.comingSoon) - .append(''); - }; - - $(function () { - UI.removeLoadingScreen(); - console.log("wut"); - $('body #mainBlock').append(comingSoon()); - }); - return; - - /* jshint ignore:start */ - var APP = window.APP = {}; - - //var Messages = Cryptpad.Messages; - var onInit = function () {}; - - var onDisconnect = function () {}; - var onChange = function () {}; - - var andThen = function () { - var hash = window.location.hash.slice(1); - - var info = Hash.parseTypeHash('invite', hash); - console.log(info); - - if (!info.pubkey) { - UI.removeLoadingScreen(); - UI.alert('invalid invite'); - return; - } - - var proxy = Cryptpad.getProxy(); - var mySecret = proxy.curvePrivate; - - var keys = Curve.deriveKeys(info.pubkey, mySecret); - var encryptor = Curve.createEncryptor(keys); - - UI.removeLoadingScreen(); - - var listmapConfig = { - data: {}, - network: Cryptpad.getNetwork(), - channel: info.channel, - readOnly: false, - validateKey: keys.validateKey, - crypto: encryptor, - userName: 'profile', - logLevel: 1, - }; - var lm = APP.lm = Listmap.create(listmapConfig); - lm.proxy.on('create', onInit) - .on('ready', function () { - APP.initialized = true; - console.log(JSON.stringify(lm.proxy)); - }) - .on('disconnect', onDisconnect) - .on('change', [], onChange); - }; - - $(function () { - var $main = $('#mainBlock'); - - // main block is hidden in case javascript is disabled - $main.removeClass('hidden'); - - APP.$container = $('#container'); - - Cryptpad.ready(function () { - andThen(); - }); - }); - /* jshint ignore:end */ -}); diff --git a/www/invite/main.less b/www/invite/main.less deleted file mode 100644 index 4ef2a8fa4..000000000 --- a/www/invite/main.less +++ /dev/null @@ -1,150 +0,0 @@ -/* -.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; - } -} -*/ - -.coming-soon { - text-align: center; - font-size: 25px; - - height: 100%; - display: flex; - flex-flow: column; - align-items: center; - justify-content: center; -} diff --git a/www/profile/inner.js b/www/profile/inner.js index 8f589107f..75f1022f8 100644 --- a/www/profile/inner.js +++ b/www/profile/inner.js @@ -559,7 +559,7 @@ define([ lm.proxy.on('ready', function () { updateValues(lm.proxy); UI.removeLoadingScreen(); - common.mailbox.subscribe({ + common.mailbox.subscribe(["notifications"], { onMessage: function () { refreshFriendRequest(lm.proxy); }, diff --git a/www/support/inner.js b/www/support/inner.js index 4de6fcb04..ded97b272 100644 --- a/www/support/inner.js +++ b/www/support/inner.js @@ -107,13 +107,13 @@ define([ // A ticket has been closed by the admins... if (!$ticket.length) { return; } $ticket.addClass('cp-support-list-closed'); - $ticket.append(Support.makeCloseMessage(common, content, hash)); + $ticket.append(APP.support.makeCloseMessage(content, hash)); return; } if (msg.type !== 'TICKET') { return; } if (!$ticket.length) { - $ticket = Support.makeTicket($div, common, content, function () { + $ticket = APP.support.makeTicket($div, content, function () { var error = false; hashesById[id].forEach(function (d) { common.mailbox.dismiss(d, function (err) { @@ -126,7 +126,7 @@ define([ if (!error) { $ticket.remove(); } }); } - $ticket.append(Support.makeMessage(common, content, hash, false)); + $ticket.append(APP.support.makeMessage(content, hash)); } }); return $div; @@ -137,7 +137,7 @@ define([ var key = 'form'; var $div = makeBlock(key, true); - var form = Support.makeForm(); + var form = APP.support.makeForm(); $div.find('button').before(form); @@ -147,7 +147,7 @@ define([ var metadataMgr = common.getMetadataMgr(); var privateData = metadataMgr.getPrivateData(); var user = metadataMgr.getUserData(); - var sent = Support.sendForm(common, id, form, { + var sent = APP.support.sendForm(id, form, { channel: privateData.support, curvePublic: user.curvePublic }); @@ -244,6 +244,7 @@ define([ APP.origin = privateData.origin; APP.readOnly = privateData.readOnly; + APP.support = Support.create(common, false); // Content var $rightside = APP.$rightside; diff --git a/www/support/ui.js b/www/support/ui.js index ef91c56a1..34207b219 100644 --- a/www/support/ui.js +++ b/www/support/ui.js @@ -8,7 +8,8 @@ define([ '/customize/messages.js', ], function ($, ApiConfig, h, UI, Hash, Util, Messages) { - var send = function (common, id, type, data, dest) { + var send = function (ctx, id, type, data, dest) { + var common = ctx.common; var supportKey = ApiConfig.supportMailbox; var supportChannel = Hash.getChannelIdFromKey(supportKey); var metadataMgr = common.getMetadataMgr(); @@ -27,6 +28,10 @@ define([ data.id = id; data.time = +new Date(); + if (!ctx.isAdmin) { + data.sender.userAgent = window.navigator && window.navigator.userAgent; + } + // Send the message to the admin mailbox and to the user mailbox common.mailbox.sendTo(type, data, { channel: supportChannel, @@ -36,9 +41,16 @@ define([ channel: dest.channel, curvePublic: dest.curvePublic }); + + if (ctx.isAdmin) { + common.mailbox.sendTo('SUPPORT_MESSAGE', {}, { + channel: dest.notifications, + curvePublic: dest.curvePublic + }); + } }; - var sendForm = function (common, id, form, dest) { + var sendForm = function (ctx, id, form, dest) { var $title = $(form).find('.cp-support-form-title'); var $content = $(form).find('.cp-support-form-msg'); @@ -53,7 +65,7 @@ define([ $content.val(''); $title.val(''); - send(common, id, 'TICKET', { + send(ctx, id, 'TICKET', { title: title, message: content, }, dest); @@ -97,7 +109,7 @@ define([ return form; }; - var makeTicket = function ($div, common, content, onHide) { + var makeTicket = function (ctx, $div, content, onHide) { var ticketTitle = content.title + ' (#' + content.id + ')'; var answer = h('button.btn.btn-primary.cp-support-answer', Messages.support_answer); var close = h('button.btn.btn-danger.cp-support-close', Messages.support_close); @@ -117,7 +129,7 @@ define([ ])); $(close).click(function () { - send(common, content.id, 'CLOSE', {}, content.sender); + send(ctx, content.id, 'CLOSE', {}, content.sender); }); $(hide).click(function () { @@ -129,7 +141,7 @@ define([ $ticket.find('.cp-support-form-container').remove(); $(actions).hide(); var form = makeForm(function () { - var sent = sendForm(common, content.id, form, content.sender); + var sent = sendForm(ctx, content.id, form, content.sender); if (sent) { $(actions).show(); $(form).remove(); @@ -142,7 +154,9 @@ define([ return $ticket; }; - var makeMessage = function (common, content, hash, isAdmin) { + var makeMessage = function (ctx, content, hash) { + var common = ctx.common; + var isAdmin = ctx.isAdmin; var metadataMgr = common.getMetadataMgr(); var privateData = metadataMgr.getPrivateData(); @@ -169,7 +183,8 @@ define([ ]); }; - var makeCloseMessage = function (common, content, hash) { + var makeCloseMessage = function (ctx, content, hash) { + var common = ctx.common; var metadataMgr = common.getMetadataMgr(); var privateData = metadataMgr.getPrivateData(); var fromMe = content.sender && content.sender.edPublic === privateData.edPublic; @@ -185,11 +200,30 @@ define([ ]); }; + var create = function (common, isAdmin) { + var ui = {}; + var ctx = { + common: common, + isAdmin: isAdmin + }; + + ui.sendForm = function (id, form, dest) { + return sendForm(ctx, id, form, dest); + }; + ui.makeForm = makeForm; + ui.makeTicket = function ($div, content, onHide) { + return makeTicket(ctx, $div, content, onHide); + }; + ui.makeMessage = function (content, hash) { + return makeMessage(ctx, content, hash); + }; + ui.makeCloseMessage = function (content, hash) { + return makeCloseMessage(ctx, content, hash); + }; + return ui; + }; + return { - sendForm: sendForm, - makeForm: makeForm, - makeTicket: makeTicket, - makeMessage: makeMessage, - makeCloseMessage: makeCloseMessage + create: create }; });
OOPS In order to do encryption in your browser, Javascript is really really required.
OUPS Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est vraiment nécessaire.