mirror of
https://gitlab.com/timvisee/send.git
synced 2025-12-06 14:10:53 +03:00
Compare commits
116 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b346e3e3ae | ||
|
|
aea428372d | ||
|
|
ea8efb9d93 | ||
|
|
2b7164f589 | ||
|
|
08399059e9 | ||
|
|
aea40fa11b | ||
|
|
e51c753c0d | ||
|
|
6520d71faa | ||
|
|
97b0b10863 | ||
|
|
50e76e0895 | ||
|
|
610e036e26 | ||
|
|
e695a8b481 | ||
|
|
d33ddf643b | ||
|
|
512bd32368 | ||
|
|
3c42de0efd | ||
|
|
b7582230cf | ||
|
|
592ff3fb4a | ||
|
|
927203cb96 | ||
|
|
48237807fa | ||
|
|
38a4552d52 | ||
|
|
9d2d81e063 | ||
|
|
81d6c90c4e | ||
|
|
2bdaa0c4bd | ||
|
|
00d3bebc27 | ||
|
|
ea384ff5d3 | ||
|
|
062c439ec0 | ||
|
|
54e528980b | ||
|
|
b9292abefe | ||
|
|
1520942ac9 | ||
|
|
0e17cd567c | ||
|
|
7b21b199c2 | ||
|
|
6214b07a30 | ||
|
|
941d87976b | ||
|
|
8db3fed6fb | ||
|
|
78ca1f06e0 | ||
|
|
9fdc079878 | ||
|
|
f08d078236 | ||
|
|
46ae4a220b | ||
|
|
d0932c26ea | ||
|
|
798c399a38 | ||
|
|
825e3942a2 | ||
|
|
755459f57e | ||
|
|
42f5ca9701 | ||
|
|
1a923d21b5 | ||
|
|
3bd9f00c25 | ||
|
|
fa1c64369f | ||
|
|
9280f47afc | ||
|
|
3707b90d09 | ||
|
|
21392f1157 | ||
|
|
680d3ed948 | ||
|
|
dee1e84e58 | ||
|
|
214191e743 | ||
|
|
84da34169d | ||
|
|
93e1d2f41a | ||
|
|
43e1845d28 | ||
|
|
c01d6b73ea | ||
|
|
a394fd995e | ||
|
|
175712cfbd | ||
|
|
e5d7378fd9 | ||
|
|
20cf722b54 | ||
|
|
1d6872e279 | ||
|
|
a1ca355771 | ||
|
|
dc816d0e59 | ||
|
|
d6ac469e1a | ||
|
|
62cfecd618 | ||
|
|
9152d22913 | ||
|
|
21b198fbd5 | ||
|
|
0ffc960523 | ||
|
|
77ea05a233 | ||
|
|
a6162f7142 | ||
|
|
4a6a3dfc36 | ||
|
|
1e7efe3d98 | ||
|
|
46381fd516 | ||
|
|
1fe74f2be0 | ||
|
|
35da83bf2a | ||
|
|
bcfb9c5d09 | ||
|
|
4df2578bb1 | ||
|
|
e4f2955eae | ||
|
|
72377d3438 | ||
|
|
512c9803bd | ||
|
|
4c45d6217d | ||
|
|
b4b8060a78 | ||
|
|
ed042b8515 | ||
|
|
06bc58c93c | ||
|
|
b58caed44f | ||
|
|
174ade1c2e | ||
|
|
31ce8c048b | ||
|
|
ce401881d7 | ||
|
|
c49e8e1062 | ||
|
|
15648157c9 | ||
|
|
4280edd5af | ||
|
|
a3d4e2c502 | ||
|
|
bed5443685 | ||
|
|
f9f5d77cd0 | ||
|
|
0f8a6a107a | ||
|
|
02e8cb264f | ||
|
|
385ac595b9 | ||
|
|
6df0876286 | ||
|
|
827a35f73e | ||
|
|
eb3a9e8c89 | ||
|
|
6c3ac403f6 | ||
|
|
1ce2a60dd5 | ||
|
|
f5bb74e921 | ||
|
|
352fba6302 | ||
|
|
ace2aa5d73 | ||
|
|
3256b01276 | ||
|
|
96244132c6 | ||
|
|
a9cdd13543 | ||
|
|
1b6c5b8f97 | ||
|
|
27e6606516 | ||
|
|
4902d304b6 | ||
|
|
a182ff2dd1 | ||
|
|
0361e3ce1c | ||
|
|
32539e58ac | ||
|
|
eeb1359d90 | ||
|
|
e2dde364eb |
4
.gitattributes
vendored
4
.gitattributes
vendored
@@ -1,2 +1,2 @@
|
|||||||
public/locales/* linguist-documentation
|
public/locales/*/*.ftl linguist-documentation
|
||||||
docs/* linguist-documentation
|
docs/** linguist-documentation
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,6 +1,7 @@
|
|||||||
node_modules
|
node_modules
|
||||||
coverage
|
coverage
|
||||||
dist
|
dist
|
||||||
|
.env
|
||||||
.idea
|
.idea
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.nyc_output
|
.nyc_output
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ Cynthia Pereira
|
|||||||
Daniel Thorn
|
Daniel Thorn
|
||||||
Daniela Arcese
|
Daniela Arcese
|
||||||
Danny Coates
|
Danny Coates
|
||||||
|
David Dumas
|
||||||
Davide
|
Davide
|
||||||
Derek Tamsen
|
Derek Tamsen
|
||||||
Dhyey Thakore
|
Dhyey Thakore
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
|
|
||||||
# Build project
|
# Build project
|
||||||
FROM node:15.5.1-alpine AS builder
|
FROM node:16.13-alpine3.13 AS builder
|
||||||
RUN set -x \
|
RUN set -x \
|
||||||
# Add user
|
# Add user
|
||||||
&& addgroup --gid 10001 app \
|
&& addgroup --gid 10001 app \
|
||||||
@@ -26,7 +26,7 @@ RUN set -x \
|
|||||||
|
|
||||||
|
|
||||||
# Main image
|
# Main image
|
||||||
FROM node:15.5.1-alpine
|
FROM node:16.13-alpine3.13
|
||||||
RUN set -x \
|
RUN set -x \
|
||||||
# Add user
|
# Add user
|
||||||
&& addgroup --gid 10001 app \
|
&& addgroup --gid 10001 app \
|
||||||
|
|||||||
13
README.md
13
README.md
@@ -1,4 +1,4 @@
|
|||||||
# [](https://gitlab.com/timvisee/send/) Send
|
# [](https://gitlab.com/timvisee/send/) Send
|
||||||
|
|
||||||
[![Build status on GitLab CI][gitlab-ci-master-badge]][gitlab-ci-link]
|
[![Build status on GitLab CI][gitlab-ci-master-badge]][gitlab-ci-link]
|
||||||
[![Latest release][release-badge]][release-link]
|
[![Latest release][release-badge]][release-link]
|
||||||
@@ -81,7 +81,7 @@ A file sharing experiment which allows you to send encrypted files to other user
|
|||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- [Node.js 12.x](https://nodejs.org/)
|
- [Node.js 16.x](https://nodejs.org/)
|
||||||
- [Redis server](https://redis.io/) (optional for development)
|
- [Redis server](https://redis.io/) (optional for development)
|
||||||
- [AWS S3](https://aws.amazon.com/s3/) or compatible service (optional)
|
- [AWS S3](https://aws.amazon.com/s3/) or compatible service (optional)
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ The server is configured with environment variables. See [server/config.js](serv
|
|||||||
|
|
||||||
## Localization
|
## Localization
|
||||||
|
|
||||||
see [docs/localization.md](docs/localization.md)
|
See: [docs/localization.md](docs/localization.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -139,7 +139,11 @@ Find a list of public instances here: https://github.com/timvisee/send-instances
|
|||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
|
||||||
See also [docs/deployment.md](docs/deployment.md)
|
See: [docs/deployment.md](docs/deployment.md)
|
||||||
|
|
||||||
|
Docker quickstart: [docs/docker.md](docs/docker.md)
|
||||||
|
|
||||||
|
AWS example using Ubuntu Server `20.04`: [docs/AWS.md](docs/AWS.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -148,6 +152,7 @@ See also [docs/deployment.md](docs/deployment.md)
|
|||||||
- Web: _this repository_
|
- Web: _this repository_
|
||||||
- Command-line: [`ffsend`](https://github.com/timvisee/ffsend)
|
- Command-line: [`ffsend`](https://github.com/timvisee/ffsend)
|
||||||
- Android: _see [Android](#android) section_
|
- Android: _see [Android](#android) section_
|
||||||
|
- Thunderbird: [FileLink provider for Send](https://addons.thunderbird.net/en-US/thunderbird/addon/filelink-provider-for-send/)
|
||||||
|
|
||||||
#### Android
|
#### Android
|
||||||
|
|
||||||
|
|||||||
@@ -77,7 +77,11 @@ function body(main) {
|
|||||||
state.capabilities = {
|
state.capabilities = {
|
||||||
account: true
|
account: true
|
||||||
}; //TODO
|
}; //TODO
|
||||||
state.archive = new Archive([], DEFAULTS.EXPIRE_SECONDS);
|
state.archive = new Archive(
|
||||||
|
[],
|
||||||
|
DEFAULTS.EXPIRE_SECONDS,
|
||||||
|
DEFAULTS.DOWNLOADS
|
||||||
|
);
|
||||||
state.storage = storage;
|
state.storage = storage;
|
||||||
state.user = new User(storage, LIMITS);
|
state.user = new User(storage, LIMITS);
|
||||||
state.sentry = Sentry;
|
state.sentry = Sentry;
|
||||||
|
|||||||
@@ -14,11 +14,11 @@ function isDupe(newFile, array) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class Archive {
|
export default class Archive {
|
||||||
constructor(files = [], defaultTimeLimit = 86400) {
|
constructor(files = [], defaultTimeLimit = 86400, defaultDownloadLimit = 1) {
|
||||||
this.files = Array.from(files);
|
this.files = Array.from(files);
|
||||||
this.defaultTimeLimit = defaultTimeLimit;
|
this.defaultTimeLimit = defaultTimeLimit;
|
||||||
this.timeLimit = defaultTimeLimit;
|
this.timeLimit = defaultTimeLimit;
|
||||||
this.dlimit = 1;
|
this.dlimit = defaultDownloadLimit;
|
||||||
this.password = null;
|
this.password = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -224,24 +224,6 @@ async function saveFile(file) {
|
|||||||
if (navigator.msSaveBlob) {
|
if (navigator.msSaveBlob) {
|
||||||
navigator.msSaveBlob(blob, file.name);
|
navigator.msSaveBlob(blob, file.name);
|
||||||
return resolve();
|
return resolve();
|
||||||
} else if (/iPhone|fxios/i.test(navigator.userAgent)) {
|
|
||||||
// This method is much slower but createObjectURL
|
|
||||||
// is buggy on iOS
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.addEventListener('loadend', function() {
|
|
||||||
if (reader.error) {
|
|
||||||
return reject(reader.error);
|
|
||||||
}
|
|
||||||
if (reader.result) {
|
|
||||||
const a = document.createElement('a');
|
|
||||||
a.href = reader.result;
|
|
||||||
a.download = file.name;
|
|
||||||
document.body.appendChild(a);
|
|
||||||
a.click();
|
|
||||||
}
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
reader.readAsDataURL(blob);
|
|
||||||
} else {
|
} else {
|
||||||
const downloadUrl = URL.createObjectURL(blob);
|
const downloadUrl = URL.createObjectURL(blob);
|
||||||
const a = document.createElement('a');
|
const a = document.createElement('a');
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ details {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
details > summary::-webkit-details-marker {
|
details > summary::marker {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +175,6 @@ footer li a:hover {
|
|||||||
position: relative;
|
position: relative;
|
||||||
max-width: 64rem;
|
max-width: 64rem;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.main > section {
|
.main > section {
|
||||||
@@ -271,7 +270,6 @@ select {
|
|||||||
@apply m-auto;
|
@apply m-auto;
|
||||||
@apply py-8;
|
@apply py-8;
|
||||||
|
|
||||||
min-height: 42rem;
|
|
||||||
max-height: 42rem;
|
max-height: 42rem;
|
||||||
width: calc(100% - 3rem);
|
width: calc(100% - 3rem);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ if (process.env.NODE_ENV === 'production') {
|
|||||||
DEFAULTS,
|
DEFAULTS,
|
||||||
WEB_UI,
|
WEB_UI,
|
||||||
PREFS,
|
PREFS,
|
||||||
archive: new Archive([], DEFAULTS.EXPIRE_SECONDS),
|
archive: new Archive([], DEFAULTS.EXPIRE_SECONDS, DEFAULTS.DOWNLOADS),
|
||||||
capabilities,
|
capabilities,
|
||||||
translate,
|
translate,
|
||||||
storage,
|
storage,
|
||||||
|
|||||||
1281
app/qrcode.js
1281
app/qrcode.js
File diff suppressed because it is too large
Load Diff
@@ -31,12 +31,11 @@ module.exports = function(state, emit) {
|
|||||||
counts,
|
counts,
|
||||||
num => state.translate('downloadCount', { num }),
|
num => state.translate('downloadCount', { num }),
|
||||||
value => {
|
value => {
|
||||||
const max = state.user.maxDownloads;
|
const selected = parseInt(value);
|
||||||
state.archive.dlimit = Math.min(value, max);
|
state.archive.dlimit = selected;
|
||||||
if (value > max) {
|
emit('render');
|
||||||
emit('signup-cta', 'count');
|
if (selected > parseInt(state.user.maxDownloads || '0')) {
|
||||||
} else {
|
console.log('Chosen max download count is larger than the allowed limit', selected)
|
||||||
emit('render');
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'expire-after-dl-count-select'
|
'expire-after-dl-count-select'
|
||||||
@@ -58,12 +57,11 @@ module.exports = function(state, emit) {
|
|||||||
return state.translate(l10n.id, l10n);
|
return state.translate(l10n.id, l10n);
|
||||||
},
|
},
|
||||||
value => {
|
value => {
|
||||||
const max = state.user.maxExpireSeconds;
|
const selected = parseInt(value);
|
||||||
state.archive.timeLimit = Math.min(value, max);
|
state.archive.timeLimit = selected;
|
||||||
if (value > max) {
|
emit('render');
|
||||||
emit('signup-cta', 'time');
|
if (selected > parseInt(state.user.maxExpireSeconds || '0')) {
|
||||||
} else {
|
console.log('Chosen download expiration is larger than the allowed limit', selected)
|
||||||
emit('render');
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'expire-after-time-select'
|
'expire-after-time-select'
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ const raw = require('choo/html/raw');
|
|||||||
const qrcode = require('../qrcode');
|
const qrcode = require('../qrcode');
|
||||||
|
|
||||||
module.exports = function(url) {
|
module.exports = function(url) {
|
||||||
const gen = qrcode(5, 'L');
|
const gen = qrcode(0, 'L');
|
||||||
gen.addData(url);
|
gen.addData(url);
|
||||||
gen.make();
|
gen.make();
|
||||||
const qr = gen.createSvgTag({ scalable: true });
|
const qr = gen.createSvgTag({ scalable: true });
|
||||||
|
|||||||
@@ -1,32 +1,28 @@
|
|||||||
const html = require('choo/html');
|
const html = require('choo/html');
|
||||||
|
|
||||||
module.exports = function(selected, options, translate, changed, htmlId) {
|
module.exports = function(selected, options, translate, changed, htmlId) {
|
||||||
let x = selected;
|
function choose(event) {
|
||||||
|
if (event.target.value != selected) {
|
||||||
|
console.log('Selected new value from dropdown', htmlId, ':', selected, '->', event.target.value)
|
||||||
|
changed(event.target.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<select
|
<select
|
||||||
id="${htmlId}"
|
id="${htmlId}"
|
||||||
class="appearance-none cursor-pointer border rounded bg-grey-10 hover:border-blue-50 focus:border-blue-50 pl-1 pr-8 py-1 my-1 h-8 dark:bg-grey-80"
|
class="appearance-none cursor-pointer border rounded bg-grey-10 hover:border-blue-50 focus:border-blue-50 pl-1 pr-8 py-1 my-1 h-8 dark:bg-grey-80"
|
||||||
|
data-selected="${selected}"
|
||||||
onchange="${choose}"
|
onchange="${choose}"
|
||||||
>
|
>
|
||||||
${options.map(
|
${options.map(
|
||||||
i =>
|
value =>
|
||||||
html`
|
html`
|
||||||
<option value="${i}" ${i === selected ? 'selected' : ''}
|
<option value="${value}" ${value == selected ? 'selected' : ''}>
|
||||||
>${translate(i)}</option
|
${translate(value)}
|
||||||
>
|
</option>
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
</select>
|
</select>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
function choose(event) {
|
|
||||||
const target = event.target;
|
|
||||||
const value = +target.value;
|
|
||||||
|
|
||||||
if (x !== value) {
|
|
||||||
x = value;
|
|
||||||
changed(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ module.exports = function(state, emit) {
|
|||||||
why = html`
|
why = html`
|
||||||
<a
|
<a
|
||||||
class="text-blue"
|
class="text-blue"
|
||||||
href="https://github.com/mozilla/send/blob/master/docs/faq.md#why-is-my-browser-not-supported"
|
href="https://github.com/timvisee/send/blob/master/docs/faq.md#why-is-my-browser-not-supported"
|
||||||
>
|
>
|
||||||
${state.translate('notSupportedLink')}
|
${state.translate('notSupportedLink')}
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
BIN
assets/icon-64x64.png
Normal file
BIN
assets/icon-64x64.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
236
docs/AWS.md
Normal file
236
docs/AWS.md
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
# Deployment to AWS
|
||||||
|
|
||||||
|
This document describes how to do a deployment of Send in AWS
|
||||||
|
|
||||||
|
## AWS requirements
|
||||||
|
|
||||||
|
### Security groups (2)
|
||||||
|
|
||||||
|
* ALB:
|
||||||
|
- inbound: allow traffic from anywhere on port 80 and 443
|
||||||
|
- ountbound: allow traffic to the instance security group on port `8080`
|
||||||
|
|
||||||
|
* Instance:
|
||||||
|
- inbound: allow SSH from your public IP or a bastion (changing the default SSH port is a good idea)
|
||||||
|
- inbound: allow traffic from the ALB security group on port `8080`
|
||||||
|
- ountbound: allow all traffic to anywhere
|
||||||
|
|
||||||
|
### Resources
|
||||||
|
|
||||||
|
* An S3 bucket (block all public access)
|
||||||
|
|
||||||
|
* A private EC2 instance running Ubuntu `20.04` (you can use the [Amazon EC2 AMI Locator](https://cloud-images.ubuntu.com/locator/ec2/) to find the latest)
|
||||||
|
|
||||||
|
Attach an IAM role to the instance with the following inline policy:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Version": "2012-10-17",
|
||||||
|
"Statement": [
|
||||||
|
{
|
||||||
|
"Action": [
|
||||||
|
"s3:ListAllMyBuckets"
|
||||||
|
],
|
||||||
|
"Resource": [
|
||||||
|
"*"
|
||||||
|
],
|
||||||
|
"Effect": "Allow"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Action": [
|
||||||
|
"s3:ListBucket",
|
||||||
|
"s3:GetBucketLocation",
|
||||||
|
"s3:ListBucketMultipartUploads"
|
||||||
|
],
|
||||||
|
"Resource": [
|
||||||
|
"arn:aws:s3:::<s3_bucket_name>"
|
||||||
|
],
|
||||||
|
"Effect": "Allow"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Action": [
|
||||||
|
"s3:GetObject",
|
||||||
|
"s3:GetObjectVersion",
|
||||||
|
"s3:ListMultipartUploadParts",
|
||||||
|
"s3:PutObject",
|
||||||
|
"s3:AbortMultipartUpload",
|
||||||
|
"s3:DeleteObject",
|
||||||
|
"s3:DeleteObjectVersion"
|
||||||
|
],
|
||||||
|
"Resource": [
|
||||||
|
"arn:aws:s3:::<s3_bucket_name>/*"
|
||||||
|
],
|
||||||
|
"Effect": "Allow"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* A public ALB:
|
||||||
|
|
||||||
|
- Create a target group with the instance registered (HTTP on port `8080` and path `/`)
|
||||||
|
- Configure HTTP (port 80) to redirect to HTTPS (port 443)
|
||||||
|
- HTTPS (port 443) using the latest security policy and an ACM certificate like `send.mydomain.com`
|
||||||
|
|
||||||
|
* A Route53 public record, alias from `send.mydomain.com` to the ALB
|
||||||
|
|
||||||
|
## Software requirements
|
||||||
|
|
||||||
|
* Git
|
||||||
|
* NodeJS `15.x` LTS
|
||||||
|
* Local Redis server
|
||||||
|
|
||||||
|
### Prerequisite packages
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install -y apt-transport-https ca-certificates curl software-properties-common
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add repositories
|
||||||
|
|
||||||
|
* NodeJS `15.x` LTS (checkout [package.json](../package.json)):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | sudo apt-key add -
|
||||||
|
echo 'deb [arch=amd64] https://deb.nodesource.com/node_15.x focal main' | sudo tee /etc/apt/sources.list.d/nodejs.list
|
||||||
|
```
|
||||||
|
|
||||||
|
* Git (latest)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo add-apt-repository ppa:git-core/ppa
|
||||||
|
```
|
||||||
|
|
||||||
|
* Redis (latest)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo add-apt-repository ppa:redislabs/redis
|
||||||
|
```
|
||||||
|
|
||||||
|
### Install required packages
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install git nodejs redis-server telnet
|
||||||
|
```
|
||||||
|
|
||||||
|
### Redis server
|
||||||
|
|
||||||
|
#### Password (optional)
|
||||||
|
|
||||||
|
Generate a strong password:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
makepasswd --chars=100
|
||||||
|
```
|
||||||
|
|
||||||
|
Edit Redis configuration file `/etc/redis/redis.conf`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
requirepass <redis_password>
|
||||||
|
```
|
||||||
|
|
||||||
|
_Note: documentation on securing Redis https://redis.io/topics/security_
|
||||||
|
|
||||||
|
#### Systemd
|
||||||
|
|
||||||
|
Enable and (re)start the Redis server service:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl enable redis-server
|
||||||
|
sudo systemctl restart redis-server
|
||||||
|
sudo systemctl status redis-server
|
||||||
|
```
|
||||||
|
|
||||||
|
## Website directory
|
||||||
|
|
||||||
|
Setup a directory for the data
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo mkdir -pv /var/www/send
|
||||||
|
sudo chown www-data:www-data /var/www/send
|
||||||
|
sudo 750 /var/www/send
|
||||||
|
```
|
||||||
|
|
||||||
|
### NodeJS
|
||||||
|
|
||||||
|
Update npm:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo npm install -g npm
|
||||||
|
```
|
||||||
|
|
||||||
|
Checkout current NodeJS and npm versions:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node --version
|
||||||
|
npm --version
|
||||||
|
```
|
||||||
|
|
||||||
|
Clone repository, install JavaScript packages and compiles the assets:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo su -l www-data -s /bin/bash
|
||||||
|
cd /var/www/send
|
||||||
|
git clone https://gitlab.com/timvisee/send.git .
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
exit
|
||||||
|
```
|
||||||
|
|
||||||
|
Create the file `/var/www/send/.env` used by Systemd with your environment variables
|
||||||
|
(checkout [config.js](../server/config.js) for more configuration environment variables):
|
||||||
|
|
||||||
|
```
|
||||||
|
BASE_URL='https://send.mydomain.com'
|
||||||
|
NODE_ENV='production'
|
||||||
|
PORT='8080'
|
||||||
|
REDIS_PASSWORD='<redis_password>'
|
||||||
|
S3_BUCKET='<s3_bucket_name>'
|
||||||
|
```
|
||||||
|
|
||||||
|
Lower files and folders permissions to user and group `www-data`:
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo find /var/www/send -type d -exec chmod 750 {} \;
|
||||||
|
sudo find /var/www/send -type f -exec chmod 640 {} \;
|
||||||
|
sudo find -L /var/www/send/node_modules/.bin/ -exec chmod 750 {} \;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Systemd
|
||||||
|
|
||||||
|
Create the file `/etc/systemd/system/send.service` with `root` user and `644` mode:
|
||||||
|
|
||||||
|
```
|
||||||
|
[Unit]
|
||||||
|
Description=Send
|
||||||
|
After=network.target
|
||||||
|
Requires=redis-server.service
|
||||||
|
Documentation=https://gitlab.com/timvisee/send
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/usr/bin/npm run prod
|
||||||
|
EnvironmentFile=/var/www/send/.env
|
||||||
|
WorkingDirectory=/var/www/send
|
||||||
|
User=www-data
|
||||||
|
Group=www-data
|
||||||
|
Restart=on-failure
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
```
|
||||||
|
|
||||||
|
_Note: could be better tuner to secure the service by restricting system permissions,
|
||||||
|
check with `systemd-analyze security send`_
|
||||||
|
|
||||||
|
Enable and start the Send service, check logs:
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable send
|
||||||
|
sudo systemctl start send
|
||||||
|
sudo systemctl status send
|
||||||
|
journalctl -fu send
|
||||||
|
```
|
||||||
@@ -1,69 +1,96 @@
|
|||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
This document describes how to do a full deployment of Send on your own Linux server. You will need:
|
This document describes how to do a full deployment of Send on your own Linux server. You will need:
|
||||||
|
|
||||||
* A working (and ideally somewhat recent) installation of NodeJS and NPM
|
* A working (and ideally somewhat recent) installation of NodeJS and npm
|
||||||
* GIT
|
* Git
|
||||||
* An Apache webserver
|
* Apache webserver
|
||||||
* Optionally telnet, to be able to quickly check your installation
|
* Optionally telnet, to be able to quickly check your installation
|
||||||
|
|
||||||
For Debian/Ubuntu systems this probably just means something like this:
|
For example in Debian/Ubuntu systems:
|
||||||
|
|
||||||
* apt install git apache2 nodejs npm telnet
|
```bash
|
||||||
|
sudo apt install git apache2 nodejs npm telnet
|
||||||
|
```
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
* We assume an already configured virtual-host on your webserver with an existing empty htdocs folder
|
* We assume an already configured virtual-host on your webserver with an existing empty htdocs folder
|
||||||
* First, remove that htdocs folder - we will replace it with Send's version now
|
* First, remove that htdocs folder - we will replace it with Send's version now
|
||||||
* git clone https://github.com/mozilla/send.git htdocs
|
* git clone https://github.com/timvisee/send.git htdocs
|
||||||
* Make now sure you are NOT root but rather the user your webserver is serving files under (e.g. "su www-data" or whoever the owner of your htdocs folder is)
|
* Make now sure you are NOT root but rather the user your webserver is serving files under (e.g. "su www-data" or whoever the owner of your htdocs folder is)
|
||||||
* npm install
|
* npm install
|
||||||
* npm run build
|
* npm run build
|
||||||
|
|
||||||
## Running
|
## Running
|
||||||
|
|
||||||
To have a permanently running version of Send as a background process:
|
To have a permanently running version of Send as a background process:
|
||||||
|
|
||||||
* Create a file "run.sh" with:
|
* Create a file `run.sh` with:
|
||||||
```
|
|
||||||
|
```bash
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
nohup su www-data -c "npm run prod" 2>/dev/null &
|
nohup su www-data -c "npm run prod" 2>/dev/null &
|
||||||
```
|
```
|
||||||
* chmod +x run.sh
|
|
||||||
* ./run.sh
|
* Execute the script:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod +x run.sh
|
||||||
|
./run.sh
|
||||||
|
```
|
||||||
|
|
||||||
Now the Send backend should be running on port 1443. You can check with:
|
Now the Send backend should be running on port 1443. You can check with:
|
||||||
* telnet localhost 1443
|
|
||||||
|
```bash
|
||||||
|
telnet localhost 1443
|
||||||
|
```
|
||||||
|
|
||||||
## Reverse Proxy
|
## Reverse Proxy
|
||||||
|
|
||||||
Of course, we don't want to expose the service on port 1443. Instead we want our normal webserver to forward all requests to Send ("Reverse proxy").
|
Of course, we don't want to expose the service on port 1443. Instead we want our normal webserver to forward all requests to Send ("Reverse proxy").
|
||||||
|
|
||||||
# Apache webserver
|
# Apache webserver
|
||||||
|
|
||||||
* a2enmod proxy
|
* Enable Apache required modules:
|
||||||
* a2enmod proxy_http
|
|
||||||
* a2enmod proxy_wstunnel
|
|
||||||
* a2enmod rewrite
|
|
||||||
|
|
||||||
In your Apache virtual host configuration file, insert this:
|
```bash
|
||||||
|
sudo a2enmod headers
|
||||||
|
sudo a2enmod proxy
|
||||||
|
sudo a2enmod proxy_http
|
||||||
|
sudo a2enmod proxy_wstunnel
|
||||||
|
sudo a2enmod rewrite
|
||||||
|
```
|
||||||
|
|
||||||
|
* Edit your Apache virtual host configuration file, insert this:
|
||||||
|
|
||||||
```
|
```
|
||||||
# Enable rewrite engine
|
# Enable rewrite engine
|
||||||
RewriteEngine on
|
RewriteEngine on
|
||||||
|
|
||||||
# Make sure the original domain name is forwarded to Send
|
# Make sure the original domain name is forwarded to Send
|
||||||
# Otherwise the generated URLs will be wrong
|
# Otherwise the generated URLs will be wrong
|
||||||
ProxyPreserveHost on
|
ProxyPreserveHost on
|
||||||
|
|
||||||
# Make sure the generated URL is https://
|
# Make sure the generated URL is https://
|
||||||
RequestHeader set X-Forwarded-Proto https
|
RequestHeader set X-Forwarded-Proto https
|
||||||
|
|
||||||
# If it's a normal file (e.g. PNG, CSS) just return it
|
# If it's a normal file (e.g. PNG, CSS) just return it
|
||||||
RewriteCond %{REQUEST_FILENAME} -f
|
RewriteCond %{REQUEST_FILENAME} -f
|
||||||
RewriteRule .* - [L]
|
RewriteRule .* - [L]
|
||||||
|
|
||||||
# If it's a websocket connection, redirect it to a Send WS connection
|
# If it's a websocket connection, redirect it to a Send WS connection
|
||||||
RewriteCond %{HTTP:Upgrade} =websocket [NC]
|
RewriteCond %{HTTP:Upgrade} =websocket [NC]
|
||||||
RewriteRule /(.*) ws://127.0.0.1:1443/$1 [P,L]
|
RewriteRule /(.*) ws://127.0.0.1:1443/$1 [P,L]
|
||||||
|
|
||||||
# Otherwise redirect it to a normal HTTP connection
|
# Otherwise redirect it to a normal HTTP connection
|
||||||
RewriteRule ^/(.*)$ http://127.0.0.1:1443/$1 [P,QSA]
|
RewriteRule ^/(.*)$ http://127.0.0.1:1443/$1 [P,QSA]
|
||||||
ProxyPassReverse "/" "http://127.0.0.1:1443"
|
ProxyPassReverse "/" "http://127.0.0.1:1443"
|
||||||
|
```
|
||||||
|
|
||||||
|
* Test configuration and restart Apache:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apache2ctl configtest
|
||||||
|
sudo systemctl restart apache2
|
||||||
```
|
```
|
||||||
|
|||||||
120
docs/docker.md
120
docs/docker.md
@@ -1,45 +1,121 @@
|
|||||||
## Setup
|
## Docker Quickstart
|
||||||
|
|
||||||
Use `registry.gitlab.com/timvisee/send:latest` from [`timvisee/send`'s registry](https://gitlab.com/timvisee/send/container_registry) for the latest Docker image.
|
Use `registry.gitlab.com/timvisee/send:latest` from [`timvisee/send`'s Gitlab image registry](https://gitlab.com/timvisee/send/container_registry) for the latest Docker image.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker pull registry.gitlab.com/timvisee/send:latest
|
docker pull registry.gitlab.com/timvisee/send:latest
|
||||||
|
|
||||||
|
# example quickstart (point REDIS_HOST to an already-running redis server)
|
||||||
|
docker run -v $PWD/uploads:/uploads -p 1443:1443 \
|
||||||
|
-e 'DETECT_BASE_URL=true' \
|
||||||
|
-e 'REDIS_HOST=localhost' \
|
||||||
|
registry.gitlab.com/timvisee/send:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
Or run `docker build -t send:latest .` to create an image locally or `docker-compose up` to run a full testable stack. *We don't recommend using docker-compose for production.*
|
Or clone this repo and run `docker build -t send:latest .` to build an image locally.
|
||||||
|
|
||||||
## Environment variables:
|
*Note: for Docker Compose, see: https://github.com/timvisee/send-docker-compose*
|
||||||
|
|
||||||
| Name | Description
|
## Environment Variables
|
||||||
|
|
||||||
|
All the available config options and their defaults can be found here: https://github.com/timvisee/send/blob/master/server/config.js
|
||||||
|
|
||||||
|
Config options should be set as unquoted environment variables. Boolean options should be `true`/`false`, time/duration should be integers (seconds), and filesize values should be integers (bytes).
|
||||||
|
|
||||||
|
Config options expecting array values (e.g. `EXPIRE_TIMES_SECONDS`, `DOWNLOAD_COUNTS`) should be in unquoted CSV format. UI dropdowns will default to the first value in the CSV, e.g. `DOWNLOAD_COUNTS=5,1,10,100` will show four dropdown options, with `5` selected by the default.
|
||||||
|
|
||||||
|
#### Server Configuration
|
||||||
|
|
||||||
|
| Name | Description |
|
||||||
|------------------|-------------|
|
|------------------|-------------|
|
||||||
| `BASE_URL` | The HTTPS URL where traffic will be served (e.g. `https://send.firefox.com`)
|
| `BASE_URL` | The HTTPS URL where traffic will be served (e.g. `https://send.firefox.com`)
|
||||||
| `PORT` | Port the server will listen on (defaults to 1443).
|
| `DETECT_BASE_URL` | Autodetect the base URL using browser if `BASE_URL` is unset (defaults to `false`)
|
||||||
| `NODE_ENV` | `"production"`
|
| `PORT` | Port the server will listen on (defaults to `1443`)
|
||||||
| `FILE_DIR` | Uploads directory for local storage
|
| `NODE_ENV` | Run in `development` mode (unsafe) or `production` mode (the default)
|
||||||
| `S3_BUCKET` | The S3 bucket name.
|
| `SEND_FOOTER_DMCA_URL` | A URL to a contact page for DMCA requests (empty / not shown by default)
|
||||||
| `S3_ENDPOINT`| Optional custom S3 endpoint host.
|
| `SENTRY_CLIENT`, `SENTRY_DSN` | Sentry Client ID and DNS for error tracking (optional, disabled by default)
|
||||||
| `S3_USE_PATH_STYLE_ENDPOINTS`| `true` or `false`
|
|
||||||
| `AWS_ACCESS_KEY_ID` | S3 access key ID
|
|
||||||
| `AWS_SECRET_ACCESS_KEY` | S3 secret access key ID
|
|
||||||
| `MAX_FILE_SIZE` | Maximum upload file size in bytes (defaults to 2147483648)
|
|
||||||
| `MAX_EXPIRE_SECONDS` | Maximum upload expiry time in seconds (defaults to 604800)
|
|
||||||
| `REDIS_HOST` | Host name of the Redis server.
|
|
||||||
| `SENTRY_CLIENT` | Sentry Client ID
|
|
||||||
| `SENTRY_DSN` | Sentry DSN
|
|
||||||
|
|
||||||
## Example:
|
*Note: more options can be found here: https://github.com/timvisee/send/blob/master/server/config.js*
|
||||||
|
|
||||||
|
#### Upload and Download Limits
|
||||||
|
|
||||||
|
Configure the limits for uploads and downloads. Long expiration times are risky on public servers as people may use you as free hosting for copyrighted content or malware (which is why Mozilla shut down their `send` service). It's advised to only expose your service on a LAN/intranet, password protect it with a proxy/gateway, or make sure to set `SEND_FOOTER_DMCA_URL` above so you can respond to takedown requests.
|
||||||
|
|
||||||
|
| Name | Description |
|
||||||
|
|------------------|-------------|
|
||||||
|
| `MAX_FILE_SIZE` | Maximum upload file size in bytes (defaults to `2147483648` aka 2GB)
|
||||||
|
| `MAX_FILES_PER_ARCHIVE` | Maximum number of files per archive (defaults to `64`)
|
||||||
|
| `MAX_EXPIRE_SECONDS` | Maximum upload expiry time in seconds (defaults to `604800` aka 7 days)
|
||||||
|
| `MAX_DOWNLOADS` | Maximum number of downloads (defaults to `100`)
|
||||||
|
| `DOWNLOAD_COUNTS` | Download limit options to show in UI dropdown, e.g. `10,1,2,5,10,15,25,50,100,1000`
|
||||||
|
| `EXPIRE_TIMES_SECONDS` | Expire time options to show in UI dropdown, e.g. `3600,86400,604800,2592000,31536000`
|
||||||
|
| `DEFAULT_DOWNLOADS` | Default download limit in UI (defaults to `1`)
|
||||||
|
| `DEFAULT_EXPIRE_SECONDS` | Default expire time in UI (defaults to `86400`)
|
||||||
|
|
||||||
|
*Note: more options can be found here: https://github.com/timvisee/send/blob/master/server/config.js*
|
||||||
|
|
||||||
|
#### Storage Backend Options
|
||||||
|
|
||||||
|
Pick how you want to store uploaded files and set these config options accordingly:
|
||||||
|
|
||||||
|
- Local filesystem (the default): set `FILE_DIR` to the local path used inside the container for storage (or leave the default)
|
||||||
|
- S3-compatible object store: set `S3_BUCKET`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` (and `S3_ENDPOINT` if using something other than AWS)
|
||||||
|
- Google Cloud Storage: set `GCS_BUCKET` to the name of a GCS bucket (auth should be set up using [Application Default Credentials](https://cloud.google.com/docs/authentication/production#auth-cloud-implicit-nodejs))
|
||||||
|
|
||||||
|
Redis is used as the metadata database for the backend and is required no matter which storage method you use.
|
||||||
|
|
||||||
|
| Name | Description |
|
||||||
|
|------------------|-------------|
|
||||||
|
| `REDIS_HOST`, `REDIS_PORT`, `REDIS_USER`, `REDIS_PASSWORD`, `REDIS_DB` | Host name, port, and pass of the Redis server (defaults to `localhost`, `6379`, and no password)
|
||||||
|
| `FILE_DIR` | Directory for storage inside the Docker container (defaults to `/uploads`)
|
||||||
|
| `S3_BUCKET` | The S3 bucket name to use (only set if using S3 for storage)
|
||||||
|
| `S3_ENDPOINT` | An optional custom endpoint to use for S3 (defaults to AWS)
|
||||||
|
| `S3_USE_PATH_STYLE_ENDPOINT`| Whether to force [path style URLs](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Config.html#s3ForcePathStyle-property) for S3 objects (defaults to `false`)
|
||||||
|
| `AWS_ACCESS_KEY_ID` | S3 access key ID (only set if using S3 for storage)
|
||||||
|
| `AWS_SECRET_ACCESS_KEY` | S3 secret access key ID (only set if using S3 for storage)
|
||||||
|
| `GCS_BUCKET` | Google Cloud Storage bucket (only set if using GCP for storage)
|
||||||
|
|
||||||
|
*Note: more options can be found here: https://github.com/timvisee/send/blob/master/server/config.js*
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
**Run using an Amazon Elasticache for the Redis DB, Amazon S3 for the storage backend, and Sentry for error reporting.**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ docker run --net=host -e 'NODE_ENV=production' \
|
$ docker run -p 1443:1443 \
|
||||||
-e 'S3_BUCKET=testpilot-p2p-dev' \
|
-e 'S3_BUCKET=testpilot-p2p-dev' \
|
||||||
-e 'REDIS_HOST=dyf9s2r4vo3.bolxr4.0001.usw2.cache.amazonaws.com' \
|
-e 'REDIS_HOST=dyf9s2r4vo3.bolxr4.0001.usw2.cache.amazonaws.com' \
|
||||||
-e 'SENTRY_CLIENT=https://51e23d7263e348a7a3b90a5357c61cb2@sentry.prod.mozaws.net/168' \
|
-e 'SENTRY_CLIENT=https://51e23d7263e348a7a3b90a5357c61cb2@sentry.prod.mozaws.net/168' \
|
||||||
-e 'SENTRY_DSN=https://51e23d7263e348a7a3b90a5357c61cb2:65e23d7263e348a7a3b90a5357c61c44@sentry.prod.mozaws.net/168' \
|
-e 'SENTRY_DSN=https://51e23d7263e348a7a3b90a5357c61cb2:65e23d7263e348a7a3b90a5357c61c44@sentry.prod.mozaws.net/168' \
|
||||||
-e 'BASE_URL=https://send.firefox.com' \
|
-e 'BASE_URL=https://send.example.com' \
|
||||||
registry.gitlab.com/timvisee/send:latest
|
registry.gitlab.com/timvisee/send:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
## Docker compose
|
*Note: make sure to replace the example values above with your real values before running.*
|
||||||
|
|
||||||
|
|
||||||
|
**Run totally self-hosted using the current filesystem directry (`$PWD`) to store the Redis data and file uploads, with a `5GB` upload limit, 1 month expiry, and contact URL set.**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# create a network for the send backend and redis containers to talk to each other
|
||||||
|
$ docker network create timviseesend
|
||||||
|
|
||||||
|
# start the redis container
|
||||||
|
$ docker run --net=timviseesend -v $PWD/redis:/data redis-server --appendonly yes
|
||||||
|
|
||||||
|
# start the send backend container
|
||||||
|
$ docker run --net=timviseesend -v $PWD/uploads:/uploads -p 1443:1443 \
|
||||||
|
-e 'BASE_URL=http://localhost:1443' \
|
||||||
|
-e 'MAX_FILE_SIZE=5368709120' \
|
||||||
|
-e 'MAX_EXPIRE_SECONDS=2592000' \
|
||||||
|
-e 'SEND_FOOTER_DMCA_URL=https://example.com/dmca-contact-info' \
|
||||||
|
registry.gitlab.com/timvisee/send:latest
|
||||||
|
```
|
||||||
|
Then open http://localhost:1443 to view the UI. (change the `localhost` to your IP or hostname above to serve the UI to others)
|
||||||
|
|
||||||
|
To run with HTTPS, you will need to set up a reverse proxy with SSL termination in front of the backend. See Docker Compose below for an example setup.
|
||||||
|
|
||||||
|
## Docker Compose
|
||||||
|
|
||||||
For a Docker compose configuration example, see:
|
For a Docker compose configuration example, see:
|
||||||
|
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ Send uses JavaScript to:
|
|||||||
|
|
||||||
- Encrypt and decrypt files locally on the client instead of the server.
|
- Encrypt and decrypt files locally on the client instead of the server.
|
||||||
- Render the user interface.
|
- Render the user interface.
|
||||||
- Manage translations on the website into [various different languages](https://github.com/mozilla/send#localization).
|
- Manage translations on the website into [various different languages](https://github.com/timvisee/send#localization).
|
||||||
- Collect data to help us improve Send in accordance with our [Terms & Privacy](https://send.firefox.com/legal).
|
- Collect data to help us improve Send in accordance with our [Terms & Privacy](https://send.firefox.com/legal).
|
||||||
|
|
||||||
Since Send is an open source project, you can see all of the cool ways we use JavaScript by [examining our code](https://github.com/mozilla/send/).
|
Since Send is an open source project, you can see all of the cool ways we use JavaScript by [examining our code](https://github.com/timvisee/send/).
|
||||||
|
|
||||||
## How long are files available for?
|
## How long are files available for?
|
||||||
|
|
||||||
|
|||||||
3496
package-lock.json
generated
3496
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
47
package.json
47
package.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "send",
|
"name": "send",
|
||||||
"description": "File Sharing Experiment",
|
"description": "File Sharing Experiment",
|
||||||
"version": "3.4.6",
|
"version": "3.4.16",
|
||||||
"author": "Mozilla (https://mozilla.org)",
|
"author": "Mozilla (https://mozilla.org)",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
"Tim Visee <3a4fb3964f@sinenomine.email> (https://timvisee.com)"
|
"Tim Visee <3a4fb3964f@sinenomine.email> (https://timvisee.com)"
|
||||||
@@ -30,16 +30,14 @@
|
|||||||
"test:report": "nyc report --reporter=html",
|
"test:report": "nyc report --reporter=html",
|
||||||
"test-integration": "cross-env NODE_ENV=development wdio test/wdio.docker.conf.js",
|
"test-integration": "cross-env NODE_ENV=development wdio test/wdio.docker.conf.js",
|
||||||
"circleci-test-integration": "echo 'webdriverio tests need to be updated to node 12'",
|
"circleci-test-integration": "echo 'webdriverio tests need to be updated to node 12'",
|
||||||
"start": "npm run clean && cross-env NODE_ENV=development L10N_DEV=true FXA_CLIENT_ID=fced6b5e3f4c66b9 BASE_URL=http://localhost:8080 webpack-dev-server --mode=development",
|
"start": "npm run clean && cross-env NODE_ENV=development L10N_DEV=true BASE_URL=http://localhost:8080 DETECT_BASE_URL=true webpack-dev-server --mode=development",
|
||||||
"android": "cross-env ANDROID=1 npm start",
|
"android": "cross-env ANDROID=1 npm start",
|
||||||
"prod": "node server/bin/prod.js"
|
"prod": "node server/bin/prod.js"
|
||||||
},
|
},
|
||||||
"husky": {
|
"husky": {
|
||||||
"hooks": {
|
"hooks": {
|
||||||
"pre-commit": "lint-staged",
|
"pre-commit": "lint-staged",
|
||||||
"pre-push": "npm test",
|
"pre-push": "npm test"
|
||||||
"post-merge": "npm install",
|
|
||||||
"post-checkout": "scripts/sync-npm-dependencies.sh"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
@@ -61,24 +59,24 @@
|
|||||||
"cache": true
|
"cache": true
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^15.5.1"
|
"node": "^16.13.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.13.15",
|
"@babel/core": "^7.16.7",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.13.0",
|
"@babel/plugin-proposal-class-properties": "^7.16.7",
|
||||||
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
|
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
|
||||||
"@babel/preset-env": "^7.13.15",
|
"@babel/preset-env": "^7.16.8",
|
||||||
"@dannycoates/webcrypto-liner": "^0.1.37",
|
"@dannycoates/webcrypto-liner": "^0.1.37",
|
||||||
"@fullhuman/postcss-purgecss": "^1.3.0",
|
"@fullhuman/postcss-purgecss": "^1.3.0",
|
||||||
"@mattiasbuelens/web-streams-polyfill": "0.2.1",
|
"@mattiasbuelens/web-streams-polyfill": "0.2.1",
|
||||||
"@sentry/browser": "^5.30.0",
|
"@sentry/browser": "^5.30.0",
|
||||||
"asmcrypto.js": "^0.22.0",
|
"asmcrypto.js": "^0.22.0",
|
||||||
"babel-loader": "^8.2.2",
|
"babel-loader": "^8.2.3",
|
||||||
"babel-plugin-istanbul": "^5.2.0",
|
"babel-plugin-istanbul": "^5.2.0",
|
||||||
"base64-js": "^1.5.1",
|
"base64-js": "^1.5.1",
|
||||||
"content-disposition": "^0.5.3",
|
"content-disposition": "^0.5.4",
|
||||||
"copy-webpack-plugin": "^5.1.2",
|
"copy-webpack-plugin": "^5.1.2",
|
||||||
"core-js": "^3.10.1",
|
"core-js": "^3.20.3",
|
||||||
"crc": "^3.8.0",
|
"crc": "^3.8.0",
|
||||||
"cross-env": "^6.0.3",
|
"cross-env": "^6.0.3",
|
||||||
"css-loader": "^3.6.0",
|
"css-loader": "^3.6.0",
|
||||||
@@ -98,7 +96,7 @@
|
|||||||
"html-loader": "^0.5.5",
|
"html-loader": "^0.5.5",
|
||||||
"http_ece": "^1.1.0",
|
"http_ece": "^1.1.0",
|
||||||
"husky": "^3.0.9",
|
"husky": "^3.0.9",
|
||||||
"intl-pluralrules": "^1.2.2",
|
"intl-pluralrules": "^1.3.1",
|
||||||
"lint-staged": "^9.4.2",
|
"lint-staged": "^9.4.2",
|
||||||
"mocha": "^6.2.2",
|
"mocha": "^6.2.2",
|
||||||
"morgan": "^1.9.1",
|
"morgan": "^1.9.1",
|
||||||
@@ -117,7 +115,7 @@
|
|||||||
"script-loader": "^0.7.2",
|
"script-loader": "^0.7.2",
|
||||||
"sinon": "^7.5.0",
|
"sinon": "^7.5.0",
|
||||||
"string-hash": "^1.1.3",
|
"string-hash": "^1.1.3",
|
||||||
"stylelint": "^13.12.0",
|
"stylelint": "^13.13.1",
|
||||||
"stylelint-config-standard": "^19.0.0",
|
"stylelint-config-standard": "^19.0.0",
|
||||||
"stylelint-no-unsupported-browser-features": "^4.1.4",
|
"stylelint-no-unsupported-browser-features": "^4.1.4",
|
||||||
"svgo": "^1.3.2",
|
"svgo": "^1.3.2",
|
||||||
@@ -127,7 +125,7 @@
|
|||||||
"webpack": "4.38.0",
|
"webpack": "4.38.0",
|
||||||
"webpack-cli": "^3.3.12",
|
"webpack-cli": "^3.3.12",
|
||||||
"webpack-dev-middleware": "^3.7.3",
|
"webpack-dev-middleware": "^3.7.3",
|
||||||
"webpack-dev-server": "^3.11.2",
|
"webpack-dev-server": "^3.11.3",
|
||||||
"webpack-manifest-plugin": "^2.2.0",
|
"webpack-manifest-plugin": "^2.2.0",
|
||||||
"webpack-unassert-loader": "^1.2.0"
|
"webpack-unassert-loader": "^1.2.0"
|
||||||
},
|
},
|
||||||
@@ -135,23 +133,24 @@
|
|||||||
"@dannycoates/express-ws": "^5.0.3",
|
"@dannycoates/express-ws": "^5.0.3",
|
||||||
"@fluent/bundle": "^0.13.0",
|
"@fluent/bundle": "^0.13.0",
|
||||||
"@fluent/langneg": "^0.3.0",
|
"@fluent/langneg": "^0.3.0",
|
||||||
"@google-cloud/storage": "^5.8.3",
|
"@google-cloud/storage": "^5.17.0",
|
||||||
"@sentry/node": "^5.30.0",
|
"@sentry/node": "^5.30.0",
|
||||||
"aws-sdk": "^2.884.0",
|
"aws-sdk": "^2.1058.0",
|
||||||
"body-parser": "^1.19.0",
|
"body-parser": "^1.19.1",
|
||||||
"choo": "^7.0.0",
|
"choo": "^7.0.0",
|
||||||
"cldr-core": "^35.1.0",
|
"cldr-core": "^35.1.0",
|
||||||
"configstore": "github:dannycoates/configstore#master",
|
"configstore": "github:dannycoates/configstore#master",
|
||||||
"convict": "^5.2.0",
|
"convict": "^5.2.1",
|
||||||
"express": "^4.17.1",
|
"double-ended-queue": "^2.1.0-0",
|
||||||
|
"express": "^4.17.2",
|
||||||
"helmet": "^3.23.3",
|
"helmet": "^3.23.3",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"mozlog": "^2.2.0",
|
"mozlog": "^2.2.0",
|
||||||
"node-fetch": "^2.6.1",
|
"node-fetch": "^2.6.7",
|
||||||
"redis": "^2.8.0",
|
"redis": "^3.1.1",
|
||||||
"redis-mock": "^0.47.0",
|
"redis-mock": "^0.47.0",
|
||||||
"selenium-standalone": "^6.23.0",
|
"selenium-standalone": "^6.24.0",
|
||||||
"ua-parser-js": "^0.7.28"
|
"ua-parser-js": "^0.7.31"
|
||||||
},
|
},
|
||||||
"availableLanguages": [
|
"availableLanguages": [
|
||||||
"en-US",
|
"en-US",
|
||||||
|
|||||||
@@ -2,22 +2,17 @@
|
|||||||
"name": "firefox-send",
|
"name": "firefox-send",
|
||||||
"description": "File Sharing Experiment",
|
"description": "File Sharing Experiment",
|
||||||
"repository": {
|
"repository": {
|
||||||
"url": "https://github.com/mozilla/send/",
|
"url": "https://github.com/send/send/",
|
||||||
"license": "MPL-2.0"
|
"license": "MPL-2.0"
|
||||||
},
|
},
|
||||||
"participate": {
|
"participate": {
|
||||||
"home": "https://github.com/mozilla/send/blob/master/README.md",
|
"home": "https://github.com/send/send/blob/master/README.md",
|
||||||
"docs": "https://github.com/mozilla/send/blob/master/README.md"
|
"docs": "https://github.com/send/send/blob/master/README.md"
|
||||||
},
|
},
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"list": "https://github.com/mozilla/send/issues",
|
"list": "https://gitlab.com/send/send/issues",
|
||||||
"report": "https://github.com/mozilla/send/issues/new"
|
"report": "https://gitlab.com/send/send/issues/new"
|
||||||
},
|
},
|
||||||
"urls": {
|
|
||||||
"prod": "https://send.firefox.com/",
|
|
||||||
"stage": "https://stage.send.nonprod.cloudops.mozgcp.net/",
|
|
||||||
"dev": "https://send2.dev.lcip.org/"
|
|
||||||
},
|
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"JavaScript",
|
"JavaScript",
|
||||||
"jQuery",
|
"jQuery",
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ notSupportedOutdatedDetail = Helaas ondersteunt deze versie van Firefox de webte
|
|||||||
updateFirefox = Firefox bijwerken
|
updateFirefox = Firefox bijwerken
|
||||||
deletePopupCancel = Annuleren
|
deletePopupCancel = Annuleren
|
||||||
deleteButtonHover = Verwijderen
|
deleteButtonHover = Verwijderen
|
||||||
footerText = Niet aangesloten aan Mozilla of Firefox.
|
footerText = Niet gelieerd aan Mozilla of Firefox.
|
||||||
footerLinkDonate = Doneren
|
footerLinkDonate = Doneren
|
||||||
footerLinkCli = CLI
|
footerLinkCli = CLI
|
||||||
footerLinkDmca = DMCA
|
footerLinkDmca = DMCA
|
||||||
@@ -52,7 +52,7 @@ passwordSetError = Dit wachtwoord kon niet worden ingesteld
|
|||||||
-send-short-brand = Send
|
-send-short-brand = Send
|
||||||
-firefox = Firefox
|
-firefox = Firefox
|
||||||
-mozilla = Mozilla
|
-mozilla = Mozilla
|
||||||
introTitle = Eenvoudig, privé bestanden delen
|
introTitle = Bestanden delen, eenvoudig en privé
|
||||||
introDescription = Met { -send-brand } kunt u bestanden delen met end-to-endversleuteling en een koppeling die automatisch verloopt. Hierdoor kunt u privé houden wat u wilt delen en er zeker van zijn dat uw zaken niet voor altijd online blijven.
|
introDescription = Met { -send-brand } kunt u bestanden delen met end-to-endversleuteling en een koppeling die automatisch verloopt. Hierdoor kunt u privé houden wat u wilt delen en er zeker van zijn dat uw zaken niet voor altijd online blijven.
|
||||||
notifyUploadEncryptDone = Uw bestand is versleuteld en klaar voor verzending
|
notifyUploadEncryptDone = Uw bestand is versleuteld en klaar voor verzending
|
||||||
# downloadCount is from the downloadCount string and timespan is a timespanMinutes string. ex. 'Expires after 2 downloads or 25 minutes'
|
# downloadCount is from the downloadCount string and timespan is a timespanMinutes string. ex. 'Expires after 2 downloads or 25 minutes'
|
||||||
|
|||||||
2
public/robots.txt
Normal file
2
public/robots.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
User-agent: *
|
||||||
|
Disallow: /
|
||||||
@@ -15,6 +15,7 @@ module.exports = {
|
|||||||
FOOTER_SOURCE_URL: config.footer_source_url
|
FOOTER_SOURCE_URL: config.footer_source_url
|
||||||
},
|
},
|
||||||
DEFAULTS: {
|
DEFAULTS: {
|
||||||
|
DOWNLOADS: config.default_downloads,
|
||||||
DOWNLOAD_COUNTS: config.download_counts,
|
DOWNLOAD_COUNTS: config.download_counts,
|
||||||
EXPIRE_TIMES_SECONDS: config.expire_times_seconds,
|
EXPIRE_TIMES_SECONDS: config.expire_times_seconds,
|
||||||
EXPIRE_SECONDS: config.default_expire_seconds
|
EXPIRE_SECONDS: config.default_expire_seconds
|
||||||
|
|||||||
@@ -3,6 +3,26 @@ const { tmpdir } = require('os');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { randomBytes } = require('crypto');
|
const { randomBytes } = require('crypto');
|
||||||
|
|
||||||
|
convict.addFormat({
|
||||||
|
name: 'positive-int-array',
|
||||||
|
coerce: ints => {
|
||||||
|
// can take: int[] | string[] | string (csv), returns -> int[]
|
||||||
|
const ints_arr = Array.isArray(ints) ? ints : ints.trim().split(',');
|
||||||
|
return ints_arr.map(int =>
|
||||||
|
typeof int === 'number'
|
||||||
|
? int
|
||||||
|
: parseInt(int.replace(/['"]+/g, '').trim(), 10)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
validate: ints => {
|
||||||
|
// takes: int[], errors if any NaNs, negatives, or floats present
|
||||||
|
for (const int of ints) {
|
||||||
|
if (typeof int !== 'number' || isNaN(int) || int < 0 || int % 1 > 0)
|
||||||
|
throw new Error('must be a comma-separated list of positive integers');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const conf = convict({
|
const conf = convict({
|
||||||
s3_bucket: {
|
s3_bucket: {
|
||||||
format: String,
|
format: String,
|
||||||
@@ -25,7 +45,7 @@ const conf = convict({
|
|||||||
env: 'GCS_BUCKET'
|
env: 'GCS_BUCKET'
|
||||||
},
|
},
|
||||||
expire_times_seconds: {
|
expire_times_seconds: {
|
||||||
format: Array,
|
format: 'positive-int-array',
|
||||||
default: [300, 3600, 86400, 604800],
|
default: [300, 3600, 86400, 604800],
|
||||||
env: 'EXPIRE_TIMES_SECONDS'
|
env: 'EXPIRE_TIMES_SECONDS'
|
||||||
},
|
},
|
||||||
@@ -40,10 +60,15 @@ const conf = convict({
|
|||||||
env: 'MAX_EXPIRE_SECONDS'
|
env: 'MAX_EXPIRE_SECONDS'
|
||||||
},
|
},
|
||||||
download_counts: {
|
download_counts: {
|
||||||
format: Array,
|
format: 'positive-int-array',
|
||||||
default: [1, 2, 3, 4, 5, 20, 50, 100],
|
default: [1, 2, 3, 4, 5, 20, 50, 100],
|
||||||
env: 'DOWNLOAD_COUNTS'
|
env: 'DOWNLOAD_COUNTS'
|
||||||
},
|
},
|
||||||
|
default_downloads: {
|
||||||
|
format: Number,
|
||||||
|
default: 1,
|
||||||
|
env: 'DEFAULT_DOWNLOADS'
|
||||||
|
},
|
||||||
max_downloads: {
|
max_downloads: {
|
||||||
format: Number,
|
format: Number,
|
||||||
default: 100,
|
default: 100,
|
||||||
@@ -64,6 +89,26 @@ const conf = convict({
|
|||||||
default: 'localhost',
|
default: 'localhost',
|
||||||
env: 'REDIS_HOST'
|
env: 'REDIS_HOST'
|
||||||
},
|
},
|
||||||
|
redis_port: {
|
||||||
|
format: Number,
|
||||||
|
default: 6379,
|
||||||
|
env: 'REDIS_PORT'
|
||||||
|
},
|
||||||
|
redis_user: {
|
||||||
|
format: String,
|
||||||
|
default: '',
|
||||||
|
env: 'REDIS_USER'
|
||||||
|
},
|
||||||
|
redis_password: {
|
||||||
|
format: String,
|
||||||
|
default: '',
|
||||||
|
env: 'REDIS_PASSWORD'
|
||||||
|
},
|
||||||
|
redis_db: {
|
||||||
|
format: String,
|
||||||
|
default: '',
|
||||||
|
env: 'REDIS_DB'
|
||||||
|
},
|
||||||
redis_event_expire: {
|
redis_event_expire: {
|
||||||
format: Boolean,
|
format: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
@@ -120,6 +165,11 @@ const conf = convict({
|
|||||||
default: 'https://send.firefox.com',
|
default: 'https://send.firefox.com',
|
||||||
env: 'BASE_URL'
|
env: 'BASE_URL'
|
||||||
},
|
},
|
||||||
|
detect_base_url: {
|
||||||
|
format: Boolean,
|
||||||
|
default: false,
|
||||||
|
env: 'DETECT_BASE_URL'
|
||||||
|
},
|
||||||
file_dir: {
|
file_dir: {
|
||||||
format: 'String',
|
format: 'String',
|
||||||
default: `${tmpdir()}${path.sep}send-${randomBytes(4).toString('hex')}`,
|
default: `${tmpdir()}${path.sep}send-${randomBytes(4).toString('hex')}`,
|
||||||
@@ -196,4 +246,17 @@ const conf = convict({
|
|||||||
conf.validate({ allowed: 'strict' });
|
conf.validate({ allowed: 'strict' });
|
||||||
|
|
||||||
const props = conf.getProperties();
|
const props = conf.getProperties();
|
||||||
module.exports = props;
|
|
||||||
|
const deriveBaseUrl = req => {
|
||||||
|
if (!props.detect_base_url) {
|
||||||
|
return props.base_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
const protocol = req.secure ? 'https://' : 'http://';
|
||||||
|
return `${protocol}${req.headers.host}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
...props,
|
||||||
|
deriveBaseUrl
|
||||||
|
};
|
||||||
|
|||||||
@@ -36,9 +36,14 @@ module.exports = function(app) {
|
|||||||
defaultSrc: ["'self'"],
|
defaultSrc: ["'self'"],
|
||||||
connectSrc: [
|
connectSrc: [
|
||||||
"'self'",
|
"'self'",
|
||||||
config.base_url.replace(/^https:\/\//, 'wss://')
|
function(req) {
|
||||||
|
const baseUrl = config.deriveBaseUrl(req);
|
||||||
|
const r = baseUrl.replace(/^http(s?):\/\//, 'ws$1://');
|
||||||
|
console.log([baseUrl, r]);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
],
|
],
|
||||||
imgSrc: ["'self'"],
|
imgSrc: ["'self'", 'data:'],
|
||||||
scriptSrc: [
|
scriptSrc: [
|
||||||
"'self'",
|
"'self'",
|
||||||
function(req) {
|
function(req) {
|
||||||
@@ -52,10 +57,6 @@ module.exports = function(app) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
csp.directives.connectSrc.push(
|
|
||||||
config.base_url.replace(/^https:\/\//, 'wss://')
|
|
||||||
);
|
|
||||||
|
|
||||||
app.use(helmet.contentSecurityPolicy(csp));
|
app.use(helmet.contentSecurityPolicy(csp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,8 +28,7 @@ module.exports = async function(req, res) {
|
|||||||
//this hasn't been updated to expiration time setting yet
|
//this hasn't been updated to expiration time setting yet
|
||||||
//if you want to fallback to this code add this
|
//if you want to fallback to this code add this
|
||||||
await storage.set(newId, fileStream, meta, config.default_expire_seconds);
|
await storage.set(newId, fileStream, meta, config.default_expire_seconds);
|
||||||
const protocol = config.env === 'production' ? 'https' : req.protocol;
|
const url = `${config.deriveBaseUrl(req)}/download/${newId}/`;
|
||||||
const url = `${protocol}://${req.get('host')}/download/${newId}/`;
|
|
||||||
res.set('WWW-Authenticate', `send-v1 ${meta.nonce}`);
|
res.set('WWW-Authenticate', `send-v1 ${meta.nonce}`);
|
||||||
res.json({
|
res.json({
|
||||||
url,
|
url,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ module.exports = function(ws, req) {
|
|||||||
|
|
||||||
const fileInfo = JSON.parse(message);
|
const fileInfo = JSON.parse(message);
|
||||||
const timeLimit = fileInfo.timeLimit || config.default_expire_seconds;
|
const timeLimit = fileInfo.timeLimit || config.default_expire_seconds;
|
||||||
const dlimit = fileInfo.dlimit || 1;
|
const dlimit = fileInfo.dlimit || config.default_downloads;
|
||||||
const metadata = fileInfo.fileMetadata;
|
const metadata = fileInfo.fileMetadata;
|
||||||
const auth = fileInfo.authorization;
|
const auth = fileInfo.authorization;
|
||||||
const user = await fxa.verify(fileInfo.bearer);
|
const user = await fxa.verify(fileInfo.bearer);
|
||||||
@@ -65,8 +65,7 @@ module.exports = function(ws, req) {
|
|||||||
nonce: crypto.randomBytes(16).toString('base64')
|
nonce: crypto.randomBytes(16).toString('base64')
|
||||||
};
|
};
|
||||||
|
|
||||||
const protocol = config.env === 'production' ? 'https' : req.protocol;
|
const url = `${config.deriveBaseUrl(req)}/download/${newId}/`;
|
||||||
const url = `${protocol}://${req.get('host')}/download/${newId}/`;
|
|
||||||
|
|
||||||
ws.send(
|
ws.send(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ module.exports = async function(req) {
|
|||||||
if (config.survey_url) {
|
if (config.survey_url) {
|
||||||
prefs.surveyUrl = config.survey_url;
|
prefs.surveyUrl = config.survey_url;
|
||||||
}
|
}
|
||||||
|
const baseUrl = config.deriveBaseUrl(req);
|
||||||
return {
|
return {
|
||||||
archive: {
|
archive: {
|
||||||
numFiles: 0
|
numFiles: 0
|
||||||
@@ -33,7 +34,7 @@ module.exports = async function(req) {
|
|||||||
title: 'Send',
|
title: 'Send',
|
||||||
description:
|
description:
|
||||||
'Encrypt and send files with a link that automatically expires to ensure your important documents don’t stay online forever.',
|
'Encrypt and send files with a link that automatically expires to ensure your important documents don’t stay online forever.',
|
||||||
baseUrl: config.base_url,
|
baseUrl,
|
||||||
ui: {},
|
ui: {},
|
||||||
storage: {
|
storage: {
|
||||||
files: []
|
files: []
|
||||||
|
|||||||
@@ -8,8 +8,10 @@ module.exports = function(config) {
|
|||||||
|
|
||||||
//eslint-disable-next-line security/detect-non-literal-require
|
//eslint-disable-next-line security/detect-non-literal-require
|
||||||
const redis = require(redis_lib);
|
const redis = require(redis_lib);
|
||||||
const client = redis.createClient({
|
|
||||||
|
var client_config = {
|
||||||
host: config.redis_host,
|
host: config.redis_host,
|
||||||
|
port: config.redis_port,
|
||||||
retry_strategy: options => {
|
retry_strategy: options => {
|
||||||
if (options.total_retry_time > config.redis_retry_time) {
|
if (options.total_retry_time > config.redis_retry_time) {
|
||||||
client.emit('error', 'Retry time exhausted');
|
client.emit('error', 'Retry time exhausted');
|
||||||
@@ -18,7 +20,14 @@ module.exports = function(config) {
|
|||||||
|
|
||||||
return config.redis_retry_delay;
|
return config.redis_retry_delay;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
if (config.redis_user != null && config.redis_user.length > 0)
|
||||||
|
client_config.user = config.redis_user;
|
||||||
|
if (config.redis_password != null && config.redis_password.length > 0)
|
||||||
|
client_config.password = config.redis_password;
|
||||||
|
if (config.redis_db != null && config.redis_db.length > 0)
|
||||||
|
client_config.db = config.redis_db;
|
||||||
|
const client = redis.createClient(client_config);
|
||||||
|
|
||||||
client.ttlAsync = promisify(client.ttl);
|
client.ttlAsync = promisify(client.ttl);
|
||||||
client.hgetallAsync = promisify(client.hgetall);
|
client.hgetallAsync = promisify(client.hgetall);
|
||||||
|
|||||||
Reference in New Issue
Block a user