From cb2efe138b2d52f899313c92b90500167d528a31 Mon Sep 17 00:00:00 2001 From: Daniel RADEAU Date: Tue, 30 May 2017 16:36:06 +0200 Subject: [PATCH] Media Tag integration, image, audio, video, pdf --- config.modifs.js | 233 ++++++++++++++++++++++++++++++++++++++++ www/common/boot2.js | 4 +- www/common/media-tag.js | 2 +- www/media/main.js | 28 ++++- 4 files changed, 264 insertions(+), 3 deletions(-) create mode 100644 config.modifs.js diff --git a/config.modifs.js b/config.modifs.js new file mode 100644 index 000000000..1216b3c98 --- /dev/null +++ b/config.modifs.js @@ -0,0 +1,233 @@ +/*@flow*/ +/* + globals module +*/ +module.exports = { + + // the address you want to bind to, :: means all ipv4 and ipv6 addresses + // this may not work on all operating systems + httpAddress: '::', + + // the port on which your httpd will listen + + /* Cryptpad can be configured to send customized HTTP Headers + * These settings may vary widely depending on your needs + * Examples are provided below + */ + + httpHeaders: { + "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'", + "font-src 'self'", + + /* child-src is used to restrict iframes to a set of allowed domains. + * connect-src is used to restrict what domains can connect to the websocket. + * + * it is recommended that you configure these fields to match the + * domain which will serve your cryptpad instance. + */ + "child-src 'self' *", + + /* this allows connections over secure or insecure websockets + if you are deploying to production, you'll probably want to remove + the ws://* directive, and change '*' to your domain + */ + "connect-src 'self' ws: wss: blob:", + + // data: is used by codemirror + "img-src 'self' data: blob:", + "media-src 'self' data: blob:" + ].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'", + "font-src 'self'", + + /* See above under 'contentSecurity' as to how these values should be + * configured for best effect. + */ + "child-src 'self' *", + + // see the comment above in the 'contentSecurity' section + "connect-src 'self' ws: wss: blob:", + + // (insecure remote) images are included by users of the wysiwyg who embed photos in their pads + "img-src *", + "media-src *" + ].join('; '), + + httpPort: 3000, + + /* your server's websocket url is configurable + * (default: '/cryptpad_websocket') + * + * websocketPath can be relative, of the form '/path/to/websocket' + * or absolute, specifying a particular URL + * + * 'wss://cryptpad.fr:3000/cryptpad_websocket' + */ + websocketPath: '/cryptpad_websocket', + + /* it is assumed that your websocket will bind to the same port as http + * you can override this behaviour by supplying a number via websocketPort + */ + //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 + * the websockets on that server + */ + //useExternalWebsocket: false, + + /* If Cryptpad is proxied without using https, the server needs to know. + * Specify 'useSecureWebsockets: true' so that it can send + * Content Security Policy Headers that prevent http and https from mixing + */ + useSecureWebsockets: false, + + /* Cryptpad can log activity to stdout + * This may be useful for debugging + */ + logToStdout: false, + + /* Cryptpad supports verbose logging + * (false by default) + */ + verbose: false, + + /* Main pages + * add exceptions to the router so that we can access /privacy.html + * and other odd pages + */ + mainPages: [ + 'index', + 'privacy', + 'terms', + 'about', + 'contact', + ], + + /* Domain + * If you want to have enable payments on your CryptPad instance, it has to be able to tell + * our account server what is your domain + */ + // domain: 'https://cryptpad.fr', + + /* + You have the option of specifying an alternative storage adaptor. + These status of these alternatives are specified in their READMEs, + which are available at the following URLs: + + mongodb: a noSQL database + https://github.com/xwiki-labs/cryptpad-mongo-store + amnesiadb: in memory storage + https://github.com/xwiki-labs/cryptpad-amnesia-store + leveldb: a simple, fast, key-value store + https://github.com/xwiki-labs/cryptpad-level-store + sql: an adaptor for a variety of sql databases via knexjs + https://github.com/xwiki-labs/cryptpad-sql-store + + For the most up to date solution, use the default storage adaptor. + */ + storage: './storage/file', + + /* + Cryptpad stores each document in an individual file on your hard drive. + Specify a directory where files should be stored. + It will be created automatically if it does not already exist. + */ + filePath: './datastore/', + + /* CryptPad allows logged in users to request that particular documents be + * stored by the server indefinitely. This is called 'pinning'. + * Pin requests are stored in a pin-store. The location of this store is + * defined here. + */ + pinPath: './pins', + + /* CryptPad allows logged in users to upload encrypted files. Files/blobs + * are stored in a 'blob-store'. Set its location here. + */ + blobPath: './blob', + + /* CryptPad stores incomplete blobs in a 'staging' area until they are + * fully uploaded. Set its location here. + */ + blobStagingPath: './blobstage', + + /* Cryptpad's file storage adaptor closes unused files after a configurale + * number of milliseconds (default 30000 (30 seconds)) + */ + channelExpirationMs: 30000, + + /* Cryptpad's file storage adaptor is limited by the number of open files. + * When the adaptor reaches openFileLimit, it will clean up older files + */ + openFileLimit: 2048, + + /* Cryptpad's socket server can be extended to respond to RPC calls + * you can configure it to respond to custom RPC calls if you like. + * provide the path to your RPC module here, or `false` if you would + * like to disable the RPC interface completely + */ + rpc: './rpc.js', + + /* RPC errors are shown by default, but if you really don't care, + * you can suppress them + */ + suppressRPCErrors: false, + + + /* WARNING: EXPERIMENTAL + * + * CryptPad features experimental support for encrypted file upload. + * Our encryption format is still liable to change. As such, we do not + * guarantee that files uploaded now will be supported in the future + */ + + /* Setting this value to anything other than true will cause file upload + * attempts to be rejected outright. + */ + enableUploads: true, + + /* If you have enabled file upload, you have the option of restricting it + * to a list of users identified by their public keys. If this value is set + * to true, your server will query a file (cryptpad/privileged.conf) when + * users connect via RPC. Only users whose public keys can be found within + * the file will be allowed to upload. + * + * privileged.conf uses '#' for line comments, and splits keys by newline. + * This is a temporary measure until a better quota system is in place. + * registered users' public keys can be found on the settings page. + */ + restrictUploads: false, + + /* clients can use the /settings/ app to opt out of usage feedback + * which informs the server of things like how much each app is being + * used, and whether certain clientside features are supported by + * the client's browser. The intent is to provide feedback to the admin + * such that the service can be improved. Enable this with `true` + * and ignore feedback with `false` or by commenting the attribute + */ + //logFeedback: true, + + /* it is recommended that you serve cryptpad over https + * the filepaths below are used to configure your certificates + */ + //privKeyAndCertFiles: [ + // '/etc/apache2/ssl/my_secret.key', + // '/etc/apache2/ssl/my_public_cert.crt', + // '/etc/apache2/ssl/my_certificate_authorities_cert_chain.ca' + //], +}; diff --git a/www/common/boot2.js b/www/common/boot2.js index d894191e8..76ce9bcf9 100644 --- a/www/common/boot2.js +++ b/www/common/boot2.js @@ -7,7 +7,9 @@ define([], function () { // jquery declares itself as literally "jquery" so it cannot be pulled by path :( "jquery": "/bower_components/jquery/dist/jquery.min", // json.sortify same - "json.sortify": "/bower_components/json.sortify/dist/JSON.sortify" + "json.sortify": "/bower_components/json.sortify/dist/JSON.sortify", + "pdfjs-dist/build/pdf": "/bower_components/pdfjs-dist/build/pdf", + "pdfjs-dist/build/pdf.worker": "/bower_components/pdfjs-dist/build/pdf.worker" } }); diff --git a/www/common/media-tag.js b/www/common/media-tag.js index 370b0e93d..1f1bc7445 100644 --- a/www/common/media-tag.js +++ b/www/common/media-tag.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.MediaTag=t():e.MediaTag=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var n={};return t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=82)}([function(e,t,n){"use strict";var r={IMAGE:"image",AUDIO:"audio",VIDEO:"video",PDF:"pdf",DASH:"dash",DOWNLOAD:"download",CRYPTO:"crypto",CLEAR_KEY:"clear-key",MEDIA_OBJECT:"media-object"};e.exports=r},function(e,t,n){"use strict";var r={MATCHER:"matcher",RENDERER:"renderer",FILTER:"filter",SANITIZER:"sanitizer"};e.exports=r},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function i(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var u=function(){function e(e,t){for(var n=0;n=e.STACK_LIMIT)throw console.error(e.snapshots[n]),new Error("Plugin stack size exceed");if(e.snapshots[n].length>=e.SNAPSHOT_LIMIT)throw console.error(e.snapshots[n]),new Error("Plugin snapshots size exceed");var r=0;if(e.stacks[n].forEach(function(e){e.type===u.RENDERER&&r++}),r<1&&e.stacks[n].unshift(e.defaultPlugin),r>1)throw new Error("More of one renderer in the stack")}},{key:"return",value:function(t){e.start(t)}},{key:"run",value:function(t){var n=t.getId(),r=e.stacks[n].length,o=e.stacks[n][r-1];if(!o)throw console.log(e.stacks),new Error("Impossible to run a undefined plugin");o.process(t)}}]),e}();f.stacks={},f.STACK_LIMIT=1e3,f.snapshots={},f.SNAPSHOT_LIMIT=1e3,f.defaultPlugin=new s,e.exports=f},function(e,t,n){"use strict";var r={EVERY:"every",ANY:"any",ONCE:"once"};e.exports=r},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=function(){function e(e,t){for(var n=0;n1;){if(c){if("number"!=typeof e[t])throw new Error("E_UNSAFE_TYPE");if(e[t]>255)throw new Error("E_OUT_OF_BOUNDS")}if(255!==e[t])return void e[t]++;if(e[t]=0,0===t)throw new Error("E_NONCE_TOO_LARGE")}}},{key:"encodePrefix",value:function(e){return[65280,255].map(function(t,n){return(e&t)>>8*(1-n)})}},{key:"decodePrefix",value:function(e){return e[0]<<8|e[1]}},{key:"joinChunks",value:function(t){return new Uint8Array(t.reduce(function(t,n){return e.slice(t).concat(e.slice(n))},[]))}},{key:"slice",value:function(e){return Array.prototype.slice.call(e)}},{key:"getRandomKeyStr",value:function(){var t=e.Nacl,n=t.randomBytes(18);return t.util.encodeBase64(n)}},{key:"getKeyFromStr",value:function(t){return e.Nacl.util.decodeBase64(t)}},{key:"encrypt",value:function(t,n){var r=t,o=e.Nacl.randomBytes(24),i=e.Nacl.secretbox(r,o,n);if(i)return new Uint8Array(e.slice(o).concat(e.slice(i)));throw new Error}},{key:"decrypt",value:function(t,n,r){var o=e.Nacl,i=function(e){var n=new Event("decryptionProgress");n.percent=e/t.length*100,window.document.dispatchEvent(n)},u=e.createNonce(),a=0,c=t.subarray(0,2),f=e.decodePrefix(c),l={metadata:void 0},p=new Uint8Array(t.subarray(2,2+f)),y=o.secretbox.open(p,u,n);e.increment(u);try{l.metadata=JSON.parse(o.util.encodeUTF8(y))}catch(e){return r("E_METADATA_DECRYPTION")}if(!l.metadata)return r("NO_METADATA");var b=function(r){var c=a*s+2+f,l=c+s;a++;var p=new Uint8Array(t.subarray(c,l)),y=o.secretbox.open(p,u,n);if(e.increment(u),!y)return void r("DECRYPTION_FAILURE");i(Math.min(l,t.length)),r(void 0,y)},h=[];!function n(){b(function(o,i){return o?setTimeout(function(){r(o)}):i?a*s1?t[0]:window.location.protocol}},{key:"hostname",value:function(e){var t=e.getAttribute("src").split("://");return t.length>1?t[1].split("/")[0]:window.location.hostname}},{key:"source",value:function(e){return e.getAttribute("src")}},{key:"schemes",value:function(e){return/\w+:/.exec(e.getAttribute("src"))}},{key:"parse",value:function(t){return{protocol:e.protocol(t),hostname:e.hostname(t),src:e.source(t),type:e.type(t),extension:e.extension(t),mime:e.mime(t)}}}]),e}();e.exports=i},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function i(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var u=function(){function e(e,t){for(var n=0;n=0&&f.mediaTypes.splice(t,1)},f.removeAllAllowedMediaTypes=function(e){e.forEach(function(e){f.removeAllowedMediaType(e)})},f.isAllowedMediaType=function(e){return f.mediaTypes.some(function(t){return t===e})},e.exports=f},,function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=function(){function e(e,t){for(var n=0;n1;){if(f){if("number"!=typeof e[t])throw new Error("E_UNSAFE_TYPE");if(e[t]>255)throw new Error("E_OUT_OF_BOUNDS")}if(255!==e[t])return void e[t]++;if(e[t]=0,0===t)throw new Error("E_NONCE_TOO_LARGE")}}},{key:"encodePrefix",value:function(e){return[65280,255].map(function(t,n){return(e&t)>>8*(1-n)})}},{key:"decodePrefix",value:function(e){return e[0]<<8|e[1]}},{key:"joinChunks",value:function(t){return new Uint8Array(t.reduce(function(t,n){return e.slice(t).concat(e.slice(n))},[]))}},{key:"slice",value:function(e){return Array.prototype.slice.call(e)}},{key:"getRandomKeyStr",value:function(){var t=e.Nacl,n=t.randomBytes(18);return t.util.encodeBase64(n)}},{key:"getKeyFromStr",value:function(t){return e.Nacl.util.decodeBase64(t)}},{key:"encrypt",value:function(t,n){var r=t,o=e.Nacl.randomBytes(24),i=e.Nacl.secretbox(r,o,n);if(i)return new Uint8Array(e.slice(o).concat(e.slice(i)));throw new Error}},{key:"decrypt",value:function(t,n,r){var o=e.Nacl,i=function(e){var n=new Event("decryptionProgress");n.percent=e/t.length*100,window.document.dispatchEvent(n)},u=e.createNonce(),a=0,c=t.subarray(0,2),s=e.decodePrefix(c),f={metadata:void 0},p=new Uint8Array(t.subarray(2,2+s)),y=o.secretbox.open(p,u,n);e.increment(u);try{f.metadata=JSON.parse(o.util.encodeUTF8(y))}catch(e){return r("E_METADATA_DECRYPTION")}if(!f.metadata)return r("NO_METADATA");var h=function(r){var c=a*l+2+s,f=c+l;a++;var p=new Uint8Array(t.subarray(c,f)),y=o.secretbox.open(p,u,n);if(e.increment(u),!y)return void r("DECRYPTION_FAILURE");i(Math.min(f,t.length)),r(void 0,y)},b=[];!function n(){h(function(o,i){return o?setTimeout(function(){r(o)}):i?a*l1?t[0]:window.location.protocol}},{key:"hostname",value:function(e){var t=e.getAttribute("src").split("://");return t.length>1?t[1].split("/")[0]:window.location.hostname}},{key:"source",value:function(e){return e.getAttribute("src")}},{key:"schemes",value:function(e){return/\w+:/.exec(e.getAttribute("src"))}},{key:"parse",value:function(t){return{protocol:e.protocol(t),hostname:e.hostname(t),src:e.source(t),type:e.type(t),extension:e.extension(t),mime:e.mime(t)}}}]),e}();e.exports=i},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=function(){function e(e,t){for(var n=0;n=e.STACK_LIMIT)throw console.error(this.snapshots[n]),new Error("Plugin stack size exceed");if(this.snapshots[n].length>=e.SNAPSHOT_LIMIT)throw console.error(this.snapshots[n]),new Error("Plugin snapshots size exceed");var r=0;if(this.stacks[n].forEach(function(e){e.type===a.RENDERER&&r++}),r>1)throw console.error(this.snapshots[n]),new Error("More of one renderer in the stack");0!==this.stacks[n].length||this.stats[n][a.RENDERER]||this.stacks[n].unshift(e.defaultPlugin)}},{key:"return",value:function(e){var t=e.getId(),n=this.unstack(e);this.stats[t]||(this.stats[t]={}),this.stats[t][n.type]?this.stats[t][n.type]+=1:this.stats[t][n.type]=1,0===this.stacks[t].length&&n.type===a.RENDERER?this.run(e):n.type!==a.SANITIZER&&this.fill(e),this.snapshot(e),this.check(e),this.run(e)}},{key:"process",value:function(e){var t=e.getId(),n=this.stacks[t].length,r=this.stacks[t][n-1];if(!r)throw console.log(this.stacks),new Error("Impossible to run a undefined plugin");r.process(e)}},{key:"isStacked",value:function(e,t){var n=e.getId();return!(!this.stacks[n]||!this.stacks[n].includes(t))}}]),e}();l.STACK_LIMIT=100,l.SNAPSHOT_LIMIT=100,l.defaultPlugin=new s("

MediaTag cannot find a plugin able to renderer your content

","Download"),e.exports=l},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function i(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var u=function(){function e(e,t){for(var n=0;n