diff --git a/.gitignore b/.gitignore index 252a571..2f57b2e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ # Env file .env +# Certbot files +/data/certbot/ + # The directory Mix will write compiled artifacts to. /_build/ diff --git a/README.md b/README.md index 11e4d69..716e569 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,8 @@ BOOKMARK_ARCHIVE_DELAY=1000 $ docker login -u bookmarkorg -p ``` +4. Optional: You can use HTTPS on localhost in port 4001. If you are using Google Chrome, open `chrome://flags/#allow-insecure-localhost` to enable the use of self-signed certificates on localhost. + ## Basic Commands: Development Run the app: diff --git a/assets/css/app.css b/assets/css/app.css index 76b36d9..ad82ffa 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -969,11 +969,21 @@ body { } } - - - /***************************************** Bulk Archives **************************************/ @media screen and (max-width: 350px) {.responsive-form {width: auto;}} @media screen and (min-width: 350px) {.responsive-form {width: 300px;}} -@media screen and (min-width: 550px) {.responsive-form {width: 500px;}} \ No newline at end of file +@media screen and (min-width: 550px) {.responsive-form {width: 500px;}} + + +/******************************************** Withdraw *****************************************/ + +@media screen and (max-width: 350px) { + .donate-button.scan{ width: auto; } + .donate-button.withdraw{ width: auto; margin-top: 50px;} +} + +@media screen and (min-width: 350px) { + .donate-button.scan{ width: auto; margin-bottom: 10px; padding-left: auto;} + .donate-button.withdraw{ width: 100%;} +} \ No newline at end of file diff --git a/assets/js/app.js b/assets/js/app.js index 6290f1d..6af48ec 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -29,9 +29,20 @@ import QrScanner from "../vendor/qr-scanner.min.js" let Hooks = {}; Hooks.ScanCode = { - mounted() { + async mounted() { const btn = document.getElementById("scan-btn"); + if (await QrScanner.hasCamera()) { + showScanButton(); + } + + function showScanButton() { + var scanButton = document.getElementById('scan-btn'); + scanButton.removeAttribute('hidden'); + var withdrawButton = document.getElementById('withdraw-btn'); + withdrawButton.style.width = '66%'; + } + btn.addEventListener("click", () => { this.pushEvent("scan-btn-clicked"); }); @@ -43,7 +54,9 @@ Hooks.ScanCode = { video, result => { qrScanner.stop(); - this.pushEvent("modal-closed", result); + qr_data = result["data"] + console.log("QR data: ", qr_data) + this.pushEvent("modal-closed", qr_data); }, { highlightScanRegion: true, highlightCodeOutline: true, diff --git a/config/dev.exs b/config/dev.exs index b37fc8c..841155f 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -39,16 +39,13 @@ config :bookmark, BookmarkWeb.Endpoint, # # Note that this task requires Erlang/OTP 20 or later. # Run `mix help phx.gen.cert` for more information. -# -# The `http:` config above can be replaced with: -# -# https: [ -# port: 4001, -# cipher_suite: :strong, -# keyfile: "priv/cert/selfsigned_key.pem", -# certfile: "priv/cert/selfsigned.pem" -# ], -# +config :bookmark, BookmarkWeb.Endpoint, + https: [ + port: 4001, + cipher_suite: :strong, + keyfile: "priv/cert/selfsigned_key.pem", + certfile: "priv/cert/selfsigned.pem" + ] # If desired, both `http:` and `https:` keys can be # configured to run both http and https servers on # different ports. diff --git a/data/nginx/app.conf b/data/nginx/app.conf new file mode 100644 index 0000000..20bb2fe --- /dev/null +++ b/data/nginx/app.conf @@ -0,0 +1,37 @@ +upstream bookmark { + server bookmark-app:4000; +} + +server { + listen 80; + listen [::]:80; + + server_name alpha.bookmark.org; + server_tokens off; + + location /.well-known/acme-challenge/ { + root /var/www/certbot; + } + + location / { + return 301 https://$host$request_uri; + } +} + +server { + listen 443 default_server ssl http2; + listen [::]:443 ssl http2; + + server_name alpha.bookmark.org; + + ssl_certificate /etc/letsencrypt/live/alpha.bookmark.org/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/alpha.bookmark.org/privkey.pem; + + location / { + proxy_pass http://bookmark; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + } +} + diff --git a/docker-compose.yml b/docker-compose.yml index 15197cb..2e47f09 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,23 @@ version: "3.9" services: + nginx: + image: nginx:1.15-alpine + command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'" + ports: + - "80:80" + - "443:443" + volumes: + - ./data/nginx:/etc/nginx/conf.d + - ./data/certbot/conf:/etc/letsencrypt + - ./data/certbot/www:/var/www/certbot + + certbot: + image: certbot/certbot + entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'" + volumes: + - ./data/certbot/conf:/etc/letsencrypt + - ./data/certbot/www:/var/www/certbot + bookmark: image: bookmarkorg/bookmark:latest container_name: bookmark-app @@ -7,12 +25,13 @@ services: environment: OPENAI_API_KEY: ${OPENAI_API_KEY} BOOKMARK_ARCHIVE_DELAY: ${BOOKMARK_ARCHIVE_DELAY} + PHX_HOST: alpha.bookmark.org MIX_ENV: prod depends_on: - bookmark-db - archivebox ports: - - '80:4000' + - '4000:4000' env_file: - base.env volumes: diff --git a/init-letsencrypt.sh b/init-letsencrypt.sh new file mode 100755 index 0000000..0c25c2a --- /dev/null +++ b/init-letsencrypt.sh @@ -0,0 +1,84 @@ +#!/bin/bash + +# IMPORTANT: +# Don't forget to check and configure the `domains` and `email` variables before running this script. +# You can run it, with `chmod +x init-letsencrypt.sh` and `sudo ./init-letsencrypt.sh` + +if ! [ -x "$(command -v docker)" ]; then + echo 'Error: docker compose is not installed.' >&2 + exit 1 +fi + +domains=(alpha.bookmark.org) +rsa_key_size=4096 +data_path="./data/certbot" +email="" # Adding a valid address is strongly recommended +staging=0 # Set to 1 if you're testing your setup to avoid hitting request limits + +if [ -d "$data_path" ]; then + read -p "Existing data found for $domains. Continue and replace existing certificate? (y/N) " decision + if [ "$decision" != "Y" ] && [ "$decision" != "y" ]; then + exit + fi +fi + + +if [ ! -e "$data_path/conf/options-ssl-nginx.conf" ] || [ ! -e "$data_path/conf/ssl-dhparams.pem" ]; then + echo "### Downloading recommended TLS parameters ..." + mkdir -p "$data_path/conf" + curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf > "$data_path/conf/options-ssl-nginx.conf" + curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot/certbot/ssl-dhparams.pem > "$data_path/conf/ssl-dhparams.pem" + echo +fi + +echo "### Creating dummy certificate for $domains ..." +path="/etc/letsencrypt/live/$domains" +mkdir -p "$data_path/conf/live/$domains" +docker compose run --rm --entrypoint "\ + openssl req -x509 -nodes -newkey rsa:$rsa_key_size -days 1\ + -keyout '$path/privkey.pem' \ + -out '$path/fullchain.pem' \ + -subj '/CN=localhost'" certbot +echo + + +echo "### Starting nginx ..." +docker compose up --force-recreate -d nginx +echo + +echo "### Deleting dummy certificate for $domains ..." +docker compose run --rm --entrypoint "\ + rm -Rf /etc/letsencrypt/live/$domains && \ + rm -Rf /etc/letsencrypt/archive/$domains && \ + rm -Rf /etc/letsencrypt/renewal/$domains.conf" certbot +echo + + +echo "### Requesting Let's Encrypt certificate for $domains ..." +#Join $domains to -d args +domain_args="" +for domain in "${domains[@]}"; do + domain_args="$domain_args -d $domain" +done + +# Select appropriate email arg +case "$email" in + "") email_arg="--register-unsafely-without-email" ;; + *) email_arg="--email $email" ;; +esac + +# Enable staging mode if needed +if [ $staging != "0" ]; then staging_arg="--staging"; fi + +docker compose run --rm --entrypoint "\ + certbot certonly --webroot -w /var/www/certbot \ + $staging_arg \ + $email_arg \ + $domain_args \ + --rsa-key-size $rsa_key_size \ + --agree-tos \ + --force-renewal" certbot +echo + +echo "### Reloading nginx ..." +docker compose exec nginx nginx -s reload diff --git a/lib/bookmark/withdrawals.ex b/lib/bookmark/withdrawals.ex index a296823..7c7dd95 100644 --- a/lib/bookmark/withdrawals.ex +++ b/lib/bookmark/withdrawals.ex @@ -13,7 +13,7 @@ defmodule Bookmark.Withdrawals do headers: [{:x_api_key, key}], method: :post, body: body, - receive_timeout: 30_000 + receive_timeout: 60_000 ) do {:ok, response} -> case response.status do diff --git a/lib/bookmark_web/live/withdrawals.ex b/lib/bookmark_web/live/withdrawals.ex index 3aaf61e..be80133 100644 --- a/lib/bookmark_web/live/withdrawals.ex +++ b/lib/bookmark_web/live/withdrawals.ex @@ -20,8 +20,8 @@ defmodule BookmarkWeb.WithdrawalsLive do
- - + +
<%= if @show_modal do %> diff --git a/priv/cert/selfsigned.pem b/priv/cert/selfsigned.pem new file mode 100644 index 0000000..928ed2d --- /dev/null +++ b/priv/cert/selfsigned.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDfDCCAmSgAwIBAgIIfq3YHHWBHR8wDQYJKoZIhvcNAQELBQAwQzEaMBgGA1UE +CgwRUGhvZW5peCBGcmFtZXdvcmsxJTAjBgNVBAMMHFNlbGYtc2lnbmVkIHRlc3Qg +Y2VydGlmaWNhdGUwHhcNMjMwNjI2MDAwMDAwWhcNMjQwNjI2MDAwMDAwWjBDMRow +GAYDVQQKDBFQaG9lbml4IEZyYW1ld29yazElMCMGA1UEAwwcU2VsZi1zaWduZWQg +dGVzdCBjZXJ0aWZpY2F0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AL3eFZsvAiEnbhEwaS+RqppkyTQpwADD/U97qPYt4BFjC3lOHBfh+aamwrkaBvpL +eGbvnlm77ihP2sqSPNwstEKcyBR7xJleif3EX0NOE2b8SHZVx420NznUoHdfnwUa +fa7TkzhoTiGA7wdsnipWV+9Cn0U4v/sWqUTxvjXYQLT3UAaUITd7QiZLjZu8/sP5 +cK1sjx3J/NjrM1jXjYwcHLpFj7cG0P4nF4wZqBnudKb2zB2A4bJ/lGvlhUF/5GeA +cXoCk4n+gDvVHOX1ucyU0vtP5GhsJAVBsiURQJfMZxAF6jKrlxKUMlSlAZyX3FCp +XjWrsKsK+RkxcttAYyq4PoECAwEAAaN0MHIwDAYDVR0TAQH/BAIwADAOBgNVHQ8B +Af8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQW +BBTZmMlASFS8Lwu3hBQRJm9qUF9fyTAUBgNVHREEDTALgglsb2NhbGhvc3QwDQYJ +KoZIhvcNAQELBQADggEBAI4K2dvGkSJjum6vnnk+y9843KsAh3mjLloMFUmZ/lox +0tpNO48Z+eWcj6Qepd92cVv80wDsykLRvKVG1DNgI0XfrCD9CL1TvH9gDQU07113 +S+S6yTcQnMZ/5Krj7ZcMrnqI1w8elqJE1AbrubOvfizU00Yk5ppU28X1QTz+NU0D +NvQS6jlpaX48Id52/bhRp4p3ne/1nH+7IT+1WGA7paLcoAfxm7KVX28DDKScU6iP +mw0/+h7TYenbOTjRnaxW6R92fE3l6ViLbInTUN0okCqUnnF3ptV4WO6ATOkxnuPu +kCTMDuA0qC9ho69t9nwLSTMuW28RH7Kcp6mX8xr56GI= +-----END CERTIFICATE----- + diff --git a/priv/cert/selfsigned_key.pem b/priv/cert/selfsigned_key.pem new file mode 100644 index 0000000..b3dee27 --- /dev/null +++ b/priv/cert/selfsigned_key.pem @@ -0,0 +1,28 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAvd4Vmy8CISduETBpL5GqmmTJNCnAAMP9T3uo9i3gEWMLeU4c +F+H5pqbCuRoG+kt4Zu+eWbvuKE/aypI83Cy0QpzIFHvEmV6J/cRfQ04TZvxIdlXH +jbQ3OdSgd1+fBRp9rtOTOGhOIYDvB2yeKlZX70KfRTi/+xapRPG+NdhAtPdQBpQh +N3tCJkuNm7z+w/lwrWyPHcn82OszWNeNjBwcukWPtwbQ/icXjBmoGe50pvbMHYDh +sn+Ua+WFQX/kZ4BxegKTif6AO9Uc5fW5zJTS+0/kaGwkBUGyJRFAl8xnEAXqMquX +EpQyVKUBnJfcUKleNauwqwr5GTFy20BjKrg+gQIDAQABAoIBAAvUkC0Ur0HIlquc +hBlSLrqjCARni46gp6JxtpPsRNdggAEFdGuqiWcwYdatv/yNgkmLqaa2tn6thxjz +JrajVHIIGdFo6tWRlfCJcVQcw8m5c3xoGOCD96LzVDJL83kabvVbOoObwC6HPZ2N +T4eczKrcUFc8U33+KfrhQzRQrqt31/qrg6H5WWTbHJqzecfJJ3Mp797s3QmsA5KI +8CC9o/BmzlaCYbllnw/mk0H4qMMqqyyNILjArvnusHyh3CvvEKD1DyG2PD6g5XZ/ +m21Brg6e8v5JkKP1vjhFLio4jp8/dOBf2eraoik4o1OmZ9BUWdZQ+eE8SPak6nwA +FlMPJU8CgYEA2LHR6QM7w7XKN4mPsw4uUrsNa/kTy72hIBY1lLRUMB5SfPdKt6Nc +rOAFk4H6SfRFIiDmzEMzm3h1VdfeTfCgcM9+WqDn7vvFYqqji4wRABvM34Dztrg0 +k4O+jdQ0/UvgwiEIoENf7C7jVAm2uXTVdRMXHuNhbZ1HFyeNHvh5MX8CgYEA4E6N +eif2L0dhHYkA2Ug2jhzqLzhZyYHJUsN2dD1S9lrkU2Ux2ZyIP6IaFsDle3yYgOD3 +qi1qBMLPizQySqbxxYv5Wv9iHPdksyd5jjWpo2WbrlgPdHI8CGe/UKiGtzvJXl7D +k55tWn/7YeMkH8Wn9CB97POBKL/paOdaeaGmj/8CgYEA0q4gbjIMmz1V/CUsp2P0 +Oc9PP1kNnBskWrP9KDUjXR0+Ce3MoTqdUh8EjOPkWp650HK4soPr2w6E1g9pPdHj +y4qRSMAEf+Adis5o77YgmUBuMieHzHDP/VQrom1dj5+ESHohjt+ylUkJEJ3ZH/qt +xoPnCMr94Lr3cVWs6R2fhzUCgYEAjt25gsqdJPPjyToPzlUOWmnURwsvNQdzQUG5 +2sOMadjugKd9nsryhQUsdL2b7JEpWTzwwfV3B11Fb7ZpKd83Msm6otjyltyDyRAl +fgxz5dy70cnI3jQ8RGZAFpGgbGiqE29sRkOsBu5pIKnZwlrUZMulKRzXcSr68ZQZ +rkrlmeUCgYEAz4kIiJQN4rzJexUfUoE4cHFKBAUzo4ghnqs3rcgV+w8zBdgIgqQF +s56jly1rthZEBDL9jN45toDnb2sT+DihgwtBOwE05TV33WMSHwMHDxcpUM557iKT +vaa1Hbek4aAUPg70TQYBuk4oylYrZm8ySYHtt0kSCf/zsV0KEI9Mdlk= +-----END RSA PRIVATE KEY----- +