diff --git a/Dockerfile b/Dockerfile
index fa6b34e10..c8b752d54 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -25,8 +25,6 @@ RUN rm /usr/share/nginx/html/*
COPY --from=builder /opt/threema-web/release/threema-web-* /usr/share/nginx/html/
COPY docker/entrypoint.sh /usr/local/bin/
-ENV SALTYRTC_HOST="" \
- SALTYRTC_PORT=443 \
- SALTYRTC_SERVER_KEY="b1337fc8402f7db8ea639e05ed05d65463e24809792f91eca29e88101b4a2171"
+EXPOSE 80
CMD ["/bin/sh", "/usr/local/bin/entrypoint.sh"]
diff --git a/README.md b/README.md
index c4a2526a4..71197d769 100644
--- a/README.md
+++ b/README.md
@@ -124,9 +124,10 @@ You can also install a pre-push hook to do the linting:
## Configuration
-The configuration of Threema Web can be tweaked in `src/config.ts`:
+The configuration of Threema Web can be tweaked in `src/config.ts` and
+`src/userconfig.js`:
-**General**
+**General (Config)**
- `SELF_HOSTED`: Set this to `true` if this instance of Threema Web isn't being
hosted on `web.threema.ch`.
@@ -135,7 +136,7 @@ The configuration of Threema Web can be tweaked in `src/config.ts`:
previous protocol version. If set to something different than `null`, a
message will be shown to the user if reconnecting fails.
-**SaltyRTC**
+**SaltyRTC (Userconfig)**
- `SALTYRTC_HOST`: Set this to the hostname of the SaltyRTC server that you
want to use. If supplied, the substring `{prefix}` will be replaced by the
@@ -146,16 +147,24 @@ The configuration of Threema Web can be tweaked in `src/config.ts`:
this value to `null` if your server does not provide a public permanent key,
or if you don't want to verify it.
-**ICE**
+**ICE (Userconfig)**
- `ICE_SERVERS`: Configuration object for the WebRTC STUN and ICE servers.
Each URL may contain the substring `{prefix}`, which will be replaced by a
random byte represented as a lowercase hexadecimal value.
-**Push**
+**Push (Userconfig)**
- `PUSH_URL`: The server URL used to deliver push notifications to the app.
+**Fonts (Userconfig)**
+
+Note: If you want to use the Lab Grotesque font in your self-hosted instance
+(with SELF_HOSTED=true), you need to obtain a license for it and update the
+font URL below. Otherwise, Threema Web will fall back to Roboto.
+
+- `FONT_CSS_URL`: URL to the Lab Grotesque font.
+
## Self Hosting
diff --git a/dist/package.sh b/dist/package.sh
index e9e00dcb9..0dd52bcc5 100755
--- a/dist/package.sh
+++ b/dist/package.sh
@@ -45,8 +45,8 @@ mkdir -p $DIR/{partials,directives,components,node_modules,partials/messenger.re
echo "+ Copy code..."
cp -R index.html $DIR/
-cp -R dist/generated/*.bundle.js $DIR/
-cp -R dist/generated/*.bundle.js.map $DIR/
+cp -R dist/generated/*.js $DIR/
+cp -R dist/generated/*.js.map $DIR/
cp -R dist/generated/*.wasm $DIR/
cp -R public/* $DIR/
cp -R troubleshoot/* $DIR/troubleshoot/
diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh
index 916bd9515..5530c2c94 100644
--- a/docker/entrypoint.sh
+++ b/docker/entrypoint.sh
@@ -2,13 +2,22 @@
set -euo pipefail
# Patch config file
-echo "Patching config file..."
+echo "Patching userconfig file..."
cd /usr/share/nginx/html/
-if [ ! -z "$SALTYRTC_HOST" ]; then
- sed -i -E "s/SALTYRTC_HOST:\s*null,/SALTYRTC_HOST:'${SALTYRTC_HOST}',/g" *.bundle.js
+if [[ ! -f userconfig.js ]]; then
+ echo "Error: Userconfig not found"
+ exit 1
+fi
+echo '// Overrides by entrypoint.sh' >> userconfig.js
+if [ ! -z "${SALTYRTC_HOST:-}" ]; then
+ echo "window.UserConfig.SALTYRTC_HOST = '${SALTYRTC_HOST}';" >> userconfig.js
+fi
+if [ ! -z "${SALTYRTC_PORT:-}" ]; then
+ echo "window.UserConfig.SALTYRTC_PORT = ${SALTYRTC_PORT};" >> userconfig.js
+fi
+if [ ! -z "${SALTYRTC_SERVER_KEY:-}" ]; then
+ echo "window.UserConfig.SALTYRTC_SERVER_KEY = '${SALTYRTC_SERVER_KEY}';" >> userconfig.js
fi
-sed -i -E "s/SALTYRTC_PORT:\s*[^,]*,/SALTYRTC_PORT:${SALTYRTC_PORT},/g" *.bundle.js
-sed -i -E "s/SALTYRTC_SERVER_KEY:\s*\"[^\"]*\",/SALTYRTC_SERVER_KEY:\"${SALTYRTC_SERVER_KEY}\",/g" *.bundle.js
# Add nginx mime type for wasm
# See https://trac.nginx.org/nginx/ticket/1606
diff --git a/docs/docker.md b/docs/docker.md
index 2239779f8..adc4486e8 100644
--- a/docs/docker.md
+++ b/docs/docker.md
@@ -21,7 +21,8 @@ mechanisms in your web server.
## Config Variables
-- `SALTYRTC_HOST`: The SaltyRTC signaling server hostname (default `null`)
+- `SALTYRTC_HOST`: The SaltyRTC signaling server hostname
+ (default `saltyrtc-{prefix}.threema.ch`)
- `SALTYRTC_PORT`: The SaltyRTC signaling server port (default `443`)
- `SALTYRTC_SERVER_KEY`: The SaltyRTC signaling server public key
(default `"b1337fc8402f7db8ea639e05ed05d65463e24809792f91eca29e88101b4a2171"`)
diff --git a/index.html b/index.html
index 3b43419d1..10e3bd604 100644
--- a/index.html
+++ b/index.html
@@ -167,6 +167,7 @@
+
diff --git a/package-lock.json b/package-lock.json
index 0a85a0a80..66b453093 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1616,7 +1616,6 @@
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
- "dev": true,
"requires": {
"@nodelib/fs.stat": "2.0.5",
"run-parallel": "^1.1.9"
@@ -1625,14 +1624,12 @@
"@nodelib/fs.stat": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
- "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
- "dev": true
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="
},
"@nodelib/fs.walk": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
- "dev": true,
"requires": {
"@nodelib/fs.scandir": "2.1.5",
"fastq": "^1.6.0"
@@ -2254,8 +2251,7 @@
"array-union": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
- "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
- "dev": true
+ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="
},
"arrify": {
"version": "1.0.1",
@@ -3150,6 +3146,37 @@
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=",
"dev": true
},
+ "copy-webpack-plugin": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-9.1.0.tgz",
+ "integrity": "sha512-rxnR7PaGigJzhqETHGmAcxKnLZSR5u1Y3/bcIv/1FnqXedcL/E2ewK7ZCNrArJKCiSv8yVXhTqetJh8inDvfsA==",
+ "requires": {
+ "fast-glob": "^3.2.7",
+ "glob-parent": "^6.0.1",
+ "globby": "^11.0.3",
+ "normalize-path": "^3.0.0",
+ "schema-utils": "^3.1.1",
+ "serialize-javascript": "^6.0.0"
+ },
+ "dependencies": {
+ "glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "requires": {
+ "is-glob": "^4.0.3"
+ }
+ },
+ "is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "requires": {
+ "is-extglob": "^2.1.1"
+ }
+ }
+ }
+ },
"core-js": {
"version": "3.18.3",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.18.3.tgz",
@@ -3413,7 +3440,6 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
- "dev": true,
"requires": {
"path-type": "^4.0.0"
}
@@ -3811,7 +3837,6 @@
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz",
"integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==",
- "dev": true,
"requires": {
"@nodelib/fs.stat": "^2.0.2",
"@nodelib/fs.walk": "^1.2.3",
@@ -3824,7 +3849,6 @@
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
- "dev": true,
"requires": {
"fill-range": "^7.0.1"
}
@@ -3833,7 +3857,6 @@
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "dev": true,
"requires": {
"to-regex-range": "^5.0.1"
}
@@ -3841,14 +3864,12 @@
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
},
"micromatch": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
"integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==",
- "dev": true,
"requires": {
"braces": "^3.0.1",
"picomatch": "^2.2.3"
@@ -3857,14 +3878,12 @@
"picomatch": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
- "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
- "dev": true
+ "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw=="
},
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
"requires": {
"is-number": "^7.0.0"
}
@@ -3885,7 +3904,6 @@
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
"integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
- "dev": true,
"requires": {
"reusify": "^1.0.4"
}
@@ -4190,7 +4208,6 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dev": true,
"requires": {
"is-glob": "^4.0.1"
}
@@ -4209,7 +4226,6 @@
"version": "11.0.4",
"resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz",
"integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==",
- "dev": true,
"requires": {
"array-union": "^2.1.0",
"dir-glob": "^3.0.1",
@@ -4546,8 +4562,7 @@
"ignore": {
"version": "5.1.8",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz",
- "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==",
- "dev": true
+ "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw=="
},
"immediate": {
"version": "3.0.6",
@@ -4691,8 +4706,7 @@
"is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
- "dev": true
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
},
"is-fullwidth-code-point": {
"version": "1.0.0",
@@ -4706,7 +4720,6 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
"integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
- "dev": true,
"requires": {
"is-extglob": "^2.1.1"
}
@@ -5387,8 +5400,7 @@
"merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
- "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
- "dev": true
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="
},
"messageformat": {
"version": "2.3.0",
@@ -5707,8 +5719,7 @@
"normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
- "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
- "dev": true
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
},
"normalize-url": {
"version": "6.1.0",
@@ -5946,8 +5957,7 @@
"path-type": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
- "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
- "dev": true
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="
},
"pathval": {
"version": "1.1.1",
@@ -6062,8 +6072,7 @@
"queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
- "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
- "dev": true
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="
},
"quick-lru": {
"version": "4.0.1",
@@ -6429,8 +6438,7 @@
"reusify": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
- "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
- "dev": true
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="
},
"rfdc": {
"version": "1.3.0",
@@ -6442,7 +6450,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
- "dev": true,
"requires": {
"queue-microtask": "^1.2.2"
}
@@ -6694,8 +6701,7 @@
"slash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="
},
"socket.io": {
"version": "4.3.1",
diff --git a/package.json b/package.json
index 3359ecf08..e3b7f1889 100644
--- a/package.json
+++ b/package.json
@@ -62,6 +62,7 @@
"angularjs-scroll-glue": "=2.1.0",
"autolinker": "^3.14.3",
"babel-loader": "^8.2.3",
+ "copy-webpack-plugin": "^9.1.0",
"core-js": "^3.18.3",
"croppie": "^2.6.5",
"emojibase-regex": "^4.1.1",
diff --git a/src/config.ts b/src/config.ts
index bdd46b1e8..c2fa62110 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -3,6 +3,7 @@
*
* The various options are explained in the `README.md` file.
*/
+
// tslint:disable:max-line-length
export default {
// Version
@@ -18,32 +19,6 @@ export default {
PREV_PROTOCOL_LAST_VERSION: '1.8.2',
GIT_BRANCH: 'master',
- // SaltyRTC
- SALTYRTC_HOST: 'saltyrtc-{prefix}.threema.ch',
- SALTYRTC_PORT: 443,
- SALTYRTC_SERVER_KEY: 'b1337fc8402f7db8ea639e05ed05d65463e24809792f91eca29e88101b4a2171',
-
- // ICE
- ICE_SERVERS: [{
- urls: [
- 'turn:ds-turn-{prefix}.threema.ch:443?transport=udp',
- 'turn:ds-turn-{prefix}.threema.ch:443?transport=tcp',
- 'turns:ds-turn-{prefix}.threema.ch:443',
- ],
- username: 'threema-angular',
- credential: 'Uv0LcCq3kyx6EiRwQW5jVigkhzbp70CjN2CJqzmRxG3UGIdJHSJV6tpo7Gj7YnGB',
- }],
-
- // Push
- PUSH_URL: 'https://push-web.threema.ch/push',
-
- // Fonts
- // Note: If you want to use the Lab Grotesque font in your self-hosted
- // instance (with SELF_HOSTED=true), you need to obtain a license for
- // it and update the font URL below. Otherwise, Threema Web will
- // fall back to Roboto.
- FONT_CSS_URL: null,
-
// Padding length (in characters) of the log tag
// Note: The padding will be stripped by the report log.
LOG_TAG_PADDING: 20,
diff --git a/src/controllers/header.ts b/src/controllers/header.ts
index b1b0a4424..2b0ae3ff8 100644
--- a/src/controllers/header.ts
+++ b/src/controllers/header.ts
@@ -21,10 +21,13 @@
export class HeaderController {
// Config
private config: threema.Config;
+ private userConfig: threema.UserConfig;
public static $inject = ['CONFIG'];
constructor(config: threema.Config) {
this.config = config;
+ // tslint:disable-next-line: no-string-literal
+ this.userConfig = window['UserConfig'];
}
/**
@@ -33,17 +36,17 @@ export class HeaderController {
public useThreemaFont(): boolean {
// In the officially hosted version, the Threema font is loaded from static.threema.ch.
// In a self-hosted version, a custom font URL needs to be provided.
- return !this.config.SELF_HOSTED || this.config.FONT_CSS_URL !== null;
+ return !this.config.SELF_HOSTED || this.userConfig.FONT_CSS_URL !== null;
}
/**
* Return the URL to the Threema font (Lab Grotesque).
*/
public fontUrl(): string {
- if (this.config.FONT_CSS_URL === null) {
+ if (this.userConfig.FONT_CSS_URL === null) {
return 'https://static.threema.ch/fonts/labgrotesque.css';
} else {
- return this.config.FONT_CSS_URL;
+ return this.userConfig.FONT_CSS_URL;
}
}
}
diff --git a/src/controllers/troubleshooting.ts b/src/controllers/troubleshooting.ts
index 145b4a7ba..eb9dc7d11 100644
--- a/src/controllers/troubleshooting.ts
+++ b/src/controllers/troubleshooting.ts
@@ -192,8 +192,10 @@ export class TroubleshootingController extends DialogController {
// Sanitise usernames and credentials from ICE servers in config
const config = copyShallow(this.config) as threema.Config;
+ // tslint:disable-next-line: no-string-literal
+ const userConfig = copyShallow(window['UserConfig']) as threema.UserConfig;
if (sanitize) {
- config.ICE_SERVERS = config.ICE_SERVERS.map((server: RTCIceServer) => {
+ userConfig.ICE_SERVERS = userConfig.ICE_SERVERS.map((server: RTCIceServer) => {
server = copyShallow(server) as RTCIceServer;
for (const key of ['username', 'credential', 'credentialType']) {
if (server[key] !== undefined) {
@@ -207,6 +209,7 @@ export class TroubleshootingController extends DialogController {
// Create container for meta data and log records
const container = {
config: config,
+ userConfig: userConfig,
browser: browser.description(),
log: this.logService.memory.getRecords(),
};
diff --git a/src/services/push.ts b/src/services/push.ts
index ab11f8df5..c6a29e91a 100644
--- a/src/services/push.ts
+++ b/src/services/push.ts
@@ -247,8 +247,6 @@ export class PushSession {
}
export class PushService {
- public static readonly $inject = ['CONFIG', 'PROTOCOL_VERSION', 'LogService'];
-
public static readonly ARG_TYPE = 'type';
public static readonly ARG_TOKEN = 'token';
public static readonly ARG_SESSION = 'session';
@@ -268,9 +266,12 @@ export class PushService {
private _pushToken: string = null;
private _pushType = threema.PushTokenType.Fcm;
+ public static readonly $inject = ['CONFIG', 'PROTOCOL_VERSION', 'LogService'];
constructor(CONFIG: threema.Config, PROTOCOL_VERSION: number, logService: LogService) {
this.config = CONFIG;
- this.url = CONFIG.PUSH_URL;
+ // tslint:disable-next-line: no-string-literal
+ const userConfig: threema.UserConfig = window['UserConfig'];
+ this.url = userConfig.PUSH_URL;
this.version = PROTOCOL_VERSION;
this.logService = logService;
this.log = logService.getLogger(`Push-S`, 'color: #fff; background-color: #9900ff');
diff --git a/src/services/webclient.ts b/src/services/webclient.ts
index b88c1e171..5ea8b8f30 100644
--- a/src/services/webclient.ts
+++ b/src/services/webclient.ts
@@ -262,6 +262,7 @@ export class WebClientService {
// Other
private config: threema.Config;
+ private userConfig: threema.UserConfig;
private container: threema.Container.Factory;
private typingInstance: threema.Container.Typing;
private drafts: threema.Container.Drafts;
@@ -349,6 +350,8 @@ export class WebClientService {
// Configuration object
this.config = CONFIG;
+ // tslint:disable-next-line: no-string-literal
+ this.userConfig = window['UserConfig'];
// Logging
this.log = logService.getLogger('WebClient-S', 'color: #fff; background-color: #0066cc');
@@ -441,8 +444,8 @@ export class WebClientService {
return this.qrCodeService.buildQrCodePayload(
this.salty.permanentKeyBytes,
this.salty.authTokenBytes,
- hexToU8a(this.config.SALTYRTC_SERVER_KEY),
- this.saltyRtcHost, this.config.SALTYRTC_PORT,
+ hexToU8a(this.userConfig.SALTYRTC_SERVER_KEY),
+ this.saltyRtcHost, this.userConfig.SALTYRTC_PORT,
persistent);
}
@@ -533,13 +536,13 @@ export class WebClientService {
}
// Determine SaltyRTC host, replace the inner prefix (if any)
- this.saltyRtcHost = this.config.SALTYRTC_HOST.replace('{prefix}', keyStore.publicKeyHex.substr(0, 2));
+ this.saltyRtcHost = this.userConfig.SALTYRTC_HOST.replace('{prefix}', keyStore.publicKeyHex.substr(0, 2));
// Create SaltyRTC client
let builder = new saltyrtcClient.SaltyRTCBuilder()
- .connectTo(this.saltyRtcHost, this.config.SALTYRTC_PORT)
+ .connectTo(this.saltyRtcHost, this.userConfig.SALTYRTC_PORT)
.withLoggingLevel(this.config.SALTYRTC_LOG_LEVEL)
- .withServerKey(this.config.SALTYRTC_SERVER_KEY)
+ .withServerKey(this.userConfig.SALTYRTC_SERVER_KEY)
.withKeyStore(keyStore)
.usingTasks(tasks)
.withPingInterval(30);
@@ -895,7 +898,7 @@ export class WebClientService {
// Determine ICE servers and replace random prefix (if any)
const prefix = u8aToHex(nacl.randomBytes(1));
- const iceServers = this.config.ICE_SERVERS.map((server) => {
+ const iceServers = this.userConfig.ICE_SERVERS.map((server) => {
server = copyShallow(server) as RTCIceServer;
const urls = Array.isArray(server.urls) ? server.urls : [server.urls];
server.urls = urls.map((url) => url.replace('{prefix}', prefix));
diff --git a/src/threema.d.ts b/src/threema.d.ts
index d1dcdd8b7..11e047ed1 100644
--- a/src/threema.d.ts
+++ b/src/threema.d.ts
@@ -663,20 +663,6 @@ declare namespace threema {
PREV_PROTOCOL_LAST_VERSION: string | null;
GIT_BRANCH: string;
- // SaltyRTC
- SALTYRTC_HOST: string;
- SALTYRTC_PORT: number;
- SALTYRTC_SERVER_KEY: string | null;
-
- // ICE
- ICE_SERVERS: RTCIceServer[];
-
- // Push
- PUSH_URL: string;
-
- // Fonts
- FONT_CSS_URL: string;
-
// Logging/debugging
LOG_TAG_PADDING: number,
CONSOLE_LOG_LEVEL: LogLevel;
@@ -693,6 +679,22 @@ declare namespace threema {
IN_MEMORY_SESSION_PASSWORD: boolean;
}
+ interface UserConfig {
+ // SaltyRTC
+ SALTYRTC_HOST: string;
+ SALTYRTC_PORT: number;
+ SALTYRTC_SERVER_KEY: string | null;
+
+ // ICE
+ ICE_SERVERS: RTCIceServer[];
+
+ // Push
+ PUSH_URL: string;
+
+ // Fonts
+ FONT_CSS_URL: string;
+ }
+
interface InitialConversationData {
draft: string;
initialText: string;
diff --git a/src/userconfig.js b/src/userconfig.js
new file mode 100644
index 000000000..9f3c6d6f5
--- /dev/null
+++ b/src/userconfig.js
@@ -0,0 +1,33 @@
+/**
+ * Threema Web configuration.
+ *
+ * The various options are explained in the `README.md` file.
+ */
+
+window.UserConfig = {
+ // SaltyRTC
+ SALTYRTC_HOST: 'saltyrtc-{prefix}.threema.ch',
+ SALTYRTC_PORT: 443,
+ SALTYRTC_SERVER_KEY: 'b1337fc8402f7db8ea639e05ed05d65463e24809792f91eca29e88101b4a2171',
+
+ // ICE
+ ICE_SERVERS: [{
+ urls: [
+ 'turn:ds-turn-{prefix}.threema.ch:443?transport=udp',
+ 'turn:ds-turn-{prefix}.threema.ch:443?transport=tcp',
+ 'turns:ds-turn-{prefix}.threema.ch:443',
+ ],
+ username: 'threema-angular',
+ credential: 'Uv0LcCq3kyx6EiRwQW5jVigkhzbp70CjN2CJqzmRxG3UGIdJHSJV6tpo7Gj7YnGB',
+ }],
+
+ // Push
+ PUSH_URL: 'https://push-web.threema.ch/push',
+
+ // Fonts
+ // Note: If you want to use the Lab Grotesque font in your self-hosted
+ // instance (with SELF_HOSTED=true), you need to obtain a license for
+ // it and update the font URL below. Otherwise, Threema Web will
+ // fall back to Roboto.
+ FONT_CSS_URL: null,
+};
diff --git a/troubleshoot/log.html b/troubleshoot/log.html
index 9b83e955f..495258611 100644
--- a/troubleshoot/log.html
+++ b/troubleshoot/log.html
@@ -78,7 +78,7 @@
display: inline-block;
}
- #config {
+ .config {
background-color: #fafafa;
border: 1px solid #e0e0e0;
padding: 8px;
@@ -180,7 +180,12 @@ Browser:
Config
-
+
+
+
+
+ Userconfig
+
Log
diff --git a/troubleshoot/log.js b/troubleshoot/log.js
index 9e03b00a3..6581919b9 100644
--- a/troubleshoot/log.js
+++ b/troubleshoot/log.js
@@ -10,6 +10,7 @@ const elements = {
container: document.querySelector('#container'),
browser: document.querySelector('#browser'),
config: document.querySelector('#config'),
+ userConfig: document.querySelector('#userconfig'),
log: document.querySelector('#log'),
};
@@ -125,6 +126,7 @@ function showLog(data) {
// Display meta data
elements.browser.textContent = container.browser;
elements.config.textContent = JSON.stringify(container.config, null, 2);
+ elements.userConfig.textContent = JSON.stringify(container.userConfig, null, 2);
// Display log records
elements.log.innerHTML = '';
diff --git a/webpack.common.js b/webpack.common.js
index 8e4e1732e..3bf0488e6 100644
--- a/webpack.common.js
+++ b/webpack.common.js
@@ -1,5 +1,6 @@
const path = require('path');
const webpack = require('webpack');
+const CopyPlugin = require("copy-webpack-plugin");
const babelOptions = {
presets: [
@@ -49,6 +50,17 @@ module.exports = {
resolve: {
extensions: ['.js', '.ts', '.wasm'],
},
+ plugins: [
+ new CopyPlugin({
+ patterns: [
+ {
+ from: 'src/userconfig.js',
+ to: path.resolve(__dirname, 'dist', 'generated'),
+ info: { minimized: true /* Do not minimize / uglify */ },
+ },
+ ],
+ }),
+ ],
output: {
path: path.resolve(__dirname, 'dist', 'generated'),
filename: '[name].bundle.js',