diff --git a/.gitignore b/.gitignore index 28f1ba7..bdd050d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules -.DS_Store \ No newline at end of file +.DS_Store +fqdn.env \ No newline at end of file diff --git a/README.md b/README.md index 77eecce..53b66b3 100644 --- a/README.md +++ b/README.md @@ -53,13 +53,32 @@ ShareDrop uses WebRTC only and isn't compatible with Safari browsers. Snapdrop u ## Local Development [Install docker with docker-compose.](https://docs.docker.com/compose/install/) +Clone the repository: ``` git clone git@github.com:RobinLinus/snapdrop.git cd snapdrop - docker-compose up + docker-compose up -d ``` -Now point your browser to http://localhost:8080. +To restart the containers run `docker-compose restart`. +To stop the containers run `docker-compose stop`. + + +Now point your browser to `http://localhost:8080`. + +### Testing PWA related features +PWAs require that the app is served under a correctly set up and trusted TLS endpoint. + +The nginx container creates a CA certificate and a website certificate for you. To correctly set the common name of the certificate you need to change the FQDN environment variable in `fqdn.env` to the fully qualified domain name of your workstation. + +If you want to test PWA features you need to trust the CA of the certificate for your local deployment. For your convenience you can download the crt file from `http://:8080/ca.crt`. Install that certificate to the trust store of your operating system. +- On windows make sure to install it to the `Trusted Root Certification Authorities` store. +- On macOS double click the installed CA certificate in `Keychain Access` expand `Trust` and select `Always Trust` for SSL. +- Firefox uses its own trust store. To install the CA point Firefox at `http://:8080/ca.crt`. When prompted select `Trust this CA to identify websites` and click OK. +- When using Chrome you need to restart Chrome so it reloads the trust store (`chrome://restart`). Additionally, after installing a new cert you need to clear the Storage (DevTools -> Application -> Clear storagae -> Clear site data). + +Please note that the certificates (CA and webserver cert) expire after a day. +Also whenever you restart the nginx docker container new certificates are created.     ## Deployment Notes The client expects the server at http(s)://your.domain/server. diff --git a/docker-compose.yml b/docker-compose.yml index 0d7d02c..4c7f67b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,9 +8,18 @@ services: - ./server/:/home/node/app command: ash -c "npm i && node index.js" nginx: - image: "nginx:alpine" + build: + context: ./ + dockerfile: nginx-with-openssl.Dockerfile + image: "nginx-with-openssl" volumes: - ./client:/usr/share/nginx/html - ./nginx/default.conf:/etc/nginx/conf.d/default.conf + - ./certs:/etc/ssl/certs + - ./openssl:/mnt/openssl ports: - "8080:80" + - "443:443" + env_file: fqdn.env + entrypoint: /mnt/openssl/create.sh + command: ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/fqdn.env b/fqdn.env new file mode 100644 index 0000000..3302bc9 --- /dev/null +++ b/fqdn.env @@ -0,0 +1 @@ +FQDN=localhost \ No newline at end of file diff --git a/nginx-with-openssl.Dockerfile b/nginx-with-openssl.Dockerfile new file mode 100644 index 0000000..4752a53 --- /dev/null +++ b/nginx-with-openssl.Dockerfile @@ -0,0 +1,3 @@ +FROM nginx:alpine + +RUN apk add --no-cache openssl \ No newline at end of file diff --git a/nginx/default.conf b/nginx/default.conf index 6fd995c..d5db3cd 100644 --- a/nginx/default.conf +++ b/nginx/default.conf @@ -18,6 +18,47 @@ server { proxy_set_header X-Forwarded-for $remote_addr; } + location /ca.crt { + alias /etc/ssl/certs/snapdropCA.crt; + } + + #error_page 404 /404.html; + + # redirect server error pages to the static page /50x.html + # + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } +} + +server { + listen 443 ssl http2; + ssl_certificate /etc/ssl/certs/snapdrop-dev.crt; + ssl_certificate_key /etc/ssl/certs/snapdrop-dev.key; + + #server_name ; + + #charset koi8-r; + #access_log /var/log/nginx/host.access.log main; + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + } + + location /server { + proxy_connect_timeout 300; + proxy_pass http://node:3000; + proxy_set_header Connection "upgrade"; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header X-Forwarded-for $remote_addr; + } + + location /ca.crt { + alias /etc/ssl/certs/snapdropCA.crt; + } + #error_page 404 /404.html; # redirect server error pages to the static page /50x.html diff --git a/openssl/create.sh b/openssl/create.sh new file mode 100755 index 0000000..7c081c3 --- /dev/null +++ b/openssl/create.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +cnf_dir='/mnt/openssl/' +certs_dir='/etc/ssl/certs/' +openssl req -config ${cnf_dir}snapdropCA.cnf -new -x509 -days 1 -keyout ${certs_dir}snapdropCA.key -out ${certs_dir}snapdropCA.crt +openssl req -config ${cnf_dir}snapdropCert.cnf -new -out /tmp/snapdrop-dev.csr -keyout ${certs_dir}snapdrop-dev.key +openssl x509 -req -in /tmp/snapdrop-dev.csr -CA ${certs_dir}snapdropCA.crt -CAkey ${certs_dir}snapdropCA.key -CAcreateserial -extensions req_ext -extfile ${cnf_dir}snapdropCert.cnf -sha512 -days 1 -out ${certs_dir}snapdrop-dev.crt + +exec "$@" \ No newline at end of file diff --git a/openssl/snapdropCA.cnf b/openssl/snapdropCA.cnf new file mode 100644 index 0000000..d8502c3 --- /dev/null +++ b/openssl/snapdropCA.cnf @@ -0,0 +1,26 @@ +[ req ] +default_bits = 2048 +default_md = sha256 +default_days = 1 +encrypt_key = no +distinguished_name = subject +x509_extensions = x509_ext +string_mask = utf8only +prompt = no + +[ subject ] +organizationName = Snapdrop +OU = CA +commonName = snapdrop-CA + +[ x509_ext ] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer + +# You only need digitalSignature below. *If* you don't allow +# RSA Key transport (i.e., you use ephemeral cipher suites), then +# omit keyEncipherment because that's key transport. + +basicConstraints = critical, CA:TRUE, pathlen:0 +keyUsage = critical, digitalSignature, keyEncipherment, cRLSign, keyCertSign + diff --git a/openssl/snapdropCert.cnf b/openssl/snapdropCert.cnf new file mode 100644 index 0000000..a98b70d --- /dev/null +++ b/openssl/snapdropCert.cnf @@ -0,0 +1,29 @@ +[ req ] +default_bits = 2048 +default_md = sha256 +default_days = 1 +encrypt_key = no +distinguished_name = subject +req_extensions = req_ext +string_mask = utf8only +prompt = no + +[ subject ] +organizationName = Snapdrop +OU = Development + +# Use a friendly name here because it's presented to the user. The server's DNS +# names are placed in Subject Alternate Names. Plus, DNS names here is deprecated +# by both IETF and CA/Browser Forums. If you place a DNS name here, then you +# must include the DNS name in the SAN too (otherwise, Chrome and others that +# strictly follow the CA/Browser Baseline Requirements will fail). + +commonName = ${ENV::FQDN} + +[ req_ext ] +subjectKeyIdentifier = hash +basicConstraints = CA:FALSE +keyUsage = digitalSignature, keyEncipherment +subjectAltName = DNS:${ENV::FQDN} +nsComment = "OpenSSL Generated Certificate" +extendedKeyUsage = serverAuth \ No newline at end of file