From 7c3d56345319186e4727baa076f05764a59b9018 Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 24 Feb 2022 15:37:05 +0530 Subject: [PATCH] WIP support for customized and translated legal info --- customize.dist/pages.js | 49 ++++++++++++---- www/checkup/main.js | 70 ++++++++++++++++++++++- www/common/application_config_internal.js | 26 +++++++++ www/common/common-ui-elements.js | 23 +++++++- 4 files changed, 155 insertions(+), 13 deletions(-) diff --git a/customize.dist/pages.js b/customize.dist/pages.js index ea52b00f8..2012fc103 100644 --- a/customize.dist/pages.js +++ b/customize.dist/pages.js @@ -102,27 +102,54 @@ define([ return h('a', attrs, text); }; - var imprintUrl = AppConfig.imprint && (typeof(AppConfig.imprint) === "boolean" ? - '/imprint.html' : AppConfig.imprint); - Pages.versionString = "v4.13.0"; + var customURLs = Pages.customURLs = {}; + (function () { + var defaultURLs = { + //imprint: '/imprint.html', // XXX cryptpad.org/default-imprint.html? + //privacy: '/privacy.html', // XXX cryptpad.org/default-privacy.html? + terms: '/terms.html', // XXX cryptpad.org/default-terms.html? + //roadmap: '/roadmap.html', // XXX cryptpad.org/default-roadmap.html? + source: 'https://github.com/xwiki-labs/cryptpad', + }; + var l = Msg._getLanguage(); + ['imprint', 'privacy', 'terms', 'roadmap', 'source'].forEach(function (k) { + var value = AppConfig[k]; + if (value === false) { return; } + if (value === true) { + customURLs[k] = defaultURLs[k]; + return; + } + + if (!value) { return; } + if (typeof(value) === 'string') { + customURLs[k] = value; + return; + } + if (typeof(value) === 'object') { + customURLs[k] = value[l] || value['default']; + } + }); + }()); + + Msg.footer_source = 'Source code'; // XXX // used for the about menu - Pages.imprintLink = AppConfig.imprint ? footLink(imprintUrl, 'imprint') : undefined; - Pages.privacyLink = footLink(AppConfig.privacy, 'privacy'); - Pages.githubLink = footLink('https://github.com/xwiki-labs/cryptpad', null, 'GitHub'); + Pages.imprintLink = footLink(customURLs.imprint, 'imprint'); + Pages.privacyLink = footLink(customURLs.privacy, 'privacy'); + Pages.termsLink = footLink(customURLs.terms, 'footer_tos'); + Pages.sourceLink = footLink(customURLs.source, 'footer_source'); Pages.docsLink = footLink('https://docs.cryptpad.fr', 'docs_link'); - Pages.roadmapLink = footLink(AppConfig.roadmap, 'footer_roadmap'); + Pages.roadmapLink = footLink(customURLs.roadmap, 'footer_roadmap'); Pages.infopageFooter = function () { - var terms = footLink('/terms.html', 'footer_tos'); // FIXME this should be configurable like the other legal pages var legalFooter; // only display the legal part of the footer if it has content - if (terms || Pages.privacyLink || Pages.imprintLink) { + if (Pages.termsLink || Pages.privacyLink || Pages.imprintLink) { legalFooter = footerCol('footer_legal', [ - terms, + Pages.termsLink, Pages.privacyLink, Pages.imprintLink, ]); @@ -145,7 +172,7 @@ define([ footLink('/what-is-cryptpad.html', 'topbar_whatIsCryptpad'), Pages.docsLink, footLink('/features.html', Pages.areSubscriptionsAllowed()? 'pricing': 'features'), // Messages.pricing, Messages.features - Pages.githubLink, + Pages.sourceLink, footLink('https://opencollective.com/cryptpad/contribute/', 'footer_donate'), ]), footerCol('footer_aboutUs', [ diff --git a/www/checkup/main.js b/www/checkup/main.js index e7d952dbb..c1c6cdf2a 100644 --- a/www/checkup/main.js +++ b/www/checkup/main.js @@ -392,7 +392,6 @@ define([ assert(function (cb, msg) { msg.innerText = "Missing HTTP headers required for .xlsx export from sheets. "; - var url = cacheBuster(sheetURL); var expect = { 'cross-origin-resource-policy': 'cross-origin', 'cross-origin-embedder-policy': 'require-corp', @@ -1114,6 +1113,75 @@ define([ }); }); + var POLICY_ADVISORY = " It's advised that you either provide one or disable registration."; + var isValidInfoURL = function (url) { + // XXX check that it's an absolute URL ???? + if (!url || typeof(url) !== 'string') { return false; } + try { + var parsed = new URL(url, ApiConfig.httpUnsafeOrigin); + // check that the URL parsed and that they haven't simply linked to + // '/' or '.' or something silly like that. + return ![ + ApiConfig.httpUnsafeOrigin, + ApiConfig.httpUnsafeOrigin + '/', + ].includes(parsed.href); + } catch (err) { + return false; + } + }; + + // XXX check if they provide terms of service + assert(function (cb, msg) { + if (ApiConfig.restrictRegistration) { return void cb(true); } + + var url = Pages.customURLs.terms; + setWarningClass(msg); + msg.appendChild(h('span', [ + 'No terms of service specified.', // XXX + POLICY_ADVISORY, + ])); + cb(isValidInfoURL(url) || url); // XXX + }); + + // XXX check if they provide legal data + assert(function (cb, msg) { + if (ApiConfig.restrictRegistration) { return void cb(true); } + + var url = Pages.customURLs.imprint; + setWarningClass(msg); + msg.appendChild(h('span', [ + 'No legal data provided.', // XXX + POLICY_ADVISORY, + ])); + cb(isValidInfoURL(url) || url); // XXX + }); + + // XXX check if they provide a privacy policy + assert(function (cb, msg) { + if (ApiConfig.restrictRegistration) { return void cb(true); } + + var url = Pages.customURLs.privacy; + setWarningClass(msg); + msg.appendChild(h('span', [ + 'No privacy policy provided.', // XXX + POLICY_ADVISORY, + ])); + cb(isValidInfoURL(url) || url); // XXX + }); + + // XXX check if they provide a link to source code + assert(function (cb, msg) { + if (ApiConfig.restrictRegistration) { return void cb(true); } + + var url = Pages.customURLs.source; + setWarningClass(msg); + msg.appendChild(h('span', [ + 'No source code link provided.', // XXX + POLICY_ADVISORY, + ])); + cb(isValidInfoURL(url) || url); // XXX + }); + var serverToken; Tools.common_xhr('/', function (xhr) { serverToken = xhr.getResponseHeader('server'); diff --git a/www/common/application_config_internal.js b/www/common/application_config_internal.js index 3360e4f15..1943cbd29 100644 --- a/www/common/application_config_internal.js +++ b/www/common/application_config_internal.js @@ -35,6 +35,9 @@ define(function() { //'doc', 'presentation' ]; + // XXX + // AppConfig.premiumTypes = ['doc', 'presentation']; + /* CryptPad is available is multiple languages, but only English and French are maintained * by the developers. The other languages may be outdated, and any missing string for a langauge * will use the english version instead. You can customize the langauges you want to be available @@ -65,6 +68,29 @@ define(function() { */ //AppConfig.roadmap = 'https://cryptpad.fr/kanban/#/2/kanban/view/PLM0C3tFWvYhd+EPzXrbT+NxB76Z5DtZhAA5W5hG9wo/'; + // XXX +/* +AppConfig.imprint, AppConfig.privacy, AppConfig.terms, AppConfig.source, and AppConfig.roadmap can each be configured in one of three manners: + +// to prevent the display of privacy policy entirely: +AppConfig.privacy = false; + +// to display the default privacy policy: +AppConfig.privacy = true; + +// to display translated versions of the privacy policy depending on +// the user's configured or inferred language +AppConfig.privacy = { + 'default': '...', // displayed if there is no exact match + 'en': '/privacy.en.html', + 'fr': '/privacy.fr.html', +}; + + +*/ + AppConfig.source = 'https://github.com/xwiki-labs/cryptpad/'; // XXX + + /* Cryptpad apps use a common API to display notifications to users * by default, notifications are hidden after 5 seconds * You can change their duration here (measured in milliseconds) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 4b39b6aa2..38fee4c29 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -1637,6 +1637,11 @@ define([ return $container; }; + Messages.info_termsFlavour = "XXX terms flavour"; // XXX + Messages.info_imprintFlavour = "XXX imprint flavour"; // XXX + Messages.info_roadmapFlavour = "XXX roadmap flavour"; // XXX + Messages.info_sourceFlavour = "XXX source flavour"; // XXX + UIElements.displayInfoMenu = function (Common, metadataMgr) { //var padType = metadataMgr.getMetadata().type; var priv = metadataMgr.getPrivateData(); @@ -1647,9 +1652,10 @@ define([ var template = function (line, link) { if (!line || !link) { return; } - var p = $('

').html(line)[0]; + var p = $('

').html(line)[0]; // XXX var sub = link.cloneNode(true); +// XXX use URL if you need to? /* This is a hack to make relative URLs point to the main domain instead of the sandbox domain. It will break if the admins have specified some less common URL formats for their customizable links, such as if they've @@ -1669,6 +1675,17 @@ define([ var faqLine = template(Messages.help_genericMore, Pages.docsLink); + // XXX terms + var termsLine = template(Messages.info_termsFlavour, Pages.termsLink); + + // XXX imprint + var imprintLine = template(Messages.info_imprintFlavour, Pages.imprintLink); + + // XXX roadmap + var roadmapLine = template(Messages.info_roadmapFlavour, Pages.roadmapLink); + + var sourceLine = template(Messages.info_sourceFlavour, Pages.sourceLink); + var content = h('div.cp-info-menu-container', [ h('div.logo-block', [ h('img', { @@ -1680,7 +1697,11 @@ define([ h('hr'), legalLine, privacyLine, + termsLine, // XXX + imprintLine, // XXX faqLine, + roadmapLine, // XXX + sourceLine, // XXX ]); $(content).find('a').attr('target', '_blank');