diff --git a/bower.json b/bower.json index 5704b3aec..a6fc85b41 100644 --- a/bower.json +++ b/bower.json @@ -29,7 +29,7 @@ "rangy": "rangy-release#~1.3.0", "json.sortify": "~2.1.0", "fabric.js": "fabric#~1.6.0", - "hyperjson": "~1.3.1", + "hyperjson": "~1.4.0", "textpatcher": "^1.3.0", "proxy-polyfill": "^0.1.5", "chainpad": "^0.3.0", diff --git a/config.js.dist b/config.js.dist index 91bf38d95..da80bb374 100644 --- a/config.js.dist +++ b/config.js.dist @@ -14,24 +14,35 @@ module.exports = { * Examples are provided below */ -/* httpHeaders: { - "Content-Security-Policy": [ - "default-src 'none'", - "style-src 'unsafe-inline' 'self'", - "script-src 'self' 'unsafe-eval' 'unsafe-inline'", - "child-src 'self' cryptpad.fr *.cryptpad.fr", - "font-src 'self'", - "connect-src 'self' wss://cryptpad.fr", - // data: is used by codemirror, (insecure remote) images are included by - // users of the wysiwyg who embed photos in their pads - "img-src data: *", - ].join('; '), - "X-XSS-Protection": "1; mode=block", "X-Content-Type-Options": "nosniff", // 'X-Frame-Options': 'SAMEORIGIN', - },*/ + }, + + contentSecurity: [ + "default-src 'none'", + "style-src 'unsafe-inline' 'self'", + "script-src 'self'", + "child-src 'self' cryptpad.fr *.cryptpad.fr", + "font-src 'self'", + "connect-src 'self' wss://cryptpad.fr", + // data: is used by codemirror + "img-src 'self' data:", + ].join('; '), + + // CKEditor requires significantly more lax content security policy in order to function. + padContentSecurity: [ + "default-src 'none'", + "style-src 'unsafe-inline' 'self'", + // Unsafe inline, unsafe-eval are needed for ckeditor :( + "script-src 'self' 'unsafe-eval' 'unsafe-inline'", + "child-src 'self' cryptpad.fr *.cryptpad.fr", + "font-src 'self'", + "connect-src 'self' wss://cryptpad.fr", + // (insecure remote) images are included by users of the wysiwyg who embed photos in their pads + "img-src *", + ].join('; '), httpPort: 3000, @@ -51,7 +62,7 @@ module.exports = { //websocketPort: 3000, /* if you want to run a different version of cryptpad but using the same websocket - * server, you should use the other server port as websocketPort and disable + * server, you should use the other server port as websocketPort and disable * the websockets on that server */ //useExternalWebsocket: false, diff --git a/customize.dist/about.html b/customize.dist/about.html index c0f3a0b97..988efafc3 100644 --- a/customize.dist/about.html +++ b/customize.dist/about.html @@ -1,5 +1,6 @@ + Cryptpad: Zero Knowledge, Collaborative Real Time Editing @@ -9,16 +10,8 @@ - + - - -
@@ -126,4 +119,3 @@ - diff --git a/customize.dist/contact.html b/customize.dist/contact.html index 7b2cd03ae..1985d8347 100644 --- a/customize.dist/contact.html +++ b/customize.dist/contact.html @@ -1,5 +1,6 @@ + Cryptpad: Zero Knowledge, Collaborative Real Time Editing @@ -9,16 +10,8 @@ - + - - -
@@ -123,4 +116,3 @@ - diff --git a/customize.dist/index.html b/customize.dist/index.html index eb1815e34..12697787e 100644 --- a/customize.dist/index.html +++ b/customize.dist/index.html @@ -1,5 +1,6 @@ + Cryptpad: Zero Knowledge, Collaborative Real Time Editing @@ -9,16 +10,8 @@ - + - - -
@@ -245,4 +238,3 @@ - diff --git a/customize.dist/privacy.html b/customize.dist/privacy.html index 10910bfff..403a0f1c4 100644 --- a/customize.dist/privacy.html +++ b/customize.dist/privacy.html @@ -1,5 +1,6 @@ + Cryptpad: Zero Knowledge, Collaborative Real Time Editing @@ -9,16 +10,8 @@ - + - - -
@@ -144,4 +137,3 @@ - diff --git a/customize.dist/src/fragments/appscript.html b/customize.dist/src/fragments/appscript.html index 66cc0acea..3f1dd7b58 100644 --- a/customize.dist/src/fragments/appscript.html +++ b/customize.dist/src/fragments/appscript.html @@ -1,3 +1,2 @@ - - + diff --git a/customize.dist/src/fragments/empty.html b/customize.dist/src/fragments/empty.html index 05fd6a0cb..d42a450af 100644 --- a/customize.dist/src/fragments/empty.html +++ b/customize.dist/src/fragments/empty.html @@ -1,2 +1 @@ -
diff --git a/customize.dist/src/fragments/script.html b/customize.dist/src/fragments/script.html index 99ea023b5..35a65e8a1 100644 --- a/customize.dist/src/fragments/script.html +++ b/customize.dist/src/fragments/script.html @@ -1,2 +1 @@ - - + diff --git a/customize.dist/src/template.html b/customize.dist/src/template.html index 314fa29f9..069e23511 100644 --- a/customize.dist/src/template.html +++ b/customize.dist/src/template.html @@ -1,5 +1,6 @@ + Cryptpad: Zero Knowledge, Collaborative Real Time Editing @@ -10,13 +11,6 @@ {{script}} - - {{topbar}} @@ -30,4 +24,3 @@ {{footer}} - diff --git a/customize.dist/terms.html b/customize.dist/terms.html index 205f6c2a7..a92c99c93 100644 --- a/customize.dist/terms.html +++ b/customize.dist/terms.html @@ -1,5 +1,6 @@ + Cryptpad: Zero Knowledge, Collaborative Real Time Editing @@ -9,16 +10,8 @@ - + - - -
@@ -127,4 +120,3 @@ - diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index cdf113048..23d706a8c 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -221,7 +221,7 @@ define(function () { out.login_noSuchUser = 'Invalid username or password. Try again, or sign up'; out.login_invalUser = 'Username required'; out.login_invalPass = 'Password required'; - out.login_unhandledError = 'An unexpected error occured :('; + out.login_unhandledError = 'An unexpected error occurred :('; out.register_importRecent = "Import pad history (Recommended)"; out.register_acceptTerms = "I accept the terms of service"; diff --git a/server.js b/server.js index 548a78949..503558c1f 100644 --- a/server.js +++ b/server.js @@ -7,6 +7,7 @@ var Https = require('https'); var Fs = require('fs'); var WebSocketServer = require('ws').Server; var NetfluxSrv = require('./NetfluxWebsocketSrv'); +var Package = require('./package.json'); var config = require('./config'); var websocketPort = config.websocketPort || config.httpPort; @@ -19,20 +20,31 @@ var app = Express(); var httpsOpts; +const clone = (x) => (JSON.parse(JSON.stringify(x))); + var setHeaders = (function () { if (typeof(config.httpHeaders) !== 'object') { return function () {}; } - var headers = JSON.parse(JSON.stringify(config.httpHeaders)); + const headers = clone(config.httpHeaders); + if (config.contentSecurity) { + headers['Content-Security-Policy'] = clone(config.contentSecurity); + } + const padHeaders = clone(headers); + if (config.padContentSecurity) { + padHeaders['Content-Security-Policy'] = clone(config.padContentSecurity); + } if (Object.keys(headers).length) { - return function (res) { - for (var header in headers) { res.setHeader(header, headers[header]); } + return function (req, res) { + const h = /^\/pad\/inner\.html.*/.test(req.url) ? padHeaders : headers; + for (let header in h) { res.setHeader(header, h[header]); } }; } return function () {}; }()); app.use(function (req, res, next) { - setHeaders(res); + setHeaders(req, res); + if (/[\?\&]ver=[^\/]+$/.test(req.url)) { res.setHeader("Cache-Control", "max-age=31536000"); } next(); }); @@ -82,6 +94,10 @@ app.get('/api/config', function(req, res){ var host = req.headers.host.replace(/\:[0-9]+/, ''); res.setHeader('Content-Type', 'text/javascript'); res.send('define(' + JSON.stringify({ + requireConf: { + waitSeconds: 60, + urlArgs: 'ver=' + Package.version + }, websocketPath: config.useExternalWebsocket ? undefined : config.websocketPath, websocketURL:'ws' + ((useSecureWebsockets) ? 's' : '') + '://' + host + ':' + websocketPort + '/cryptpad_websocket', diff --git a/www/code/index.html b/www/code/index.html index df3fe1142..af6247a40 100644 --- a/www/code/index.html +++ b/www/code/index.html @@ -4,13 +4,7 @@ CryptPad - - +
- - +
- diff --git a/www/code/main.js b/www/code/main.js index 5ece7a208..e8999ffee 100644 --- a/www/code/main.js +++ b/www/code/main.js @@ -689,7 +689,7 @@ define([ // inform of network disconnect setEditable(false); toolbar.failed(); - Cryptpad.alert(Messages.common_connectionLost); + Cryptpad.alert(Messages.common_connectionLost, undefined, force); }; var onConnectionChange = config.onConnectionChange = function (info) { @@ -700,7 +700,7 @@ define([ toolbar.reconnecting(info.myId); Cryptpad.findOKButton().click(); } else { - Cryptpad.alert(Messages.common_connectionLost); + Cryptpad.alert(Messages.common_connectionLost, undefined, force); } }; diff --git a/www/common/boot.js b/www/common/boot.js new file mode 100644 index 000000000..406521778 --- /dev/null +++ b/www/common/boot.js @@ -0,0 +1,5 @@ +// Stage 0, this gets cached which means we can't change it. boot2.js is changable. +define(['/api/config?cb=' + (+new Date()).toString(16)], function (Config) { + if (Config.requireConf) { require.config(Config.requireConf); } + require(['/common/boot2.js']); +}); diff --git a/www/common/boot2.js b/www/common/boot2.js new file mode 100644 index 000000000..72519b73e --- /dev/null +++ b/www/common/boot2.js @@ -0,0 +1,6 @@ +// This is stage 1, it can be changed but you must bump the version of the project. +define([], function () { + // fix up locations so that relative urls work. + require.config({ baseUrl: window.location.pathname }); + require([document.querySelector('script[data-bootload]').getAttribute('data-bootload')]); +}); diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 896042532..80b366766 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -1,5 +1,5 @@ define([ - '/api/config?cb=' + Math.random().toString(16).slice(2), + '/api/config', '/customize/messages.js?app=' + window.location.pathname.split('/').filter(function (x) { return x; }).join('.'), '/customize/fsStore.js', '/bower_components/chainpad-crypto/crypto.js?v=0.1.5', @@ -838,7 +838,7 @@ define([ if (!$('#' + LOADING).is(':visible')) { common.addLoadingScreen(); } $('.spinnerContainer').hide(); if (transparent) { $('#' + LOADING).css('opacity', 0.8); } - $('#' + LOADING).find('p').html(error || Messages.error); + $('#' + LOADING).find('p').text(error || Messages.error); }; /* @@ -961,7 +961,7 @@ define([ } else { callback(); } - common.alert(Messages.movedToTrash); + common.alert(Messages.movedToTrash, undefined, true); return; }); }); @@ -1292,8 +1292,9 @@ define([ $(window).off('keyup', handler); }; - common.alert = function (msg, cb) { + common.alert = function (msg, cb, force) { cb = cb || function () {}; + if (force !== true) { msg = fixHTML(msg); } var keyHandler = listenForKeys(function (e) { // yes findOKButton().click(); }); @@ -1306,9 +1307,10 @@ define([ }); }; - common.prompt = function (msg, def, cb, opt) { + common.prompt = function (msg, def, cb, opt, force) { opt = opt || {}; cb = cb || function () {}; + if (force !== true) { msg = fixHTML(msg); } var keyHandler = listenForKeys(function (e) { // yes findOKButton().click(); @@ -1329,9 +1331,11 @@ define([ }); }; - common.confirm = function (msg, cb, opt) { + common.confirm = function (msg, cb, opt, force) { opt = opt || {}; cb = cb || function () {}; + if (force !== true) { msg = fixHTML(msg); } + var keyHandler = listenForKeys(function (e) { findOKButton().click(); }, function (e) { diff --git a/www/common/noscriptfix.js b/www/common/noscriptfix.js new file mode 100644 index 000000000..532393248 --- /dev/null +++ b/www/common/noscriptfix.js @@ -0,0 +1,3 @@ +// Fix for noscript bugs when caching iframe content. +// Caution, this file will get cached, you must change the name if you change it. +document.getElementById('pad-iframe').setAttribute('src', 'inner.html?cb=' + (+new Date())); diff --git a/www/drive/index.html b/www/drive/index.html index d9c792a4c..43fe2b44c 100644 --- a/www/drive/index.html +++ b/www/drive/index.html @@ -10,13 +10,7 @@ data-alt-favicon="/customize/alt-favicon.png" id="favicon" /> - - + - - + - diff --git a/www/drive/main.js b/www/drive/main.js index 3aa67815c..0bde36d7d 100644 --- a/www/drive/main.js +++ b/www/drive/main.js @@ -18,7 +18,6 @@ define([ // Use `$(function () {});` to make sure the html is loaded before doing anything else $(function () { - var $iframe = $('#pad-iframe').contents(); var ifrw = $('#pad-iframe')[0].contentWindow; @@ -1796,7 +1795,7 @@ define([ if (path.length !== 4) { return; } var element = filesOp.getTrashElementData(path); var sPath = stringifyPath(element.path); - Cryptpad.alert('' + Messages.fm_originalPath + ":
" + sPath); + Cryptpad.alert('' + Messages.fm_originalPath + ":
" + sPath, undefined, true); } module.hideMenu(); }); @@ -2058,7 +2057,7 @@ define([ $backupButton.attr('title', Messages.fm_backup_title); $backupButton.on('click', function() { var url = window.location.origin + window.location.pathname + '#' + editHash; - Cryptpad.alert(Messages._getKey('fm_alert_backupUrl', [url])); + Cryptpad.alert(Messages._getKey('fm_alert_backupUrl', [url]), undefined, true); $('#fm_backupUrl').val(url); $('#fm_backupUrl').click(function () { $(this).select(); @@ -2083,7 +2082,7 @@ define([ setEditable(false); if (APP.refresh) { APP.refresh(); } APP.toolbar.failed(); - Cryptpad.alert(Messages.common_connectionLost); + Cryptpad.alert(Messages.common_connectionLost, undefined, true); }; var onReconnect = function (info) { setEditable(true); @@ -2116,6 +2115,5 @@ define([ onConnectError(); } }); - }); }); diff --git a/www/examples/board/index.html b/www/examples/board/index.html index ed36db678..df0fb5312 100644 --- a/www/examples/board/index.html +++ b/www/examples/board/index.html @@ -10,12 +10,7 @@ data-alt-favicon="/customize/alt-favicon.png" id="favicon" /> - - + Edit this document's style

HTML Ipsum Presents

- +

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis.

Header Level 2

- +
  1. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  2. Aliquam tincidunt mauris eu risus.
  3. @@ -30,10 +30,10 @@
    
    -#header h1 a { 
    -    display: block; 
    -    width: 300px; 
    -    height: 80px; 
    +#header h1 a {
    +    display: block;
    +    width: 300px;
    +    height: 80px;
     }
     
    @@ -58,4 +58,3 @@ - diff --git a/www/examples/text/index.html b/www/examples/text/index.html index 514095e99..b22cb7321 100644 --- a/www/examples/text/index.html +++ b/www/examples/text/index.html @@ -3,7 +3,7 @@ - + - - + - diff --git a/www/pad/main.js b/www/pad/main.js index 83d8a99cb..28476dd68 100644 --- a/www/pad/main.js +++ b/www/pad/main.js @@ -726,7 +726,7 @@ define([ setEditable(false); // TODO inform them that the session was torn down toolbar.failed(); - Cryptpad.alert(Messages.common_connectionLost); + Cryptpad.alert(Messages.common_connectionLost, undefined, true); }; var onConnectionChange = realtimeOptions.onConnectionChange = function (info) { @@ -737,7 +737,7 @@ define([ toolbar.reconnecting(info.myId); Cryptpad.findOKButton().click(); } else { - Cryptpad.alert(Messages.common_connectionLost); + Cryptpad.alert(Messages.common_connectionLost, undefined, true); } }; diff --git a/www/poll/index.html b/www/poll/index.html index cdaf574f3..363cae7e6 100644 --- a/www/poll/index.html +++ b/www/poll/index.html @@ -11,11 +11,7 @@ id="favicon" /> - - +