tools: scripts, readme and config files
This adds a minimal setup to run the customized cryptpad instance. All info is in the readme.md. The config.js and nginx.conf will go away at some point, once a central qcode infra repo is in place.pull/1/head
parent
57e1445e3f
commit
e1224868e0
@ -0,0 +1,3 @@
|
|||||||
|
**/.git
|
||||||
|
cryptpad/config/config.js
|
||||||
|
cryptpad/customize
|
@ -0,0 +1 @@
|
|||||||
|
build
|
@ -0,0 +1,18 @@
|
|||||||
|
FROM node:16.14-slim AS build
|
||||||
|
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
RUN apt-get update -qq && \
|
||||||
|
apt-get install -yq git ca-certificates && \
|
||||||
|
npm install -g bower
|
||||||
|
|
||||||
|
# the bootstrap is created in tools/build-prod.sh
|
||||||
|
COPY build/bootstrap.tar /
|
||||||
|
RUN mkdir -p /build && \
|
||||||
|
cd /build && \
|
||||||
|
tar -xf /bootstrap.tar && \
|
||||||
|
npm ci && \
|
||||||
|
bower install --allow-root --production
|
||||||
|
|
||||||
|
FROM node:16.14-alpine
|
||||||
|
COPY --from=build /build /app
|
||||||
|
WORKDIR /app
|
@ -0,0 +1,288 @@
|
|||||||
|
/* globals module */
|
||||||
|
|
||||||
|
/* DISCLAIMER:
|
||||||
|
|
||||||
|
There are two recommended methods of running a CryptPad instance:
|
||||||
|
|
||||||
|
1. Using a standalone nodejs server without HTTPS (suitable for local development)
|
||||||
|
2. Using NGINX to serve static assets and to handle HTTPS for API server's websocket traffic
|
||||||
|
|
||||||
|
We do not officially recommend or support Apache, Docker, Kubernetes, Traefik, or any other configuration.
|
||||||
|
Support requests for such setups should be directed to their authors.
|
||||||
|
|
||||||
|
If you're having difficulty difficulty configuring your instance
|
||||||
|
we suggest that you join the project's IRC/Matrix channel.
|
||||||
|
|
||||||
|
If you don't have any difficulty configuring your instance and you'd like to
|
||||||
|
support us for the work that went into making it pain-free we are quite happy
|
||||||
|
to accept donations via our opencollective page: https://opencollective.com/cryptpad
|
||||||
|
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
/* CryptPad is designed to serve its content over two domains.
|
||||||
|
* Account passwords and cryptographic content is handled on the 'main' domain,
|
||||||
|
* while the user interface is loaded on a 'sandbox' domain
|
||||||
|
* which can only access information which the main domain willingly shares.
|
||||||
|
*
|
||||||
|
* In the event of an XSS vulnerability in the UI (that's bad)
|
||||||
|
* this system prevents attackers from gaining access to your account (that's good).
|
||||||
|
*
|
||||||
|
* Most problems with new instances are related to this system blocking access
|
||||||
|
* because of incorrectly configured sandboxes. If you only see a white screen
|
||||||
|
* when you try to load CryptPad, this is probably the cause.
|
||||||
|
*
|
||||||
|
* PLEASE READ THE FOLLOWING COMMENTS CAREFULLY.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* httpUnsafeOrigin is the URL that clients will enter to load your instance.
|
||||||
|
* Any other URL that somehow points to your instance is supposed to be blocked.
|
||||||
|
* The default provided below assumes you are loading CryptPad from a server
|
||||||
|
* which is running on the same machine, using port 3000.
|
||||||
|
*
|
||||||
|
* In a production instance this should be available ONLY over HTTPS
|
||||||
|
* using the default port for HTTPS (443) ie. https://cryptpad.fr
|
||||||
|
* In such a case this should be also handled by NGINX, as documented in
|
||||||
|
* cryptpad/docs/example.nginx.conf (see the $main_domain variable)
|
||||||
|
*
|
||||||
|
* Note: you may provide multiple origins for the purpose of accessing
|
||||||
|
* a development instance via different URLs, like so:
|
||||||
|
* httpUnsafeOrigin: 'http://127.0.0.1:3000/ http://localhost:3000/',
|
||||||
|
*
|
||||||
|
* Such configuration is not recommended for production instances,
|
||||||
|
* as the development team does not actively test such configuration
|
||||||
|
* and it may have unintended consequences in practice.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
httpUnsafeOrigin: 'https://cryptpad.qcode.ch',
|
||||||
|
|
||||||
|
/* httpSafeOrigin is the URL that is used for the 'sandbox' described above.
|
||||||
|
* If you're testing or developing with CryptPad on your local machine then
|
||||||
|
* it is appropriate to leave this blank. The default behaviour is to serve
|
||||||
|
* the main domain over port 3000 and to serve the content over port 3001.
|
||||||
|
*
|
||||||
|
* This is not appropriate in a production environment where invasive networks
|
||||||
|
* may filter traffic going over abnormal ports.
|
||||||
|
* To correctly configure your production instance you must provide a URL
|
||||||
|
* with a different domain (a subdomain is sufficient).
|
||||||
|
* It will be used to load the UI in our 'sandbox' system.
|
||||||
|
*
|
||||||
|
* This value corresponds to the $sandbox_domain variable
|
||||||
|
* in the example nginx file.
|
||||||
|
*
|
||||||
|
* CUSTOMIZE AND UNCOMMENT THIS FOR PRODUCTION INSTALLATIONS.
|
||||||
|
*/
|
||||||
|
httpSafeOrigin: 'https://cryptpad.qcodecdn.ch',
|
||||||
|
|
||||||
|
/* httpAddress specifies the address on which the nodejs server
|
||||||
|
* should be accessible. By default it will listen on 127.0.0.1
|
||||||
|
* (IPv4 localhost on most systems). If you want it to listen on
|
||||||
|
* all addresses, including IPv6, set this to '::'.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
httpAddress: '127.0.0.1',
|
||||||
|
|
||||||
|
/* httpPort specifies on which port the nodejs server should listen.
|
||||||
|
* By default it will serve content over port 3000, which is suitable
|
||||||
|
* for both local development and for use with the provided nginx example,
|
||||||
|
* which will proxy websocket traffic to your node server.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
httpPort: 3000,
|
||||||
|
|
||||||
|
/* httpSafePort allows you to specify an alternative port from which
|
||||||
|
* the node process should serve sandboxed assets. The default value is
|
||||||
|
* that of your httpPort + 1. You probably don't need to change this.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//httpSafePort: 3001,
|
||||||
|
|
||||||
|
/* CryptPad will launch a child process for every core available
|
||||||
|
* in order to perform CPU-intensive tasks in parallel.
|
||||||
|
* Some host environments may have a very large number of cores available
|
||||||
|
* or you may want to limit how much computing power CryptPad can take.
|
||||||
|
* If so, set 'maxWorkers' to a positive integer.
|
||||||
|
*/
|
||||||
|
// maxWorkers: 4,
|
||||||
|
|
||||||
|
/* =====================
|
||||||
|
* Admin
|
||||||
|
* ===================== */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CryptPad contains an administration panel. Its access is restricted to specific
|
||||||
|
* users using the following list.
|
||||||
|
* To give access to the admin panel to a user account, just add their public signing
|
||||||
|
* key, which can be found on the settings page for registered users.
|
||||||
|
* Entries should be strings separated by a comma.
|
||||||
|
*/
|
||||||
|
adminKeys: [
|
||||||
|
'[admin@cryptpad.qcode.ch/LSxbkUbVQbJZ8Tqna6Y2gg69iI0eRclGe+NjJrtiW-A=]',
|
||||||
|
'[x1ddos@cryptpad.qcode.ch/w74oU0GPvPc9OxX+2l0kefvQOSZwI61E4lpZeACJlTw=]',
|
||||||
|
],
|
||||||
|
adminEmail: 'root@qcode.ch',
|
||||||
|
|
||||||
|
/* =====================
|
||||||
|
* STORAGE
|
||||||
|
* ===================== */
|
||||||
|
|
||||||
|
/* Pads that are not 'pinned' by any registered user can be set to expire
|
||||||
|
* after a configurable number of days of inactivity (default 90 days).
|
||||||
|
* The value can be changed or set to false to remove expiration.
|
||||||
|
* Expired pads can then be removed using a cron job calling the
|
||||||
|
* `evict-inactive.js` script with node
|
||||||
|
*
|
||||||
|
* defaults to 90 days if nothing is provided
|
||||||
|
*/
|
||||||
|
inactiveTime: false,
|
||||||
|
|
||||||
|
/* CryptPad archives some data instead of deleting it outright.
|
||||||
|
* This archived data still takes up space and so you'll probably still want to
|
||||||
|
* remove these files after a brief period.
|
||||||
|
*
|
||||||
|
* cryptpad/scripts/evict-inactive.js is intended to be run daily
|
||||||
|
* from a crontab or similar scheduling service.
|
||||||
|
*
|
||||||
|
* The intent with this feature is to provide a safety net in case of accidental
|
||||||
|
* deletion. Set this value to the number of days you'd like to retain
|
||||||
|
* archived data before it's removed permanently.
|
||||||
|
*
|
||||||
|
* defaults to 15 days if nothing is provided
|
||||||
|
*/
|
||||||
|
archiveRetentionTime: 7,
|
||||||
|
|
||||||
|
/* It's possible to configure your instance to remove data
|
||||||
|
* stored on behalf of inactive accounts. Set 'accountRetentionTime'
|
||||||
|
* to the number of days an account can remain idle before its
|
||||||
|
* documents and other account data is removed.
|
||||||
|
*
|
||||||
|
* Leave this value commented out to preserve all data stored
|
||||||
|
* by user accounts regardless of inactivity.
|
||||||
|
*/
|
||||||
|
accountRetentionTime: 365,
|
||||||
|
|
||||||
|
/* Starting with CryptPad 3.23.0, the server automatically runs
|
||||||
|
* the script responsible for removing inactive data according to
|
||||||
|
* your configured definition of inactivity. Set this value to `true`
|
||||||
|
* if you prefer not to remove inactive data, or if you prefer to
|
||||||
|
* do so manually using `scripts/evict-inactive.js`.
|
||||||
|
*/
|
||||||
|
//disableIntegratedEviction: true,
|
||||||
|
|
||||||
|
|
||||||
|
/* Max Upload Size (bytes)
|
||||||
|
* this sets the maximum size of any one file uploaded to the server.
|
||||||
|
* anything larger than this size will be rejected
|
||||||
|
* defaults to 20MB if no value is provided
|
||||||
|
*/
|
||||||
|
maxUploadSize: 100 * 1024 * 1024,
|
||||||
|
|
||||||
|
/* Users with premium accounts (those with a plan included in their customLimit)
|
||||||
|
* can benefit from an increased upload size limit. By default they are restricted to the same
|
||||||
|
* upload size as any other registered user.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//premiumUploadSize: 100 * 1024 * 1024,
|
||||||
|
|
||||||
|
/* =====================
|
||||||
|
* DATABASE VOLUMES
|
||||||
|
* ===================== */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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: './data/datastore/',
|
||||||
|
|
||||||
|
/* CryptPad offers the ability to archive data for a configurable period
|
||||||
|
* before deleting it, allowing a means of recovering data in the event
|
||||||
|
* that it was deleted accidentally.
|
||||||
|
*
|
||||||
|
* To set the location of this archive directory to a custom value, change
|
||||||
|
* the path below:
|
||||||
|
*/
|
||||||
|
archivePath: './data/archive',
|
||||||
|
|
||||||
|
/* 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: './data/pins',
|
||||||
|
|
||||||
|
/* if you would like the list of scheduled tasks to be stored in
|
||||||
|
a custom location, change the path below:
|
||||||
|
*/
|
||||||
|
taskPath: './data/tasks',
|
||||||
|
|
||||||
|
/* if you would like users' authenticated blocks to be stored in
|
||||||
|
a custom location, change the path below:
|
||||||
|
*/
|
||||||
|
blockPath: './data/block',
|
||||||
|
|
||||||
|
/* CryptPad allows logged in users to upload encrypted files. Files/blobs
|
||||||
|
* are stored in a 'blob-store'. Set its location here.
|
||||||
|
*/
|
||||||
|
blobPath: './data/blob',
|
||||||
|
|
||||||
|
/* CryptPad stores incomplete blobs in a 'staging' area until they are
|
||||||
|
* fully uploaded. Set its location here.
|
||||||
|
*/
|
||||||
|
blobStagingPath: './data/blobstage',
|
||||||
|
|
||||||
|
decreePath: './data/decrees',
|
||||||
|
|
||||||
|
/* CryptPad supports logging events directly to the disk in a 'logs' directory
|
||||||
|
* Set its location here, or set it to false (or nothing) if you'd rather not log
|
||||||
|
*/
|
||||||
|
logPath: './data/logs',
|
||||||
|
|
||||||
|
/* =====================
|
||||||
|
* Debugging
|
||||||
|
* ===================== */
|
||||||
|
|
||||||
|
/* CryptPad can log activity to stdout
|
||||||
|
* This may be useful for debugging
|
||||||
|
*/
|
||||||
|
logToStdout: true,
|
||||||
|
|
||||||
|
/* CryptPad can be configured to log more or less
|
||||||
|
* the various settings are listed below by order of importance
|
||||||
|
*
|
||||||
|
* silly, verbose, debug, feedback, info, warn, error
|
||||||
|
*
|
||||||
|
* Choose the least important level of logging you wish to see.
|
||||||
|
* For example, a 'silly' logLevel will display everything,
|
||||||
|
* while 'info' will display 'info', 'warn', and 'error' logs
|
||||||
|
*
|
||||||
|
* This will affect both logging to the console and the disk.
|
||||||
|
*/
|
||||||
|
logLevel: 'debug',
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
*
|
||||||
|
* You will need to set your logLevel to include 'feedback'. Set this
|
||||||
|
* to false if you'd like to exclude feedback from your logs.
|
||||||
|
*/
|
||||||
|
logFeedback: false,
|
||||||
|
|
||||||
|
/* CryptPad supports verbose logging
|
||||||
|
* (false by default)
|
||||||
|
*/
|
||||||
|
verbose: true,
|
||||||
|
|
||||||
|
/* Surplus information:
|
||||||
|
*
|
||||||
|
* 'installMethod' is included in server telemetry to voluntarily
|
||||||
|
* indicate how many instances are using unofficial installation methods
|
||||||
|
* such as Docker.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
installMethod: 'unspecified',
|
||||||
|
};
|
@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="cp" id="four-oh-four">
|
||||||
|
<!-- If this file is not called customize.dist/src/template.html, it is generated -->
|
||||||
|
<head>
|
||||||
|
<title data-localization="main_title">CryptPad: Collaboration suite, encrypted and open-source</title>
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||||
|
<link rel="icon" type="image/png" href="/customize/favicon/main-favicon.png" id="favicon"/>
|
||||||
|
<script async data-bootload="/customize/four-oh-four.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
|
||||||
|
</head>
|
||||||
|
<body class="html">
|
||||||
|
<noscript>
|
||||||
|
<h1>404</h1>
|
||||||
|
<h3>We couldn't find the page you were looking for</h3>
|
||||||
|
|
||||||
|
</noscript>
|
@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="cp" id="five-hundred">
|
||||||
|
<!-- If this file is not called customize.dist/src/template.html, it is generated -->
|
||||||
|
<head>
|
||||||
|
<title data-localization="main_title">CryptPad: Collaboration suite, encrypted and open-source</title>
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||||
|
<link rel="icon" type="image/png" href="/customize/favicon/main-favicon.png" id="favicon"/>
|
||||||
|
<script async data-bootload="/customize/four-oh-four.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
|
||||||
|
</head>
|
||||||
|
<body class="html">
|
||||||
|
<noscript>
|
||||||
|
<h1>500</h1>
|
||||||
|
<h3>Internal server error</h3>
|
||||||
|
|
||||||
|
</noscript>
|
@ -0,0 +1,19 @@
|
|||||||
|
// see all options in www/common/application_config_internal.js
|
||||||
|
define(['/common/application_config_internal.js'], function (AppConfig) {
|
||||||
|
// remove the survey link in the menu
|
||||||
|
AppConfig.surveyURL = "";
|
||||||
|
|
||||||
|
// show all app types in document creation dialog
|
||||||
|
AppConfig.hiddenTypes = [];
|
||||||
|
|
||||||
|
// enable OnlyOffice docs and preso support
|
||||||
|
AppConfig.enableEarlyAccess = true;
|
||||||
|
|
||||||
|
// user passwords are hashed with scrypt, and salted with their username.
|
||||||
|
// this value will be appended to the username, causing the resulting hash
|
||||||
|
// to differ from other CryptPad instances if customized.
|
||||||
|
AppConfig.loginSalt = '';
|
||||||
|
AppConfig.minimumPasswordLength = 8;
|
||||||
|
|
||||||
|
return AppConfig;
|
||||||
|
});
|
@ -0,0 +1,219 @@
|
|||||||
|
server {
|
||||||
|
listen 443 ssl http2;
|
||||||
|
listen [::]:443 ssl http2;
|
||||||
|
|
||||||
|
server_name cryptpad.qcode.ch cryptpad.qcodecdn.ch;
|
||||||
|
|
||||||
|
access_log /var/log/nginx/cryptpad.log;
|
||||||
|
error_log /var/log/nginx/cryptpad.log;
|
||||||
|
|
||||||
|
# expected to cover both main and sandbox hostnames.
|
||||||
|
ssl_certificate /etc/ssl/qcode/cryptpad.qcode.ch.crt;
|
||||||
|
ssl_certificate_key /etc/ssl/qcode/cryptpad.qcode.ch.key;
|
||||||
|
|
||||||
|
ssl_dhparam /etc/nginx/snippets/dhparam; # openssl dhparam -out /etc/nginx/dhparam.pem 4096
|
||||||
|
ssl_session_timeout 5m;
|
||||||
|
ssl_session_cache shared:cryptpadSSL:5m;
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
# https://cipherli.st/
|
||||||
|
ssl_ciphers EECDH+AESGCM:EDH+AESGCM;
|
||||||
|
ssl_ecdh_curve secp384r1;
|
||||||
|
|
||||||
|
# CryptPad serves static assets over these two domains.
|
||||||
|
# `main_domain` is what users will enter in their address bar.
|
||||||
|
# Privileged computation such as key management is handled in this scope
|
||||||
|
# UI content is loaded via the `sandbox_domain`.
|
||||||
|
# "Content Security Policy" headers prevent content loaded via the sandbox
|
||||||
|
# from accessing privileged information.
|
||||||
|
# These variables must be different to take advantage of CryptPad's sandboxing techniques.
|
||||||
|
# In the event of an XSS vulnerability in CryptPad's front-end code
|
||||||
|
# this will limit the amount of information accessible to attackers.
|
||||||
|
set $main_domain "cryptpad.qcode.ch";
|
||||||
|
set $sandbox_domain "cryptpad.qcodecdn.ch";
|
||||||
|
|
||||||
|
# By default CryptPad allows remote domains to embed CryptPad documents in iframes.
|
||||||
|
# This behaviour can be blocked by changing $allowed_origins from "*" to the
|
||||||
|
# sandbox domain, which must be permitted to load content from the main domain
|
||||||
|
# in order for CryptPad to work as expected.
|
||||||
|
#
|
||||||
|
# An example is given below which can be uncommented if you want to block
|
||||||
|
# remote sites from including content from your server
|
||||||
|
set $allowed_origins "*";
|
||||||
|
# set $allowed_origins "https://${sandbox_domain}";
|
||||||
|
|
||||||
|
# CryptPad's dynamic content (websocket traffic and encrypted blobs)
|
||||||
|
# can be served over separate domains. Using dedicated domains (or subdomains)
|
||||||
|
# for these purposes allows you to move them to a separate machine at a later date
|
||||||
|
# if you find that a single machine cannot handle all of your users.
|
||||||
|
# If you don't use dedicated domains, this can be the same as $main_domain
|
||||||
|
# If you do, they can be added as exceptions to any rules which block connections to remote domains.
|
||||||
|
# You can find these variables referenced below in the relevant places
|
||||||
|
set $api_domain "cryptpad.qcode.ch";
|
||||||
|
#set $files_domain "files.your-main-domain.com";
|
||||||
|
|
||||||
|
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
|
||||||
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
add_header Access-Control-Allow-Origin "${allowed_origins}";
|
||||||
|
# add_header X-Frame-Options "SAMEORIGIN";
|
||||||
|
|
||||||
|
# Enable SharedArrayBuffer in Firefox (for .xlsx export)
|
||||||
|
add_header Cross-Origin-Resource-Policy cross-origin;
|
||||||
|
add_header Cross-Origin-Embedder-Policy require-corp;
|
||||||
|
|
||||||
|
# Insert the path to your CryptPad repository root here
|
||||||
|
root /home/cryptpad/static;
|
||||||
|
index index.html;
|
||||||
|
#error_page 404 customize/404.html;
|
||||||
|
|
||||||
|
# any static assets loaded with "ver=" in their URL will be cached for a year
|
||||||
|
if ($args ~ ver=) {
|
||||||
|
set $cacheControl max-age=31536000;
|
||||||
|
}
|
||||||
|
if ($uri ~ ^/.*(\/|\.html)$) {
|
||||||
|
set $cacheControl no-cache;
|
||||||
|
}
|
||||||
|
# Will not set any header if it is emptystring
|
||||||
|
add_header Cache-Control $cacheControl;
|
||||||
|
|
||||||
|
# CSS can be dynamically set inline, loaded from the same domain, or from $main_domain
|
||||||
|
set $styleSrc "'unsafe-inline' 'self' https://${main_domain}";
|
||||||
|
|
||||||
|
# connect-src restricts URLs which can be loaded using script interfaces
|
||||||
|
# if you have configured your instance to use a dedicated $files_domain or $api_domain
|
||||||
|
# you will need to add them below as: https://${files_domain} and https://${api_domain}
|
||||||
|
set $connectSrc "'self' https://${main_domain} blob: wss://${api_domain} https://${sandbox_domain}";
|
||||||
|
|
||||||
|
# fonts can be loaded from data-URLs or the main domain
|
||||||
|
set $fontSrc "'self' data: https://${main_domain}";
|
||||||
|
|
||||||
|
# images can be loaded from anywhere, though we'd like to deprecate this as it allows the use of images for tracking
|
||||||
|
set $imgSrc "'self' data: blob: https://${main_domain}";
|
||||||
|
|
||||||
|
# frame-src specifies valid sources for nested browsing contexts.
|
||||||
|
# this prevents loading any iframes from anywhere other than the sandbox domain
|
||||||
|
set $frameSrc "'self' https://${sandbox_domain} blob:";
|
||||||
|
|
||||||
|
# specifies valid sources for loading media using video or audio
|
||||||
|
set $mediaSrc "blob:";
|
||||||
|
|
||||||
|
# defines valid sources for webworkers and nested browser contexts
|
||||||
|
# deprecated in favour of worker-src and frame-src
|
||||||
|
set $childSrc "https://${main_domain}";
|
||||||
|
|
||||||
|
# specifies valid sources for Worker, SharedWorker, or ServiceWorker scripts.
|
||||||
|
# supercedes child-src but is unfortunately not yet universally supported.
|
||||||
|
set $workerSrc "'self'";
|
||||||
|
|
||||||
|
# script-src specifies valid sources for javascript, including inline handlers
|
||||||
|
set $scriptSrc "'self' resource: https://${main_domain}";
|
||||||
|
|
||||||
|
# frame-ancestors specifies which origins can embed your CryptPad instance
|
||||||
|
# this must include 'self' and your main domain (over HTTPS) in order for CryptPad to work
|
||||||
|
# if you have enabled remote embedding via the admin panel then this must be more permissive.
|
||||||
|
# note: cryptpad.fr permits web pages served via https: and vector: (element desktop app)
|
||||||
|
set $frameAncestors "'self' https://${main_domain}";
|
||||||
|
# set $frameAncestors "'self' https: vector:";
|
||||||
|
|
||||||
|
set $unsafe 0;
|
||||||
|
# the following assets are loaded via the sandbox domain
|
||||||
|
# they unfortunately still require exceptions to the sandboxing to work correctly.
|
||||||
|
if ($uri ~ ^\/(sheet|doc|presentation)\/inner.html.*$) { set $unsafe 1; }
|
||||||
|
if ($uri ~ ^\/common\/onlyoffice\/.*\/.*\.html.*$) { set $unsafe 1; }
|
||||||
|
|
||||||
|
# everything except the sandbox domain is a privileged scope, as they might be used to handle keys
|
||||||
|
if ($host != $sandbox_domain) { set $unsafe 0; }
|
||||||
|
# this iframe is an exception. Office file formats are converted outside of the sandboxed scope
|
||||||
|
# because of bugs in Chromium-based browsers that incorrectly ignore headers that are supposed to enable
|
||||||
|
# the use of some modern APIs that we require when javascript is run in a cross-origin context.
|
||||||
|
# We've applied other sandboxing techniques to mitigate the risk of running WebAssembly in this privileged scope
|
||||||
|
if ($uri ~ ^\/unsafeiframe\/inner\.html.*$) { set $unsafe 1; }
|
||||||
|
|
||||||
|
# privileged contexts allow a few more rights than unprivileged contexts, though limits are still applied
|
||||||
|
if ($unsafe) {
|
||||||
|
set $scriptSrc "'self' 'unsafe-eval' 'unsafe-inline' resource: https://${main_domain}";
|
||||||
|
}
|
||||||
|
|
||||||
|
# Finally, set all the rules you composed above.
|
||||||
|
add_header Content-Security-Policy "default-src 'none'; child-src $childSrc; worker-src $workerSrc; media-src $mediaSrc; style-src $styleSrc; script-src $scriptSrc; connect-src $connectSrc; font-src $fontSrc; img-src $imgSrc; frame-src $frameSrc; frame-ancestors $frameAncestors";
|
||||||
|
|
||||||
|
# The nodejs process can handle all traffic whether accessed over websocket or as static assets
|
||||||
|
# We prefer to serve static content from nginx directly and to leave the API server to handle
|
||||||
|
# the dynamic content that only it can manage. This is primarily an optimization
|
||||||
|
location ^~ /cryptpad_websocket {
|
||||||
|
proxy_pass http://localhost:3000;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
|
||||||
|
# WebSocket support (nginx 1.4)
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection upgrade;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ^~ /api/ {
|
||||||
|
proxy_pass http://localhost:3000;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
|
||||||
|
# These settings prevent both NGINX and the API server
|
||||||
|
# from setting the same headers and creating duplicates
|
||||||
|
proxy_hide_header Cross-Origin-Resource-Policy;
|
||||||
|
add_header Cross-Origin-Resource-Policy cross-origin;
|
||||||
|
proxy_hide_header Cross-Origin-Embedder-Policy;
|
||||||
|
add_header Cross-Origin-Embedder-Policy require-corp;
|
||||||
|
}
|
||||||
|
|
||||||
|
# encrypted blobs are immutable and are thus cached for a year
|
||||||
|
location ^~ /blob/ {
|
||||||
|
root /home/cryptpad/data;
|
||||||
|
if ($request_method = 'OPTIONS') {
|
||||||
|
add_header Access-Control-Allow-Origin "${allowed_origins}";
|
||||||
|
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
|
||||||
|
add_header Access-Control-Allow-Headers 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
|
||||||
|
add_header Access-Control-Max-Age 1728000;
|
||||||
|
add_header Content-Type 'application/octet-stream; charset=utf-8';
|
||||||
|
add_header Content-Length 0;
|
||||||
|
return 204;
|
||||||
|
}
|
||||||
|
add_header Access-Control-Allow-Origin "${allowed_origins}";
|
||||||
|
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
|
||||||
|
add_header Access-Control-Allow-Headers 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
|
||||||
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
add_header Cache-Control max-age=31536000;
|
||||||
|
add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,Content-Length';
|
||||||
|
}
|
||||||
|
|
||||||
|
# the "block-store" serves encrypted payloads containing users' drive keys
|
||||||
|
# these payloads are unlocked via login credentials. They are mutable
|
||||||
|
# and are thus never cached. They're small enough that it doesn't matter, in any case.
|
||||||
|
location ^~ /block/ {
|
||||||
|
root /home/cryptpad/data;
|
||||||
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
add_header Cache-Control max-age=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
# The nodejs server has some built-in forwarding rules to prevent
|
||||||
|
# URLs like /pad from resulting in a 404. This simply adds a trailing slash
|
||||||
|
# to a variety of applications.
|
||||||
|
location ~ ^/(register|login|settings|user|pad|drive|poll|slide|code|whiteboard|file|media|profile|contacts|todo|filepicker|debug|kanban|sheet|support|admin|notifications|teams|calendar|presentation|doc|form|report|convert|checkup)$ {
|
||||||
|
return 301 https://${main_domain}/$1/;
|
||||||
|
}
|
||||||
|
|
||||||
|
# try to load customizeable content via /customize/ and fall back to the default content
|
||||||
|
# located at /customize.dist/
|
||||||
|
# This is what allows you to override behaviour.
|
||||||
|
location ~ /customize/(.*)$ {
|
||||||
|
rewrite ^/customize/(.*)$ $1 break;
|
||||||
|
try_files /customize/$uri /customize.dist/$uri;
|
||||||
|
#try_files /customize/$1 /customize.dist/$1 =404;
|
||||||
|
}
|
||||||
|
location ^~ /customize.dist/ {
|
||||||
|
# simply serve static files from root
|
||||||
|
}
|
||||||
|
|
||||||
|
# Finally, serve anything the above exceptions don't govern.
|
||||||
|
try_files /www/$uri /www/$uri/index.html /customize/$uri;
|
||||||
|
}
|
@ -0,0 +1,90 @@
|
|||||||
|
A custom self-hosted instance of [CryptPad](https://cryptpad.fr/) for qcode
|
||||||
|
infra, accessible at https://cryptpad.qcode.ch.
|
||||||
|
|
||||||
|
The upstream code lives in the [cryptpad](cryptpad/) sub directory. This
|
||||||
|
is placed as a git subtree, not to be confused with submodule. To customize
|
||||||
|
functionality or look&feel, copy a file from
|
||||||
|
[cryptpad/customize.dist](cryptpad/customize.dist/) into
|
||||||
|
[customize](customize/) and change it. The file will be served in place of
|
||||||
|
the original dist.
|
||||||
|
|
||||||
|
See [upstream docs](https://docs.cryptpad.fr/en/admin_guide/customization.html)
|
||||||
|
for customization details.
|
||||||
|
|
||||||
|
## Updating from upstream
|
||||||
|
|
||||||
|
Check the current status of the local cryptpad copy with:
|
||||||
|
|
||||||
|
git log cryptpad
|
||||||
|
|
||||||
|
Then go to https://github.com/xwiki-labs/cryptpad/commits/main and check where
|
||||||
|
the upstream is at.
|
||||||
|
|
||||||
|
To update local copy with upstream changes, use
|
||||||
|
[tools/pull-cryptpad-upstream.sh](tools/pull-cryptpad-upstream.sh) script.
|
||||||
|
For example, to pull up to an imaginary release tag xyz, execute:
|
||||||
|
|
||||||
|
./tools/pull-cryptpad-upstream.sh xyz
|
||||||
|
|
||||||
|
It'll fetch from upstream and add new commits as if they were part of this repo.
|
||||||
|
Finally, `git push` to update this repo's remote.
|
||||||
|
|
||||||
|
If instead you want to make a pull request, first create a branch. Something like
|
||||||
|
`git checkout -b upstream-update-xyz master` should do. Then execute the above
|
||||||
|
script and send the branch as a pull request.
|
||||||
|
|
||||||
|
For the record, initial subtree merge from upstream was done with the following
|
||||||
|
command:
|
||||||
|
|
||||||
|
git subtree add -P cryptpad https://github.com/xwiki-labs/cryptpad.git 4.14.0
|
||||||
|
|
||||||
|
## Contributing to upstream
|
||||||
|
|
||||||
|
You'll probably want to have a separate repository, cloned directly from the
|
||||||
|
upstream `https://github.com/xwiki-labs/cryptpad.git`. Since this repo's
|
||||||
|
cryptpad dir is a copy of the upstream repo, it should be very easy to apply
|
||||||
|
changes to both using patch files and `git apply` or `patch` commands.
|
||||||
|
|
||||||
|
See details on [how to contribute](https://docs.cryptpad.fr/en/how_to_contribute.html)
|
||||||
|
in the upstream docs.
|
||||||
|
|
||||||
|
## Dev environment
|
||||||
|
|
||||||
|
To start a local dev instance, forget about the files in the root of this repo
|
||||||
|
and simply work in the [cryptpad](cryptpad/) sub directory. In other words,
|
||||||
|
follow [upstream dev guide](https://docs.cryptpad.fr/en/dev_guide/setup.html).
|
||||||
|
|
||||||
|
When done, a `git diff` will show some changes. Those in the `cryptpad/` sub
|
||||||
|
directory should go to upstream. Anything else, notably the [customize](customize/)
|
||||||
|
directory, lives in this repo.
|
||||||
|
|
||||||
|
## Production instance
|
||||||
|
|
||||||
|
To build for prod deployment, you'll need [podman](https://podman.io).
|
||||||
|
Create prod build artifacts manually with:
|
||||||
|
|
||||||
|
./tools/build-prod.sh
|
||||||
|
|
||||||
|
The script creates few files in the `build` directory. Notably, the two files
|
||||||
|
required for prod deployment are:
|
||||||
|
|
||||||
|
- `cryptpad-container-img-<git-commit-hash>.tar.gz`: container file with
|
||||||
|
the nodejs server
|
||||||
|
- `cryptpad-static-<git-commit-hash>.tar.gz`: static files served by
|
||||||
|
nginx frontend
|
||||||
|
|
||||||
|
Copy both files to production machines. The `cryptpad-container-img.tar.gz` can
|
||||||
|
be loaded on the machine with:
|
||||||
|
|
||||||
|
podman load path/to/cryptpad-container-img.tar.gz
|
||||||
|
|
||||||
|
Unpack the static files into a temp dir and sync with the prod dir:
|
||||||
|
|
||||||
|
rsync -rl --chown root:root --delete-after tmpdir/ path/to/proddir/
|
||||||
|
|
||||||
|
There are also a couple of config files, `config.js` and `nginx.conf`, in the root
|
||||||
|
of this repo. These are production configs and will eventually move to
|
||||||
|
another location with all the other prod infra configs.
|
||||||
|
|
||||||
|
All the manual steps described above will disappear once a central prod infra
|
||||||
|
is in place.
|
@ -0,0 +1,47 @@
|
|||||||
|
#!/bin/sh -e
|
||||||
|
PODMAN=podman
|
||||||
|
if ! type podman > /dev/null; then
|
||||||
|
printf "$0 requires podman; see https://podman.io\n" 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
cd $(dirname $0)/..
|
||||||
|
|
||||||
|
# all build artifacts are stored with this version suffix
|
||||||
|
VERSION=$(git rev-parse --short HEAD)
|
||||||
|
mkdir -p build
|
||||||
|
|
||||||
|
# cryptpad's node server needs a couple files from www/common.
|
||||||
|
# it also needs 404.html and 500.html from customize[.dist], otherwise
|
||||||
|
# the express server hogs CPU at 100% if a request hits a nonexistent file.
|
||||||
|
# the customize dir must be mounted in read-only at container start.
|
||||||
|
tar -cf build/bootstrap.tar \
|
||||||
|
-C cryptpad \
|
||||||
|
.bowerrc \
|
||||||
|
bower.json \
|
||||||
|
lib \
|
||||||
|
package-lock.json \
|
||||||
|
package.json \
|
||||||
|
scripts \
|
||||||
|
server.js \
|
||||||
|
LICENSE
|
||||||
|
mkdir -p cryptpad/www/bower_components
|
||||||
|
$PODMAN build --rm --squash --net=host \
|
||||||
|
-v $PWD/cryptpad/www/bower_components:/build/www/bower_components \
|
||||||
|
-t cryptpad .
|
||||||
|
$PODMAN save cryptpad | gzip > build/cryptpad-container-img-$VERSION.tar.gz
|
||||||
|
|
||||||
|
# static files served by an HTTP frontend, as well as the customize dir
|
||||||
|
# required by the node server run in a container image.
|
||||||
|
STATIC_TAR_OUT=build/cryptpad-static-$VERSION.tar
|
||||||
|
tar -cf $STATIC_TAR_OUT \
|
||||||
|
-C cryptpad \
|
||||||
|
customize.dist \
|
||||||
|
www \
|
||||||
|
LICENSE
|
||||||
|
# append custom files, in a separate step to preserve desired file
|
||||||
|
# tree structure.
|
||||||
|
tar -rf $STATIC_TAR_OUT customize
|
||||||
|
printf "${VERSION}" > build/commit.txt
|
||||||
|
tar -rf $STATIC_TAR_OUT -C build commit.txt
|
||||||
|
# finally, gzip the archive for faster transfer/deployment.
|
||||||
|
gzip -f $STATIC_TAR_OUT
|
@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
REPO="https://github.com/xwiki-labs/cryptpad.git"
|
||||||
|
PREFIX=cryptpad
|
||||||
|
REF="${1}"
|
||||||
|
if [ -z "${ref}" ]; then
|
||||||
|
printf "usage: $0 <ref>\n" 1>&2
|
||||||
|
printf "ref: main, tag, branch or commit hash\n" 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
cd $(dirname $0)/..
|
||||||
|
exec git subtree pull -P "${PREFIX}" "${REPO}" "${REF}"
|
Loading…
Reference in New Issue