From e85b34f1279c1b6cc39e632bc36ed343b078227f Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 5 Sep 2017 18:38:51 +0200 Subject: [PATCH 1/9] Add embed options in the secure pad hashes --- www/assert/main.js | 33 +++++++++++++++++++++++++++++++ www/common/common-hash.js | 25 ++++++++++++++++++++++- www/common/cryptpad-common.js | 3 ++- www/common/sframe-common-outer.js | 11 ++++++++++- www/common/toolbar3.js | 9 ++++++++- www/slide/slide.js | 18 ++++++++--------- 6 files changed, 85 insertions(+), 14 deletions(-) diff --git a/www/assert/main.js b/www/assert/main.js index 6f924f1b0..0913674ae 100644 --- a/www/assert/main.js +++ b/www/assert/main.js @@ -193,6 +193,39 @@ define([ && secret.hashData.present); }, "Couldn't handle multiple successive slashes"); + // test support for present & embed mode in hashes + assert(function (cb) { + var secret = Cryptpad.parsePadUrl('/pad/#/1/edit//CmN5+YJkrHFS3NSBg-P7Sg/DNZ2wcG683GscU4fyOyqA87G/embed/present/'); + return cb(secret.hashData.version === 1 + && secret.hashData.mode === "edit" + && secret.hashData.channel === "CmN5+YJkrHFS3NSBg-P7Sg" + && secret.hashData.key === "DNZ2wcG683GscU4fyOyqA87G" + && secret.hashData.present + && secret.hashData.embed); + }, "Couldn't handle multiple successive slashes"); + + // test support for present & embed mode in hashes + assert(function (cb) { + var secret = Cryptpad.parsePadUrl('/pad/#/1/edit//CmN5+YJkrHFS3NSBg-P7Sg/DNZ2wcG683GscU4fyOyqA87G/present/embed'); + return cb(secret.hashData.version === 1 + && secret.hashData.mode === "edit" + && secret.hashData.channel === "CmN5+YJkrHFS3NSBg-P7Sg" + && secret.hashData.key === "DNZ2wcG683GscU4fyOyqA87G" + && secret.hashData.present + && secret.hashData.embed); + }, "Couldn't handle multiple successive slashes"); + + // test support for embed mode in hashes + assert(function (cb) { + var secret = Cryptpad.parsePadUrl('/pad/#/1/edit//CmN5+YJkrHFS3NSBg-P7Sg/DNZ2wcG683GscU4fyOyqA87G///embed//'); + return cb(secret.hashData.version === 1 + && secret.hashData.mode === "edit" + && secret.hashData.channel === "CmN5+YJkrHFS3NSBg-P7Sg" + && secret.hashData.key === "DNZ2wcG683GscU4fyOyqA87G" + && !secret.hashData.present + && secret.hashData.embed); + }, "Couldn't handle multiple successive slashes"); + // test support for trailing slash assert(function (cb) { var secret = Cryptpad.parsePadUrl('/pad/#/1/edit/3Ujt4F2Sjnjbis6CoYWpoQ/usn4+9CqVja8Q7RZOGTfRgqI/'); diff --git a/www/common/common-hash.js b/www/common/common-hash.js index 5ed7ece36..ead686664 100644 --- a/www/common/common-hash.js +++ b/www/common/common-hash.js @@ -68,7 +68,9 @@ Version 1 parsed.mode = hashArr[2]; parsed.channel = hashArr[3]; parsed.key = hashArr[4].replace(/-/g, '/'); - parsed.present = typeof(hashArr[5]) === "string" && hashArr[5] === 'present'; + var options = hashArr.slice(5); + parsed.present = options.indexOf('present') !== -1; + parsed.embed = options.indexOf('embed') !== -1; return parsed; } return parsed; @@ -115,6 +117,27 @@ Version 1 var idx; + ret.getUrl = function (options) { + options = options || {}; + var url = '/'; + if (!ret.type) { return url; } + url += ret.type + '/'; + if (!ret.hashData) { return url; } + if (ret.hashData.type !== 'pad') { return url + '/#' + ret.hash; } + if (ret.hashData.version !== 1) { throw new Error("Only v1 hashes are managed here."); } + url += '#/' + ret.hashData.version + + '/' + ret.hashData.mode + + '/' + ret.hashData.channel.replace(/\//g, '-') + + '/' + ret.hashData.key.replace(/\//g, '-') +'/'; + if (options.embed) { + url += 'embed/'; + } + if (options.present) { + url += 'present/'; + } + return url; + }; + if (!/^https*:\/\//.test(href)) { idx = href.indexOf('/#'); ret.type = href.slice(1, idx); diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 6b07380ed..87168ca7c 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -674,7 +674,8 @@ define([ var href = typeof padHref === "string" ? padHref : window.location.href; var parsed = parsePadUrl(href); if (!parsed.hash) { return; } - href = getRelativeHref(href); + href = parsed.getUrl({present: parsed.present}); + //href = getRelativeHref(href); // getRecentPads return the array from the drive, not a copy // We don't have to call "set..." at the end, everything is stored with listmap getRecentPads(function (err, recent) { diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 1cecf279b..189bab6e2 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -82,7 +82,9 @@ define([ isTemplate: Cryptpad.isTemplate(window.location.href), feedbackAllowed: Cryptpad.isFeedbackAllowed(), friends: proxy.friends || {}, - settings: proxy.settings || {} + settings: proxy.settings || {}, + isPresent: parsed.hashData && parsed.hashData.present, + isEmbed: parsed.hashData && parsed.hashData.embed, } }); }); @@ -290,6 +292,13 @@ define([ readOnly: readOnly, crypto: Crypto.createEncryptor(secret.keys), onConnect: function (wc) { + if (window.location.hash && window.location.hash !== '#') { + window.location = parsed.getUrl({ + present: parsed.hashData.present, + embed: parsed.hashData.embed + }); + return; + } if (readOnly) { return; } Cryptpad.replaceHash(Cryptpad.getEditHashFromKeys(wc.id, secret.keys)); } diff --git a/www/common/toolbar3.js b/www/common/toolbar3.js index 4e07d25d6..7c8d4dd1c 100644 --- a/www/common/toolbar3.js +++ b/www/common/toolbar3.js @@ -50,6 +50,12 @@ define([ var createRealtimeToolbar = function (config) { if (!config.$container) { return; } var $container = config.$container; + + var isEmbed = Bar.isEmbed = config.metadataMgr.getPrivateData().isEmbed; + if (isEmbed) { + $container.hide(); + } + var $toolbar = $('
', { 'class': TOOLBAR_CLS, id: uid(), @@ -304,6 +310,7 @@ define([ }); }; var show = function () { + if (Bar.isEmbed) { $content.hide(); return; } $content.show(); if (mobile) { $ck.hide(); @@ -440,7 +447,7 @@ define([ }; var createFileShare = function (toolbar) { - throw new Error('TODO: Update createFileShare to add "embed" and work in secure iframes'); + if (true) { throw new Error('TODO: Update createFileShare to add "embed" and work in secure iframes'); } if (!window.location.hash) { throw new Error("Unable to display the share button: hash required in the URL"); } diff --git a/www/slide/slide.js b/www/slide/slide.js index 5d1af0ab0..98932cc0d 100644 --- a/www/slide/slide.js +++ b/www/slide/slide.js @@ -1,7 +1,8 @@ define([ 'jquery', '/common/diffMarked.js', -],function ($, DiffMd) { + '/common/cryptpad-common.js.js', +],function ($, DiffMd, Cryptpad) { var Slide = { index: 0, @@ -116,13 +117,13 @@ define([ }; var isPresentURL = Slide.isPresentURL = function () { - var hash = window.location.hash; - // Present mode has /present at the end of the hash - var urlLastFragment = hash.slice(hash.lastIndexOf('/')+1); - return urlLastFragment === "present"; + var parsed = Cryptpad.parsePadUrl(window.location.href); + return parsed && parsed.hashData && parsed.hashData.present; }; var show = Slide.show = function (bool, content) { + var parsed = Cryptpad.parsePadUrl(window.location.href); + var hashData = parsed.hashData || {}; Slide.shown = bool; if (bool) { Slide.update(content); @@ -131,10 +132,7 @@ define([ $(ifrw).focus(); change(null, Slide.index); if (!isPresentURL()) { - if (window.location.href.slice(-1) !== '/') { - window.location.hash += '/'; - } - window.location.hash += 'present'; + window.location += parsed.getUrl({present: true, embed: hashData.embed}); } $pad.contents().find('.cryptpad-present-button').hide(); $pad.contents().find('.cryptpad-source-button').show(); @@ -144,7 +142,7 @@ define([ updateFontSize(); return; } - window.location.hash = window.location.hash.replace(/\/present$/, '/'); + window.location = parsed.getUrl({embed: hashData.embed}); change(Slide.index, null); $pad.contents().find('.cryptpad-present-button').show(); $pad.contents().find('.cryptpad-source-button').hide(); From 3ca9f41290d27b616af8e3878f488ac441b180cb Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 6 Sep 2017 10:56:27 +0200 Subject: [PATCH 2/9] Get embed code for pad and code --- customize.dist/translations/messages.fr.js | 2 +- customize.dist/translations/messages.js | 4 ++- www/common/sframe-channel.js | 4 +-- www/common/sframe-common-interface.js | 10 +++--- www/common/sframe-common.js | 2 +- www/common/toolbar2.js | 4 +-- www/common/toolbar3.js | 36 +++++++++++++++++++++- 7 files changed, 49 insertions(+), 13 deletions(-) diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index e118f8cf9..95a882288 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -172,7 +172,7 @@ define(function () { out.viewOpen = "Voir dans un nouvel onglet"; out.viewOpenTitle = "Ouvrir le lien en lecture seule dans un nouvel onglet"; out.fileShare = "Copier le lien"; - out.fileEmbed = "Obtenir le code d'intégration"; + out.getEmbedCode = "Obtenir le code d'intégration"; out.fileEmbedTitle = "Intégrer le fichier dans une page web"; out.fileEmbedScript = "Pour intégrer un fichier, veuillez inclure le script suivant une fois dans votre page afin de pouvoir charger le Media Tag :"; out.fileEmbedTag = "Ensuite vous pouvez placer ce Media Tag où vous souhaitez dans votre page pour l'intégrer :"; diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 3905b7601..51ba6ae4a 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -174,7 +174,9 @@ define(function () { out.viewOpen = "Open read-only link in a new tab"; out.viewOpenTitle = "Open this pad in read-only mode in a new tab"; out.fileShare = "Copy link"; - out.fileEmbed = "Get embed code"; + out.getEmbedCode = "Get embed code"; + out.viewEmbedTitle = ""; + out.viewEmbedTag = ""; out.fileEmbedTitle = "Embed the file in an external page"; out.fileEmbedScript = "To embed this file, include this script once in your page to load the Media Tag:"; out.fileEmbedTag = "Then place this Media Tag wherever in your page you would like to embed:"; diff --git a/www/common/sframe-channel.js b/www/common/sframe-channel.js index fc9bcd0dd..c4aed597b 100644 --- a/www/common/sframe-channel.js +++ b/www/common/sframe-channel.js @@ -7,7 +7,7 @@ define([ return Math.random().toString(16).replace('0.', '') + Math.random().toString(16).replace('0.', ''); }; - var create = function (ow, cb) { + var create = function (ow, cb, isSandbox) { var otherWindow; var handlers = {}; var queries = {}; @@ -131,7 +131,7 @@ define([ console.log(msg); } }); - if (window !== window.top) { + if (isSandbox) { // we're in the sandbox otherWindow = ow; cb(chan); diff --git a/www/common/sframe-common-interface.js b/www/common/sframe-common-interface.js index 459991e1c..c6dff14f6 100644 --- a/www/common/sframe-common-interface.js +++ b/www/common/sframe-common-interface.js @@ -230,31 +230,31 @@ define([ $userAdmin.find('a.logout').click(function () { Common.logout(function () { - window.top.location = origin+'/'; + window.parent.location = origin+'/'; }); }); $userAdmin.find('a.settings').click(function () { if (padType) { window.open(origin+'/settings/'); } else { - window.top.location = origin+'/settings/'; + window.parent.location = origin+'/settings/'; } }); $userAdmin.find('a.profile').click(function () { if (padType) { window.open(origin+'/profile/'); } else { - window.top.location = origin+'/profile/'; + window.parent.location = origin+'/profile/'; } }); $userAdmin.find('a.login').click(function () { Common.setLoginRedirect(function () { - window.top.location = origin+'/login/'; + window.parent.location = origin+'/login/'; }); }); $userAdmin.find('a.register').click(function () { Common.setLoginRedirect(function () { - window.top.location = origin+'/register/'; + window.parent.location = origin+'/register/'; }); }); diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index 484c48681..36dd5e6ca 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -357,7 +357,7 @@ define([ Object.freeze(funcs); return { create: function (cb) { nThen(function (waitFor) { - SFrameChannel.create(window.top, waitFor(function (sfc) { ctx.sframeChan = sfc; })); + SFrameChannel.create(window.parent, waitFor(function (sfc) { ctx.sframeChan = sfc; }), true); // CpNfInner.start() should be here.... }).nThen(function () { ctx.metadataMgr = MetadataMgr.create(ctx.sframeChan); diff --git a/www/common/toolbar2.js b/www/common/toolbar2.js index dd2b8c4b2..6909d8c0d 100644 --- a/www/common/toolbar2.js +++ b/www/common/toolbar2.js @@ -491,8 +491,8 @@ define([ }); options.push({ tag: 'a', - attributes: {title: Messages.editShareTitle, 'class': 'fileEmbed'}, - content: ' ' + Messages.fileEmbed + attributes: {title: Messages.fileEmbedTitle, 'class': 'fileEmbed'}, + content: ' ' + Messages.getEmbedCode }); var dropdownConfigShare = { text: $('
').append($shareIcon).html(), diff --git a/www/common/toolbar3.js b/www/common/toolbar3.js index 7c8d4dd1c..436a3e94d 100644 --- a/www/common/toolbar3.js +++ b/www/common/toolbar3.js @@ -408,6 +408,15 @@ define([ content: ' ' + Messages.viewOpen }); } + options.push({tag: 'hr'}); + options.push({ + tag: 'a', + attributes: { + title: Messages.viewEmbedTitle, + 'class': 'cp-toolbar-share-view-embed', + }, + content: ' ' + Messages.getEmbedCode + }); } var dropdownConfigShare = { text: $('
').append($shareIcon).html(), @@ -438,6 +447,31 @@ define([ var success = Cryptpad.Clipboard.copy(url); if (success) { Cryptpad.log(Messages.shareSuccess); } }); + $shareBlock.find('a.cp-toolbar-share-view-embed').click(function () { + var url = origin + pathname + '#' + hashes.viewHash; + var parsed = Cryptpad.parsePadUrl(url); + url = origin + parsed.getUrl({embed: true}); + // Alertify content + var $content = $('
'); + $('', {'style':'display:none;'}).appendTo($content); + $('

').text(Messages.viewEmbedTitle).appendTo($content); + var $tag = $('

').text(Messages.fileEmbedTag).appendTo($content); + $('
').appendTo($tag); + var iframeId = uid(); + var iframeEmbed = ''; + $('', { + type: 'text', + id: iframeId, + readonly: 'readonly', + value: iframeEmbed, + }).appendTo($tag); + Cryptpad.alert($content.html(), null, true); + $('#'+iframeId).click(function () { + this.select(); + }); + //var success = Cryptpad.Clipboard.copy(url); + //if (success) { Cryptpad.log(Messages.shareSuccess); } + }); } toolbar.$leftside.append($shareBlock); @@ -611,7 +645,7 @@ define([ window.open(href); return; } - window.top.location = href; + window.parent.location = href; }; var onContext = function (e) { e.stopPropagation(); }; From d98bbf7df9ebb47b640f570ac056292bac89984c Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 6 Sep 2017 11:03:20 +0200 Subject: [PATCH 3/9] Fix the pad app when cryptpad is in an iframe --- www/common/sframe-channel.js | 4 ++-- www/common/sframe-common-interface.js | 10 +++++----- www/common/sframe-common.js | 2 +- www/common/toolbar3.js | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/www/common/sframe-channel.js b/www/common/sframe-channel.js index 6bfffb028..5d363390f 100644 --- a/www/common/sframe-channel.js +++ b/www/common/sframe-channel.js @@ -7,7 +7,7 @@ define([ return Math.random().toString(16).replace('0.', '') + Math.random().toString(16).replace('0.', ''); }; - var create = function (ow, cb) { + var create = function (ow, cb, isSandbox) { var otherWindow; var handlers = {}; var queries = {}; @@ -130,7 +130,7 @@ define([ console.log(msg); } }); - if (window !== window.top) { + if (isSandbox) { // we're in the sandbox otherWindow = ow; cb(chan); diff --git a/www/common/sframe-common-interface.js b/www/common/sframe-common-interface.js index f0f3a7da0..f812e3eec 100644 --- a/www/common/sframe-common-interface.js +++ b/www/common/sframe-common-interface.js @@ -230,31 +230,31 @@ define([ $userAdmin.find('a.logout').click(function () { Common.logout(function () { - window.top.location = origin+'/'; + window.parent.location = origin+'/'; }); }); $userAdmin.find('a.settings').click(function () { if (padType) { window.open(origin+'/settings/'); } else { - window.top.location = origin+'/settings/'; + window.parent.location = origin+'/settings/'; } }); $userAdmin.find('a.profile').click(function () { if (padType) { window.open(origin+'/profile/'); } else { - window.top.location = origin+'/profile/'; + window.parent.location = origin+'/profile/'; } }); $userAdmin.find('a.login').click(function () { Common.setLoginRedirect(function () { - window.top.location = origin+'/login/'; + window.parent.location = origin+'/login/'; }); }); $userAdmin.find('a.register').click(function () { Common.setLoginRedirect(function () { - window.top.location = origin+'/register/'; + window.parent.location = origin+'/register/'; }); }); diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index f75720d7f..bf42642a2 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -298,7 +298,7 @@ define([ Object.freeze(funcs); return { create: function (cb) { nThen(function (waitFor) { - SFrameChannel.create(window.top, waitFor(function (sfc) { ctx.sframeChan = sfc; })); + SFrameChannel.create(window.parent, waitFor(function (sfc) { ctx.sframeChan = sfc; }), true); // CpNfInner.start() should be here.... }).nThen(function () { ctx.metadataMgr = MetadataMgr.create(ctx.sframeChan); diff --git a/www/common/toolbar3.js b/www/common/toolbar3.js index fbd1dd1e0..36d607c8c 100644 --- a/www/common/toolbar3.js +++ b/www/common/toolbar3.js @@ -611,7 +611,7 @@ define([ window.open(href); return; } - window.top.location = href; + window.parent.location = href; }; var onContext = function (e) { e.stopPropagation(); }; From 8f2776657b1b8c1160532010a72034c24fa8ee53 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 6 Sep 2017 11:21:53 +0200 Subject: [PATCH 4/9] Add translations for pad embed --- customize.dist/translations/messages.fr.js | 3 +++ customize.dist/translations/messages.js | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index 95a882288..c337846f2 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -173,6 +173,9 @@ define(function () { out.viewOpenTitle = "Ouvrir le lien en lecture seule dans un nouvel onglet"; out.fileShare = "Copier le lien"; out.getEmbedCode = "Obtenir le code d'intégration"; + out.viewEmbedTitle = "Intégrer le pad dans une page web"; + out.viewEmbedTag = "Pour intégrer ce pad, veuillez inclure l'iframe suivant dans votre page là om vous souhaitez l'afficher. Vous pouvez changer sa taille en utilisant du code CSS ou des attributs HTML." + To embed this pad, include this iframe in your page wherever you want. You can style it using CSS or HTML attributes."; out.fileEmbedTitle = "Intégrer le fichier dans une page web"; out.fileEmbedScript = "Pour intégrer un fichier, veuillez inclure le script suivant une fois dans votre page afin de pouvoir charger le Media Tag :"; out.fileEmbedTag = "Ensuite vous pouvez placer ce Media Tag où vous souhaitez dans votre page pour l'intégrer :"; diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 51ba6ae4a..cdc13df2b 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -175,8 +175,8 @@ define(function () { out.viewOpenTitle = "Open this pad in read-only mode in a new tab"; out.fileShare = "Copy link"; out.getEmbedCode = "Get embed code"; - out.viewEmbedTitle = ""; - out.viewEmbedTag = ""; + out.viewEmbedTitle = "Embed the pad in an external page"; + out.viewEmbedTag = "To embed this pad, include this iframe in your page wherever you want. You can style it using CSS or HTML attributes."; out.fileEmbedTitle = "Embed the file in an external page"; out.fileEmbedScript = "To embed this file, include this script once in your page to load the Media Tag:"; out.fileEmbedTag = "Then place this Media Tag wherever in your page you would like to embed:"; From 8b2733e2da605ce97149095a49a39ec3551fb072 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 6 Sep 2017 11:37:19 +0200 Subject: [PATCH 5/9] Fix typo --- www/slide/slide.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/slide/slide.js b/www/slide/slide.js index 98932cc0d..0d0cf003e 100644 --- a/www/slide/slide.js +++ b/www/slide/slide.js @@ -1,7 +1,7 @@ define([ 'jquery', '/common/diffMarked.js', - '/common/cryptpad-common.js.js', + '/common/cryptpad-common.js', ],function ($, DiffMd, Cryptpad) { var Slide = { From 61b228db794ae56e9ebdacfacf46dc1a572ead4f Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 6 Sep 2017 11:41:09 +0200 Subject: [PATCH 6/9] Fix double / when storing a file --- www/common/common-hash.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/common-hash.js b/www/common/common-hash.js index ead686664..2aa2155bf 100644 --- a/www/common/common-hash.js +++ b/www/common/common-hash.js @@ -123,7 +123,7 @@ Version 1 if (!ret.type) { return url; } url += ret.type + '/'; if (!ret.hashData) { return url; } - if (ret.hashData.type !== 'pad') { return url + '/#' + ret.hash; } + if (ret.hashData.type !== 'pad') { return url + '#' + ret.hash; } if (ret.hashData.version !== 1) { throw new Error("Only v1 hashes are managed here."); } url += '#/' + ret.hashData.version + '/' + ret.hashData.mode + From fe8b2c2556ff7fac6f4696a8706f384436d4e4ae Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 6 Sep 2017 15:43:30 +0200 Subject: [PATCH 7/9] Fix french translation --- customize.dist/translations/messages.fr.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index c337846f2..35beb1f02 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -174,8 +174,7 @@ define(function () { out.fileShare = "Copier le lien"; out.getEmbedCode = "Obtenir le code d'intégration"; out.viewEmbedTitle = "Intégrer le pad dans une page web"; - out.viewEmbedTag = "Pour intégrer ce pad, veuillez inclure l'iframe suivant dans votre page là om vous souhaitez l'afficher. Vous pouvez changer sa taille en utilisant du code CSS ou des attributs HTML." - To embed this pad, include this iframe in your page wherever you want. You can style it using CSS or HTML attributes."; + out.viewEmbedTag = "Pour intégrer ce pad, veuillez inclure l'iframe suivant dans votre page là om vous souhaitez l'afficher. Vous pouvez changer sa taille en utilisant du code CSS ou des attributs HTML."; out.fileEmbedTitle = "Intégrer le fichier dans une page web"; out.fileEmbedScript = "Pour intégrer un fichier, veuillez inclure le script suivant une fois dans votre page afin de pouvoir charger le Media Tag :"; out.fileEmbedTag = "Ensuite vous pouvez placer ce Media Tag où vous souhaitez dans votre page pour l'intégrer :"; From 04a04aef2b6e1f36f2a0e757768487858fb393ff Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 6 Sep 2017 16:05:20 +0200 Subject: [PATCH 8/9] Add setAttribute/getAttribute in secure iframes. Store attributes in settings --- www/code/inner.js | 3 ++- www/common/cryptpad-common.js | 36 ++++++++++++++++++++------ www/common/fsStore.js | 42 +++++++++++++++++++++++++++++-- www/common/migrate-user-object.js | 32 +++++++++++++++++++++++ www/common/sframe-common-outer.js | 16 +++++++++++- www/common/sframe-common-title.js | 41 ++++++++++-------------------- www/common/sframe-common.js | 34 +++++++++++++------------ www/common/sframe-protocol.js | 4 ++- www/common/toolbar2.js | 8 +++--- www/common/toolbar3.js | 19 +++++--------- www/common/userObject.js | 4 +-- www/drive/main.js | 2 +- www/pad/inner.js | 2 +- www/poll/main.js | 6 ++--- www/profile/main.js | 27 -------------------- 15 files changed, 168 insertions(+), 108 deletions(-) diff --git a/www/code/inner.js b/www/code/inner.js index c84765108..cd440d6bb 100644 --- a/www/code/inner.js +++ b/www/code/inner.js @@ -112,6 +112,7 @@ define([ var updateIndentSettings = function () { if (!metadataMgr) { return; } var data = metadataMgr.getPrivateData().settings; + data = data.codemirror || {}; var indentUnit = data[indentKey]; var useTabs = data[useTabsKey]; setIndentation( @@ -255,7 +256,7 @@ define([ readOnly = metadataMgr.getPrivateData().readOnly; var titleCfg = { getHeadingText: CodeMirror.getHeadingText }; - Title = common.createTitle(titleCfg, config.onLocal, common, metadataMgr); + Title = common.createTitle(titleCfg, config.onLocal, common); var configTb = { displayed: ['title', 'useradmin', 'spinner', 'share', 'userlist', 'newpad', 'limit'], diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 0361332d5..d90f586ea 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -194,11 +194,14 @@ define([ return store.getProfile().avatar; } }; - common.getDisplayName = function () { + common.getDisplayName = function (cb) { + var name; if (getProxy()) { - return getProxy()[common.displayNameKey] || ''; + name = getProxy()[common.displayNameKey]; } - return ''; + name = name || ''; + if (typeof cb === "function") { cb(null, name); } + return name; }; common.getAccountName = function () { return localStorage[common.userNameKey]; @@ -479,11 +482,22 @@ define([ var href = getRelativeHref(window.location.href); getStore().setPadAttribute(href, attr, value, cb); }; + common.setDisplayName = function (value, cb) { + if (getProxy()) { + getProxy()[common.displayNameKey] = value; + } + if (typeof cb === "function") { cb(); } + }; common.setAttribute = function (attr, value, cb) { - getStore().set(["cryptpad", attr].join('.'), value, function (err, data) { + getStore().setAttribute(attr, value, function (err, data) { if (cb) { cb(err, data); } }); }; + /*common.setAttribute = function (attr, value, cb) { + getStore().set(["cryptpad", attr].join('.'), value, function (err, data) { + if (cb) { cb(err, data); } + }); + };*/ common.setLSAttribute = function (attr, value) { localStorage[attr] = value; }; @@ -494,10 +508,15 @@ define([ getStore().getPadAttribute(href, attr, cb); }; common.getAttribute = function (attr, cb) { - getStore().get(["cryptpad", attr].join('.'), function (err, data) { + getStore().getAttribute(attr, function (err, data) { cb(err, data); }); }; + /*common.getAttribute = function (attr, cb) { + getStore().get(["cryptpad", attr].join('.'), function (err, data) { + cb(err, data); + }); + };*/ /* this returns a reference to your proxy. changing it will change your drive. */ @@ -661,11 +680,12 @@ define([ }; // STORAGE: Display Name - common.getLastName = function (cb) { - common.getAttribute('username', function (err, userName) { + common.getLastName = common.getDisplayName; + /* function (cb) { + common.getDisplayName(function (err, userName) { cb(err, userName); }); - }; + };*/ var _onDisplayNameChanged = []; common.onDisplayNameChanged = function (h) { if (typeof(h) !== "function") { return; } diff --git a/www/common/fsStore.js b/www/common/fsStore.js index 50aef3573..5a8e0becb 100644 --- a/www/common/fsStore.js +++ b/www/common/fsStore.js @@ -61,8 +61,46 @@ define([ cb(void 0, res); }; - ret.setPadAttribute = filesOp.setAttribute; - ret.getPadAttribute = filesOp.getAttribute; + var getAttributeObject = function (attr) { + if (typeof attr === "string") { + console.error('DEPRECATED: use setAttribute with an array, not a string'); + return { + obj: storeObj.settings, + key: attr + }; + } + if (!Array.isArray(attr)) { throw new Error("Attribute must be string or array"); } + if (attr.length === 0) { throw new Error("Attribute can't be empty"); } + var obj = storeObj.settings; + attr.forEach(function (el, i) { + if (i === attr.length-1) { return; } + if (!obj[el]) { + obj[el] = {}; + } + else if (typeof obj[el] !== "object") { throw new Error("Wrong attribute"); } + obj = obj[el]; + }); + return { + obj: obj, + key: attr[attr.length-1] + }; + }; + ret.setAttribute = function (attr, value, cb) { + try { + var object = getAttributeObject(attr); + object.obj[object.key] = value; + } catch (e) { return void cb(e); } + cb(); + }; + ret.getAttribute = function (attr, cb) { + var object; + try { + object = getAttributeObject(attr); + } catch (e) { return void cb(e); } + cb(null, object.obj[object.key]); + }; + ret.setPadAttribute = filesOp.setPadAttribute; + ret.getPadAttribute = filesOp.getPadAttribute; ret.getIdFromHref = filesOp.getIdFromHref; ret.getDrive = function (key, cb) { diff --git a/www/common/migrate-user-object.js b/www/common/migrate-user-object.js index 400c6489e..dbf7b5727 100644 --- a/www/common/migrate-user-object.js +++ b/www/common/migrate-user-object.js @@ -64,5 +64,37 @@ define([], function () { Cryptpad.feedback('Migrate-2', true); userObject.version = version = 2; } + + + // Migration 3: global attributes from root to 'settings' subobjects + var migrateAttributes = function () { + var drawer = 'cryptpad.userlist-drawer'; + var polls = 'cryptpad.hide_poll_text'; + var indentKey = 'indentUnit'; + var useTabsKey = 'indentWithTabs'; + var settings = userObject.settings = userObject.settings || {}; + if (settings[indentKey] || settings[useTabsKey]) { + settings.codemirror = settings.codemirror || {}; + settings.codemirror.indentUnit = settings[indentKey]; + settings.codemirror.indentWithTabs = settings[useTabsKey]; + delete settings[indentKey]; + delete settings[useTabsKey]; + } + if (userObject[drawer]) { + settings.toolbar = settings.toolbar || {}; + settings.toolbar['userlist-drawer'] = userObject[drawer]; + delete userObject[drawer]; + } + if (userObject[polls]) { + settings.poll = settings.poll || {}; + settings.poll['hide-text'] = userObject[polls]; + delete userObject[polls]; + } + }; + if (version < 3) { + migrateAttributes(); + Cryptpad.feedback('Migrate-3', true); + userObject.version = version = 3; + } }; }); diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 189bab6e2..df4259dff 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -115,7 +115,7 @@ define([ }); sframeChan.on('Q_SETTINGS_SET_DISPLAY_NAME', function (newName, cb) { - Cryptpad.setAttribute('username', newName, function (err) { + Cryptpad.setDisplayName(newName, function (err) { if (err) { console.log("Couldn't set username"); console.error(err); @@ -220,6 +220,20 @@ define([ }); }); + sframeChan.on('Q_GET_ATTRIBUTE', function (data, cb) { + Cryptpad.getAttribute(data.key, function (e, data) { + cb({ + error: e, + data: data + }); + }); + }); + sframeChan.on('Q_SET_ATTRIBUTE', function (data, cb) { + Cryptpad.setAttribute(data.key, data.value, function (e) { + cb({error:e}); + }); + }); + var onFileUpload = function (sframeChan, data, cb) { var sendEvent = function (data) { diff --git a/www/common/sframe-common-title.js b/www/common/sframe-common-title.js index 6030286f5..ff2331e1e 100644 --- a/www/common/sframe-common-title.js +++ b/www/common/sframe-common-title.js @@ -3,32 +3,24 @@ define(['jquery'], function ($) { module.create = function (cfg, onLocal, Common, metadataMgr) { var exp = {}; + var metadataMgr = Common.getMetadataMgr(); + var sframeChan = Common.getSframeChannel(); + var titleUpdated; - exp.defaultTitle = Common.getDefaultTitle(); - + exp.defaultTitle = metadataMgr.getMetadata().defaultTitle; exp.title = document.title; cfg = cfg || {}; var getHeadingText = cfg.getHeadingText || function () { return; }; -/* var updateLocalTitle = function (newTitle) { - console.error(newTitle); - exp.title = newTitle; - onLocal(); - if (typeof cfg.updateLocalTitle === "function") { - cfg.updateLocalTitle(newTitle); - } else { - document.title = newTitle; - } - };*/ - var $title; exp.setToolbar = function (toolbar) { $title = toolbar && toolbar.title; }; exp.getTitle = function () { return exp.title; }; + var isDefaultTitle = exp.isDefaultTitle = function (){return exp.title === exp.defaultTitle;}; var suggestTitle = exp.suggestTitle = function (fallback) { @@ -40,32 +32,25 @@ define(['jquery'], function ($) { } }; - /*var renameCb = function (err, newTitle) { - if (err) { return; } - onLocal(); - //updateLocalTitle(newTitle); - };*/ - // update title: href is optional; if not specified, we use window.location.href exp.updateTitle = function (newTitle, cb) { cb = cb || $.noop; if (newTitle === exp.title) { return; } - Common.updateTitle(newTitle, cb); + metadataMgr.updateTitle(newTitle); + titleUpdated = cb; }; - // TODO not needed? - /*exp.updateDefaultTitle = function (newDefaultTitle) { - exp.defaultTitle = newDefaultTitle; - if (!$title) { return; } - $title.find('input').attr("placeholder", exp.defaultTitle); - };*/ - metadataMgr.onChange(function () { var md = metadataMgr.getMetadata(); $title.find('span.cp-toolbar-title-value').text(md.title || md.defaultTitle); $title.find('input').val(md.title || md.defaultTitle); exp.title = md.title; - //exp.updateTitle(md.title || md.defaultTitle); + }); + metadataMgr.onTitleChange(function (title) { + sframeChan.query('Q_SET_PAD_TITLE_IN_DRIVE', title, function (err) { + if (err) { return; } + if (titleUpdated) { titleUpdated(undefined, title); } + }); }); exp.getTitleConfig = function () { diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index 36dd5e6ca..9ee452e2c 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -46,12 +46,6 @@ define([ return ctx.cpNfInner.metadataMgr.getPrivateData().accountName; }; - var titleUpdated; - funcs.updateTitle = function (title, cb) { - ctx.metadataMgr.updateTitle(title); - titleUpdated = cb; - }; - // UI funcs.createUserAdminMenu = UI.createUserAdminMenu; funcs.displayAvatar = UI.displayAvatar; @@ -65,10 +59,7 @@ define([ // Title module funcs.createTitle = Title.create; - funcs.getDefaultTitle = function () { - if (!ctx.cpNfInner) { throw new Error("cpNfInner is not ready!"); } - return ctx.cpNfInner.metadataMgr.getMetadata().defaultTitle; - }; + // Misc funcs.setDisplayName = function (name, cb) { ctx.sframeChan.query('Q_SETTINGS_SET_DISPLAY_NAME', name, function (err) { @@ -76,6 +67,7 @@ define([ }); }; + // Window funcs.logout = function (cb) { ctx.sframeChan.query('Q_LOGOUT', null, function (err) { if (cb) { cb(err); } @@ -92,6 +84,7 @@ define([ }); }; + // Store funcs.sendAnonRpcMsg = function (msg, content, cb) { ctx.sframeChan.query('Q_ANON_RPC_MESSAGE', { msg: msg, @@ -128,6 +121,21 @@ define([ }, cb); }; + funcs.getAttribute = function (key, cb) { + ctx.sframeChan.query('Q_GET_ATTRIBUTE', { + key: key + }, function (err, res) { + cb (err || res.error, res.data); + }); + }; + funcs.setAttribute = function (key, value, cb) { + cb = cb || $.noop; + ctx.sframeChan.query('Q_SET_ATTRIBUTE', { + key: key, + value: value + }, cb); + }; + // Files funcs.uploadFile = function (data, cb) { ctx.sframeChan.query('Q_UPLOAD_FILE', data, cb); @@ -361,12 +369,6 @@ define([ // CpNfInner.start() should be here.... }).nThen(function () { ctx.metadataMgr = MetadataMgr.create(ctx.sframeChan); - ctx.metadataMgr.onTitleChange(function (title) { - ctx.sframeChan.query('Q_SET_PAD_TITLE_IN_DRIVE', title, function (err) { - if (err) { return; } - if (titleUpdated) { titleUpdated(undefined, title); } - }); - }); ctx.sframeChan.on('EV_RT_CONNECT', function () { CommonRealtime.setConnectionState(true); }); ctx.sframeChan.on('EV_RT_DISCONNECT', function () { CommonRealtime.setConnectionState(false); }); diff --git a/www/common/sframe-protocol.js b/www/common/sframe-protocol.js index 07e6b0126..9c79b1495 100644 --- a/www/common/sframe-protocol.js +++ b/www/common/sframe-protocol.js @@ -85,7 +85,9 @@ define({ // Send the new settings to the inner iframe when they are changed in the proxy 'EV_SETTINGS_UPDATE': true, - // Get and set pad attributes stored in the drive from the inner iframe + // Get and set (pad) attributes stored in the drive from the inner iframe + 'Q_GET_ATTRIBUTE': true, + 'Q_SET_ATTRIBUTE': true, 'Q_GET_PAD_ATTRIBUTE': true, 'Q_SET_PAD_ATTRIBUTE': true, diff --git a/www/common/toolbar2.js b/www/common/toolbar2.js index 6909d8c0d..e49a490ab 100644 --- a/www/common/toolbar2.js +++ b/www/common/toolbar2.js @@ -351,7 +351,7 @@ define([ $content.css('margin-top', h+'px'); }); $closeIcon.click(function () { - Cryptpad.setAttribute('userlist-drawer', false); + Cryptpad.setAttribute(['toolbar', 'userlist-drawer'], false); hide(); }); $button.click(function () { @@ -359,11 +359,11 @@ define([ if (visible) { hide(); } else { show(); } visible = !visible; - Cryptpad.setAttribute('userlist-drawer', visible); + Cryptpad.setAttribute(['toolbar', 'userlist-drawer'], visible); Cryptpad.feedback(visible?'USERLIST_SHOW': 'USERLIST_HIDE'); }); - Cryptpad.getAttribute('userlist-drawer', function (err, val) { + Cryptpad.getAttribute(['toolbar', 'userlist-drawer'], function (err, val) { if (val === false || mobile) { return void hide(); } show(); }); @@ -840,7 +840,7 @@ define([ if (newName === null && typeof(lastName) === "string") { return; } if (newName === null) { newName = ''; } else { Cryptpad.feedback('NAME_CHANGED'); } - Cryptpad.setAttribute('username', newName, function (err) { + Cryptpad.setDisplayName(newName, function (err) { if (err) { console.log("Couldn't set username"); console.error(err); diff --git a/www/common/toolbar3.js b/www/common/toolbar3.js index 436a3e94d..8e07aec32 100644 --- a/www/common/toolbar3.js +++ b/www/common/toolbar3.js @@ -256,17 +256,12 @@ define([ }; var initUserList = function (toolbar, config) { - // TODO clean comments - if (config.metadataMgr) { /* && config.userList.list && config.userList.userNetfluxId) {*/ - //var userList = config.userList.list; - //userList.change.push + if (config.metadataMgr) { var metadataMgr = config.metadataMgr; metadataMgr.onChange(function () { if (metadataMgr.isConnected()) {toolbar.connected = true;} if (!toolbar.connected) { return; } - //if (config.userList.data) { - updateUserList(toolbar, config); - //} + updateUserList(toolbar, config); }); } }; @@ -333,7 +328,7 @@ define([ $content.css('margin-top', h+'px'); }); $closeIcon.click(function () { - //Cryptpad.setAttribute('userlist-drawer', false); TODO iframe + Common.setAttribute(['toolbar', 'userlist-drawer'], false); hide(); }); $button.click(function () { @@ -341,16 +336,14 @@ define([ if (visible) { hide(); } else { show(); } visible = !visible; - // TODO iframe - //Cryptpad.setAttribute('userlist-drawer', visible); + Common.setAttribute(['toolbar', 'userlist-drawer'], visible); Common.feedback(visible?'USERLIST_SHOW': 'USERLIST_HIDE'); }); show(); - // TODO iframe - /*Cryptpad.getAttribute('userlist-drawer', function (err, val) { + Common.getAttribute(['toolbar', 'userlist-drawer'], function (err, val) { if (val === false || mobile) { return void hide(); } show(); - });*/ + }); return $container; }; diff --git a/www/common/userObject.js b/www/common/userObject.js index 87dbfa91b..504addb15 100644 --- a/www/common/userObject.js +++ b/www/common/userObject.js @@ -142,14 +142,14 @@ define([ if (type === 'name') { return data.filename; } return data.filename || data.title || NEW_FILE_NAME; }; - exp.getAttribute = function (href, attr, cb) { + exp.getPadAttribute = function (href, attr, cb) { cb = cb || $.noop; var id = exp.getIdFromHref(href); if (!id) { return void cb(null, undefined); } var data = getFileData(id); cb(null, clone(data[attr])); }; - exp.setAttribute = function (href, attr, value, cb) { + exp.setPadAttribute = function (href, attr, value, cb) { cb = cb || $.noop; var id = exp.getIdFromHref(href); if (!id) { return void cb("E_INVAL_HREF"); } diff --git a/www/drive/main.js b/www/drive/main.js index 1569c5bfb..b0d90b01b 100644 --- a/www/drive/main.js +++ b/www/drive/main.js @@ -2774,7 +2774,7 @@ define([ myUserNameTemp = myUserNameTemp.substr(0, 32); } var myUserName = myUserNameTemp; - Cryptpad.setAttribute('username', myUserName, function (err) { + Cryptpad.setDisplayName(myUserName, function (err) { if (err) { logError("Couldn't set username", err); return; diff --git a/www/pad/inner.js b/www/pad/inner.js index 9be24e78a..83222260f 100644 --- a/www/pad/inner.js +++ b/www/pad/inner.js @@ -514,7 +514,7 @@ define([ readOnly = metadataMgr.getPrivateData().readOnly; console.log('onInit'); var titleCfg = { getHeadingText: getHeadingText }; - Title = common.createTitle(titleCfg, realtimeOptions.onLocal, common, metadataMgr); + Title = common.createTitle(titleCfg, realtimeOptions.onLocal, common); var configTb = { displayed: ['userlist', 'title', 'useradmin', 'spinner', 'newpad', 'share', 'limit'], title: Title.getTitleConfig(), diff --git a/www/poll/main.js b/www/poll/main.js index 7455ee823..8a36ecd37 100644 --- a/www/poll/main.js +++ b/www/poll/main.js @@ -21,7 +21,7 @@ define([ $(function () { - var HIDE_INTRODUCTION_TEXT = "hide_poll_text"; + var HIDE_INTRODUCTION_TEXT = "hide-text"; var defaultName; var secret = Cryptpad.getSecrets(); @@ -782,10 +782,10 @@ var create = function (info) { .on('disconnect', disconnect) .on('reconnect', reconnect); - Cryptpad.getAttribute(HIDE_INTRODUCTION_TEXT, function (e, value) { + Cryptpad.getAttribute(['poll', HIDE_INTRODUCTION_TEXT], function (e, value) { if (e) { console.error(e); } if (!value) { - Cryptpad.setAttribute(HIDE_INTRODUCTION_TEXT, "1", function (e) { + Cryptpad.setAttribute(['poll', HIDE_INTRODUCTION_TEXT], "1", function (e) { if (e) { console.error(e); } }); showHelp(true); diff --git a/www/profile/main.js b/www/profile/main.js index 7cf938722..bd604dce6 100644 --- a/www/profile/main.js +++ b/www/profile/main.js @@ -131,33 +131,6 @@ define([ }); }; - /* - var addDisplayName = function ($container) { - var $block = $('

', {id: DISPLAYNAME_ID}).appendTo($container); - var getValue = function (cb) { - Cryptpad.getLastName(function (err, name) { - if (err) { return void console.error(err); } - cb(name); - }); - }; - if (APP.readOnly) { - var $span = $('', {'class': DISPLAYNAME_ID}).appendTo($block); - getValue(function (value) { - $span.text(value); - }); - return; - } - var setValue = function (value, cb) { - Cryptpad.setAttribute('username', value, function (err) { - cb(err); - }); - }; - var placeholder = Messages.anonymous; - var rt = Cryptpad.getStore().getProxy().info.realtime; - createEditableInput($block, DISPLAYNAME_ID, placeholder, 32, getValue, setValue, rt); - }; - */ - /* jshint ignore:start */ var isFriend = function (proxy, edKey) { var friends = Cryptpad.find(proxy, ['friends']); From 0423a5f4e2b53ff42750b407ece996e6e7d971e1 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 6 Sep 2017 18:26:10 +0200 Subject: [PATCH 9/9] Clean secure iframe code --- www/code/inner.js | 8 +- www/common/sframe-common-file.js | 5 + www/common/sframe-common-interface.js | 172 +++++++++++++++++- www/common/sframe-common-title.js | 2 +- www/common/sframe-common.js | 243 +++++--------------------- www/common/toolbar3.js | 4 +- www/pad/inner.js | 4 +- 7 files changed, 221 insertions(+), 217 deletions(-) diff --git a/www/code/inner.js b/www/code/inner.js index cd440d6bb..721e162aa 100644 --- a/www/code/inner.js +++ b/www/code/inner.js @@ -256,7 +256,7 @@ define([ readOnly = metadataMgr.getPrivateData().readOnly; var titleCfg = { getHeadingText: CodeMirror.getHeadingText }; - Title = common.createTitle(titleCfg, config.onLocal, common); + Title = common.createTitle(titleCfg, config.onLocal); var configTb = { displayed: ['title', 'useradmin', 'spinner', 'share', 'userlist', 'newpad', 'limit'], @@ -369,7 +369,7 @@ define([ } } }; - common.initFilePicker(common, fileDialogCfg); + common.initFilePicker(fileDialogCfg); APP.$mediaTagButton = $('