diff --git a/.github/ISSUE_TEMPLATE/01-bug-report.yml b/.github/ISSUE_TEMPLATE/01-bug-report.yml new file mode 100644 index 00000000..2a92e7b6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/01-bug-report.yml @@ -0,0 +1,38 @@ +--- +name: 🐛 Bug Report +description: Create a report to help us improve +title: "[Bug]: " +labels: + - "bug" + +body: + - type: markdown + attributes: + value: | + **Thanks :heart: for taking the time to fill out this bug report!** + We kindly ask that you search to see if an issue [already exists](https://github.com/wg-easy/wg-easy/issues?q=is%3Aissue+sort%3Acreated-desc+) for the bug you encountered. + + - type: textarea + id: what-happened + attributes: + label: Describe the bug + placeholder: Tell us what you see! + value: "A bug happened!" + validations: + required: true + + - type: textarea + id: what-should-happen + attributes: + label: Expected behavior + placeholder: Tell us what you expected! + value: "Work just fine!" + validations: + required: true + + - type: textarea + id: logs + attributes: + label: Relevant log output + description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. + render: shell diff --git a/.github/ISSUE_TEMPLATE/02-feature-request.yml b/.github/ISSUE_TEMPLATE/02-feature-request.yml new file mode 100644 index 00000000..d23b5f6c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/02-feature-request.yml @@ -0,0 +1,48 @@ +--- +name: 🛠️ Feature Request +description: Suggest an idea to help us improve +title: "[Feat]: " +labels: + - "enhancement" + +body: + - type: markdown + attributes: + value: | + **Thanks :heart: for taking the time to fill out this feature request report!** + We kindly ask that you search to see if an issue [already exists](https://github.com/wg-easy/wg-easy/issues?q=is%3Aissue+sort%3Acreated-desc+) for your feature. + + We are also happy to accept contributions from our users. For more details see [here](https://github.com/wg-easy/wg-easy/blob/master/contributing.md). + + - type: textarea + attributes: + label: Description + description: | + A clear and concise description of the feature you're interested in. + validations: + required: true + + - type: textarea + attributes: + label: Suggested Solution + description: | + Describe the solution you'd like. A clear and concise description of what you want to happen. + validations: + required: true + + - type: textarea + attributes: + label: Alternatives + description: | + Describe alternatives you've considered. + A clear and concise description of any alternative solutions or features you've considered. + validations: + required: false + + - type: textarea + attributes: + label: Additional Context + description: | + Add any other context about the problem here. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 89daa669..00000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: '' -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Desktop (please complete the following information):** - - OS: [e.g. macOS 12.1] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] - -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS 8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] - -**Additional context** -Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..421000eb --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +contact_links: + - name: Get Help + url: https://github.com/wg-easy/wg-easy/discussions/new?category=q-a + about: If you can't get something to work the way you expect, open a question in the discussions. +blank_issues_enabled: false \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE.md similarity index 100% rename from .github/PULL_REQUEST_TEMPLATE/pull_request_template.md rename to .github/PULL_REQUEST_TEMPLATE.md diff --git a/How_to_generate_an_bcrypt_hash.md b/How_to_generate_an_bcrypt_hash.md index d868d23c..e77e3717 100644 --- a/How_to_generate_an_bcrypt_hash.md +++ b/How_to_generate_an_bcrypt_hash.md @@ -16,13 +16,21 @@ docker run ghcr.io/wg-easy/wg-easy wgpw YOUR_PASSWORD PASSWORD_HASH='$2b$12$coPqCsPtcFO.Ab99xylBNOW4.Iu7OOA2/ZIboHN6/oyxca3MWo7fW' // literally YOUR_PASSWORD ``` -*Important* : make sure to enclose your password in single quotes when you run `docker run` command : +**Important** : make sure to enclose your password in **single quotes** when you run `docker run` command : ```bash -$ echo $2b$12$coPqCsPtcF +$ echo $2b$12$coPqCsPtcF <-- not correct b2 -$ echo "$2b$12$coPqCsPtcF" +$ echo "$2b$12$coPqCsPtcF" <-- not correct b2 -$ echo '$2b$12$coPqCsPtcF' +$ echo '$2b$12$coPqCsPtcF' <-- correct $2b$12$coPqCsPtcF ``` + +**Important** : Please note: don't wrap the generated hash password in single quotes when you use `docker-compose.yml`. Instead, replace each `$` symbol with two `$$` symbols. For example: + +``` yaml +- PASSWORD_HASH=$$2y$$10$$hBCoykrB95WSzuV4fafBzOHWKu9sbyVa34GJr8VV5R/pIelfEMYyG +``` + +This hash is for the password 'foobar123', obtained using the command `docker run ghcr.io/wg-easy/wg-easy wgpw foobar123` and then inserted an additional `$` before each existing `$` symbal. diff --git a/README.md b/README.md index 3cee52cb..199ae82a 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ You have found the easiest way to install & manage WireGuard on any Linux host! * Automatic Light / Dark Mode * Multilanguage Support * UI_TRAFFIC_STATS (default off) +* UI_SHOW_LINKS (default off) ## Requirements @@ -99,28 +100,29 @@ Are you enjoying this project? [Buy Emile a beer!](https://github.com/sponsors/W These options can be configured by setting environment variables using `-e KEY="VALUE"` in the `docker run` command. -| Env | Default | Example | Description | -| - | - |--------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `PORT` | `51821` | `6789` | TCP port for Web UI. | -| `WEBUI_HOST` | `0.0.0.0` | `localhost` | IP address web UI binds to. | -| `PASSWORD_HASH` | - | `$2y$05$Ci...` | When set, requires a password when logging in to the Web UI. See [How to generate an bcrypt hash.md]("https://github.com/wg-easy/wg-easy/blob/master/How_to_generate_an_bcrypt_hash.md") for know how generate the hash. | -| `PASSWORD` (deprecated) | - | `foobar123` | When set, requires a password when logging in to the Web UI. *(Not used if `PASSWORD_HASH` is set)* | -| `WG_HOST` | - | `vpn.myserver.com` | The public hostname of your VPN server. | -| `WG_DEVICE` | `eth0` | `ens6f0` | Ethernet device the wireguard traffic should be forwarded through. | -| `WG_PORT` | `51820` | `12345` | The public UDP port of your VPN server. WireGuard will listen on that (othwise default) inside the Docker container. | -| `WG_CONFIG_PORT`| `51820` | `12345` | The UDP port used on [Home Assistant Plugin](https://github.com/adriy-be/homeassistant-addons-jdeath/tree/main/wgeasy) -| `WG_MTU` | `null` | `1420` | The MTU the clients will use. Server uses default WG MTU. | -| `WG_PERSISTENT_KEEPALIVE` | `0` | `25` | Value in seconds to keep the "connection" open. If this value is 0, then connections won't be kept alive. | -| `WG_DEFAULT_ADDRESS` | `10.8.0.x` | `10.6.0.x` | Clients IP address range. | -| `WG_DEFAULT_DNS` | `1.1.1.1` | `8.8.8.8, 8.8.4.4` | DNS server clients will use. If set to blank value, clients will not use any DNS. | -| `WG_ALLOWED_IPS` | `0.0.0.0/0, ::/0` | `192.168.15.0/24, 10.0.1.0/24` | Allowed IPs clients will use. | -| `WG_PRE_UP` | `...` | - | See [config.js](https://github.com/wg-easy/wg-easy/blob/master/src/config.js#L19) for the default value. | -| `WG_POST_UP` | `...` | `iptables ...` | See [config.js](https://github.com/wg-easy/wg-easy/blob/master/src/config.js#L20) for the default value. | -| `WG_PRE_DOWN` | `...` | - | See [config.js](https://github.com/wg-easy/wg-easy/blob/master/src/config.js#L27) for the default value. | -| `WG_POST_DOWN` | `...` | `iptables ...` | See [config.js](https://github.com/wg-easy/wg-easy/blob/master/src/config.js#L28) for the default value. | -| `LANG` | `en` | `de` | Web UI language (Supports: en, ua, ru, tr, no, pl, fr, de, ca, es, ko, vi, nl, is, pt, chs, cht, it, th, hi). | -| `UI_TRAFFIC_STATS` | `false` | `true` | Enable detailed RX / TX client stats in Web UI | -| `UI_CHART_TYPE` | `0` | `1` | UI_CHART_TYPE=0 # Charts disabled, UI_CHART_TYPE=1 # Line chart, UI_CHART_TYPE=2 # Area chart, UI_CHART_TYPE=3 # Bar chart | +| Env | Default | Example | Description | +| - | - | - |------------------------------------------------------------------------------------------------------------------------------------------------------| +| `PORT` | `51821` | `6789` | TCP port for Web UI. | +| `WEBUI_HOST` | `0.0.0.0` | `localhost` | IP address web UI binds to. | +| `PASSWORD_HASH` | - | `$2y$05$Ci...` | When set, requires a password when logging in to the Web UI. See [How to generate an bcrypt hash.md]("https://github.com/wg-easy/wg-easy/blob/master/How_to_generate_an_bcrypt_hash.md") for know how generate the hash. | +| `WG_HOST` | - | `vpn.myserver.com` | The public hostname of your VPN server. | +| `WG_DEVICE` | `eth0` | `ens6f0` | Ethernet device the wireguard traffic should be forwarded through. | +| `WG_PORT` | `51820` | `12345` | The public UDP port of your VPN server. WireGuard will listen on that (othwise default) inside the Docker container. | +| `WG_CONFIG_PORT`| `51820` | `12345` | The UDP port used on [Home Assistant Plugin](https://github.com/adriy-be/homeassistant-addons-jdeath/tree/main/wgeasy) +| `WG_MTU` | `null` | `1420` | The MTU the clients will use. Server uses default WG MTU. | +| `WG_PERSISTENT_KEEPALIVE` | `0` | `25` | Value in seconds to keep the "connection" open. If this value is 0, then connections won't be kept alive. | +| `WG_DEFAULT_ADDRESS` | `10.8.0.x` | `10.6.0.x` | Clients IP address range. | +| `WG_DEFAULT_DNS` | `1.1.1.1` | `8.8.8.8, 8.8.4.4` | DNS server clients will use. If set to blank value, clients will not use any DNS. | +| `WG_ALLOWED_IPS` | `0.0.0.0/0, ::/0` | `192.168.15.0/24, 10.0.1.0/24` | Allowed IPs clients will use. | +| `WG_PRE_UP` | `...` | - | See [config.js](https://github.com/wg-easy/wg-easy/blob/master/src/config.js#L19) for the default value. | +| `WG_POST_UP` | `...` | `iptables ...` | See [config.js](https://github.com/wg-easy/wg-easy/blob/master/src/config.js#L20) for the default value. | +| `WG_PRE_DOWN` | `...` | - | See [config.js](https://github.com/wg-easy/wg-easy/blob/master/src/config.js#L27) for the default value. | +| `WG_POST_DOWN` | `...` | `iptables ...` | See [config.js](https://github.com/wg-easy/wg-easy/blob/master/src/config.js#L28) for the default value. | +| `LANG` | `en` | `de` | Web UI language (Supports: en, ua, ru, tr, no, pl, fr, de, ca, es, ko, vi, nl, is, pt, chs, cht, it, th, hi). | +| `UI_TRAFFIC_STATS` | `false` | `true` | Enable detailed RX / TX client stats in Web UI | +| `UI_CHART_TYPE` | `0` | `1` | UI_CHART_TYPE=0 # Charts disabled, UI_CHART_TYPE=1 # Line chart, UI_CHART_TYPE=2 # Area chart, UI_CHART_TYPE=3 # Bar chart | +| `UI_SHOW_LINKS` | `false` | `true` | Enable display of a short download link in Web UI | +| `MAX_AGE` | `0` | `1440` | The maximum age of Web UI sessions in minutes. `0` means that the session will exist until the browser is closed. | | `UI_ENABLE_SORT_CLIENTS` | `false` | `true` | Enable UI sort clients by name | > If you change `WG_PORT`, make sure to also change the exposed port. diff --git a/docker-compose.yml b/docker-compose.yml index e63bccc3..379c0d54 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -27,6 +27,7 @@ services: # - WG_POST_DOWN=echo "Post Down" > /etc/wireguard/post-down.txt # - UI_TRAFFIC_STATS=true # - UI_CHART_TYPE=0 # (0 Charts disabled, 1 # Line chart, 2 # Area chart, 3 # Bar chart) + # - UI_SHOW_LINKS=true # - UI_ENABLE_SORT_CLIENTS=true image: ghcr.io/wg-easy/wg-easy @@ -40,7 +41,7 @@ services: cap_add: - NET_ADMIN - SYS_MODULE - # - NET_RAW # ⚠️ Uncomment if using Podman + # - NET_RAW # ⚠️ Uncomment if using Podman sysctls: - net.ipv4.ip_forward=1 - net.ipv4.conf.all.src_valid_mark=1 diff --git a/src/config.js b/src/config.js index 1517cf51..d7a7831d 100644 --- a/src/config.js +++ b/src/config.js @@ -6,6 +6,7 @@ module.exports.RELEASE = version; module.exports.PORT = process.env.PORT || '51821'; module.exports.WEBUI_HOST = process.env.WEBUI_HOST || '0.0.0.0'; module.exports.PASSWORD_HASH = process.env.PASSWORD_HASH; +module.exports.MAX_AGE = parseInt(process.env.MAX_AGE, 10) * 1000 * 60 || 0; module.exports.WG_PATH = process.env.WG_PATH || '/etc/wireguard/'; module.exports.WG_DEVICE = process.env.WG_DEVICE || 'eth0'; module.exports.WG_HOST = process.env.WG_HOST; @@ -37,4 +38,5 @@ iptables -D FORWARD -o wg0 -j ACCEPT; module.exports.LANG = process.env.LANG || 'en'; module.exports.UI_TRAFFIC_STATS = process.env.UI_TRAFFIC_STATS || 'false'; module.exports.UI_CHART_TYPE = process.env.UI_CHART_TYPE || 0; +module.exports.UI_SHOW_LINKS = process.env.UI_SHOW_LINKS || 'false'; module.exports.UI_ENABLE_SORT_CLIENTS = process.env.UI_ENABLE_SORT_CLIENTS || 'false'; diff --git a/src/lib/Server.js b/src/lib/Server.js index 323e9b0b..df419be0 100644 --- a/src/lib/Server.js +++ b/src/lib/Server.js @@ -29,9 +29,11 @@ const { WEBUI_HOST, RELEASE, PASSWORD_HASH, + MAX_AGE, LANG, UI_TRAFFIC_STATS, UI_CHART_TYPE, + UI_SHOW_LINKS, UI_ENABLE_SORT_CLIENTS, } = require('../config'); @@ -83,6 +85,11 @@ module.exports = class Server { return `"${LANG}"`; })) + .get('/api/remember-me', defineEventHandler((event) => { + setHeader(event, 'Content-Type', 'application/json'); + return MAX_AGE > 0; + })) + .get('/api/ui-traffic-stats', defineEventHandler((event) => { setHeader(event, 'Content-Type', 'application/json'); return `"${UI_TRAFFIC_STATS}"`; @@ -93,9 +100,14 @@ module.exports = class Server { return `"${UI_CHART_TYPE}"`; })) + .get('/api/ui-show-links', defineEventHandler((event) => { + setHeader(event, 'Content-Type', 'application/json'); + return `${UI_SHOW_LINKS}`; + .get('/api/ui-sort-clients', defineEventHandler((event) => { setHeader(event, 'Content-Type', 'application/json'); return UI_ENABLE_SORT_CLIENTS; + })) // Authentication @@ -109,8 +121,19 @@ module.exports = class Server { authenticated, }; })) + .get('/:clientHash', defineEventHandler(async (event) => { + const clientHash = getRouterParam(event, 'clientHash'); + const clients = await WireGuard.getClients(); + const client = clients.find((client) => client.hash === clientHash); + if (!client) return; + const clientId = client.id; + const config = await WireGuard.getClientConfiguration({ clientId }); + setHeader(event, 'Content-Disposition', `attachment; filename="${clientHash}.conf"`); + setHeader(event, 'Content-Type', 'text/plain'); + return config; + })) .post('/api/session', defineEventHandler(async (event) => { - const { password } = await readBody(event); + const { password, remember } = await readBody(event); if (!requiresPassword) { // if no password is required, the API should never be called. @@ -128,6 +151,9 @@ module.exports = class Server { }); } + if (MAX_AGE && remember) { + event.node.req.session.cookie.maxAge = MAX_AGE; + } event.node.req.session.authenticated = true; event.node.req.session.save(); diff --git a/src/lib/WireGuard.js b/src/lib/WireGuard.js index adf6ca95..95b8c9d1 100644 --- a/src/lib/WireGuard.js +++ b/src/lib/WireGuard.js @@ -5,6 +5,7 @@ const path = require('path'); const debug = require('debug')('WireGuard'); const crypto = require('node:crypto'); const QRCode = require('qrcode'); +const CRC32 = require('crc-32'); const Util = require('./Util'); const ServerError = require('./ServerError'); @@ -147,6 +148,7 @@ ${client.preSharedKey ? `PresharedKey = ${client.preSharedKey}\n` : '' createdAt: new Date(client.createdAt), updatedAt: new Date(client.updatedAt), allowedIPs: client.allowedIPs, + hash: Math.abs(CRC32.str(clientId)).toString(16), downloadableConfig: 'privateKey' in client, persistentKeepalive: null, latestHandshakeAt: null, diff --git a/src/package-lock.json b/src/package-lock.json index f4c752ee..b1ff1375 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -10,15 +10,16 @@ "license": "CC BY-NC-SA 4.0", "dependencies": { "bcryptjs": "^2.4.3", + "crc-32": "^1.2.2", "debug": "^4.3.6", "express-session": "^1.18.0", "h3": "^1.12.0", - "qrcode": "^1.5.3" + "qrcode": "^1.5.4" }, "devDependencies": { "eslint-config-athom": "^3.1.3", "nodemon": "^3.1.4", - "tailwindcss": "^3.4.7" + "tailwindcss": "^3.4.10" }, "engines": { "node": ">=18" @@ -1209,6 +1210,18 @@ "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", "license": "MIT" }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -1456,12 +1469,6 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "license": "MIT" }, - "node_modules/encode-utf8": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz", - "integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==", - "license": "MIT" - }, "node_modules/enquirer": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", @@ -2312,9 +2319,9 @@ } }, "node_modules/foreground-child": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", - "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dev": true, "license": "ISC", "dependencies": { @@ -2664,9 +2671,9 @@ } }, "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", "engines": { @@ -3769,9 +3776,9 @@ } }, "node_modules/postcss": { - "version": "8.4.40", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.40.tgz", - "integrity": "sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==", + "version": "8.4.41", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", + "integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==", "dev": true, "funding": [ { @@ -3911,9 +3918,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz", - "integrity": "sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "dev": true, "license": "MIT", "dependencies": { @@ -3972,13 +3979,12 @@ } }, "node_modules/qrcode": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.3.tgz", - "integrity": "sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz", + "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==", "license": "MIT", "dependencies": { "dijkstrajs": "^1.0.1", - "encode-utf8": "^1.0.3", "pngjs": "^5.0.0", "yargs": "^15.3.1" }, @@ -4694,9 +4700,9 @@ "peer": true }, "node_modules/tailwindcss": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.7.tgz", - "integrity": "sha512-rxWZbe87YJb4OcSopb7up2Ba4U82BoiSGUdoDr3Ydrg9ckxFS/YWsvhN323GMcddgU65QRy7JndC7ahhInhvlQ==", + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.10.tgz", + "integrity": "sha512-KWZkVPm7yJRhdu4SRSl9d4AK2wM3a50UsvgHZO7xY77NQr2V+fIrEuoDGQcbvswWvFGbS2f6e+jC/6WJm1Dl0w==", "dev": true, "license": "MIT", "dependencies": { diff --git a/src/package.json b/src/package.json index 6750366e..c90bbc9f 100644 --- a/src/package.json +++ b/src/package.json @@ -19,12 +19,13 @@ "debug": "^4.3.6", "express-session": "^1.18.0", "h3": "^1.12.0", - "qrcode": "^1.5.3" + "qrcode": "^1.5.4", + "crc-32": "^1.2.2" }, "devDependencies": { "eslint-config-athom": "^3.1.3", "nodemon": "^3.1.4", - "tailwindcss": "^3.4.7" + "tailwindcss": "^3.4.10" }, "nodemonConfig": { "ignore": [ diff --git a/src/www/css/app.css b/src/www/css/app.css index 08271631..ae3fc3c3 100644 --- a/src/www/css/app.css +++ b/src/www/css/app.css @@ -1,5 +1,5 @@ /* -! tailwindcss v3.4.7 | MIT License | https://tailwindcss.com +! tailwindcss v3.4.10 | MIT License | https://tailwindcss.com */ /* diff --git a/src/www/index.html b/src/www/index.html index f8f5ded0..3dd7030d 100644 --- a/src/www/index.html +++ b/src/www/index.html @@ -10,6 +10,7 @@ +