Browse Source

currently working

pull/2294/head
SachinAsus 2 years ago
parent
commit
ff0ab643b0
  1. 10
      Dockerfile
  2. 5
      docker-compose.yml
  3. 88
      src/lib/Server.js
  4. 123
      src/lib/WireGuard.js
  5. 249
      src/package-lock.json
  6. 13
      src/package.json
  7. 15
      src/www/css/app.css
  8. 18
      src/www/index.html
  9. 8
      src/www/js/api.js
  10. 19
      src/www/js/app.js
  11. 46
      src/www/js/i18n.js
  12. 8
      src/www/js/vendor/apexcharts.min.js

10
Dockerfile

@ -26,10 +26,6 @@ COPY --from=build_node_modules /app /app
# than what runs inside of docker. # than what runs inside of docker.
COPY --from=build_node_modules /node_modules /node_modules COPY --from=build_node_modules /node_modules /node_modules
# Copy the needed wg-password scripts
COPY --from=build_node_modules /app/wgpw.sh /bin/wgpw
RUN chmod +x /bin/wgpw
# Install Linux packages # Install Linux packages
RUN apk add --no-cache \ RUN apk add --no-cache \
dpkg \ dpkg \
@ -41,9 +37,13 @@ RUN apk add --no-cache \
# Use iptables-legacy # Use iptables-legacy
RUN update-alternatives --install /sbin/iptables iptables /sbin/iptables-legacy 10 --slave /sbin/iptables-restore iptables-restore /sbin/iptables-legacy-restore --slave /sbin/iptables-save iptables-save /sbin/iptables-legacy-save RUN update-alternatives --install /sbin/iptables iptables /sbin/iptables-legacy 10 --slave /sbin/iptables-restore iptables-restore /sbin/iptables-legacy-restore --slave /sbin/iptables-save iptables-save /sbin/iptables-legacy-save
# Expose Ports (If needed on buildtime)
#EXPOSE 51820/udp
#EXPOSE 51821/tcp
# Set Environment # Set Environment
ENV DEBUG=Server,WireGuard ENV DEBUG=Server,WireGuard
# Run Web UI # Run Web UI
WORKDIR /app WORKDIR /app
CMD ["/usr/bin/dumb-init", "node", "server.js"] CMD ["/usr/bin/dumb-init", "node", "server.js"]

5
docker-compose.yml

@ -12,11 +12,9 @@ services:
- WG_HOST=raspberrypi.local - WG_HOST=raspberrypi.local
# Optional: # Optional:
# - PASSWORD=foobar123 (deprecated, see readme) # - PASSWORD=foobar123
# - PASSWORD_HASH=$$2y$$10$$hBCoykrB95WSzuV4fafBzOHWKu9sbyVa34GJr8VV5R/pIelfEMYyG (needs double $$, hash of 'foobar123'; see "How_to_generate_an_bcrypt_hash.md" for generate the hash)
# - PORT=51821 # - PORT=51821
# - WG_PORT=51820 # - WG_PORT=51820
# - WG_CONFIG_PORT=92820
# - WG_DEFAULT_ADDRESS=10.8.0.x # - WG_DEFAULT_ADDRESS=10.8.0.x
# - WG_DEFAULT_DNS=1.1.1.1 # - WG_DEFAULT_DNS=1.1.1.1
# - WG_MTU=1420 # - WG_MTU=1420
@ -40,7 +38,6 @@ services:
cap_add: cap_add:
- NET_ADMIN - NET_ADMIN
- SYS_MODULE - SYS_MODULE
# - NET_RAW # ⚠️ Uncomment if using Podman
sysctls: sysctls:
- net.ipv4.ip_forward=1 - net.ipv4.ip_forward=1
- net.ipv4.conf.all.src_valid_mark=1 - net.ipv4.conf.all.src_valid_mark=1

88
src/lib/Server.js

@ -4,7 +4,7 @@ const bcrypt = require('bcryptjs');
const crypto = require('node:crypto'); const crypto = require('node:crypto');
const { createServer } = require('node:http'); const { createServer } = require('node:http');
const { stat, readFile } = require('node:fs/promises'); const { stat, readFile } = require('node:fs/promises');
const { resolve, sep } = require('node:path'); const { join } = require('node:path');
const expressSession = require('express-session'); const expressSession = require('express-session');
const debug = require('debug')('Server'); const debug = require('debug')('Server');
@ -28,34 +28,12 @@ const {
PORT, PORT,
WEBUI_HOST, WEBUI_HOST,
RELEASE, RELEASE,
PASSWORD_HASH, PASSWORD,
LANG, LANG,
UI_TRAFFIC_STATS, UI_TRAFFIC_STATS,
UI_CHART_TYPE, UI_CHART_TYPE,
} = require('../config'); } = require('../config');
const requiresPassword = !!PASSWORD_HASH;
/**
* Checks if `password` matches the PASSWORD_HASH.
*
* If environment variable is not set, the password is always invalid.
*
* @param {string} password String to test
* @returns {boolean} true if matching environment, otherwise false
*/
const isPasswordValid = (password) => {
if (typeof password !== 'string') {
return false;
}
if (PASSWORD_HASH) {
return bcrypt.compareSync(password, PASSWORD_HASH);
}
return false;
};
module.exports = class Server { module.exports = class Server {
constructor() { constructor() {
@ -94,6 +72,7 @@ module.exports = class Server {
// Authentication // Authentication
.get('/api/session', defineEventHandler((event) => { .get('/api/session', defineEventHandler((event) => {
const requiresPassword = !!process.env.PASSWORD;
const authenticated = requiresPassword const authenticated = requiresPassword
? !!(event.node.req.session && event.node.req.session.authenticated) ? !!(event.node.req.session && event.node.req.session.authenticated)
: true; : true;
@ -106,16 +85,14 @@ module.exports = class Server {
.post('/api/session', defineEventHandler(async (event) => { .post('/api/session', defineEventHandler(async (event) => {
const { password } = await readBody(event); const { password } = await readBody(event);
if (!requiresPassword) { if (typeof password !== 'string') {
// if no password is required, the API should never be called.
// Do not automatically authenticate the user.
throw createError({ throw createError({
status: 401, status: 401,
message: 'Invalid state', message: 'Missing: Password',
}); });
} }
if (!isPasswordValid(password)) { if (password !== PASSWORD) {
throw createError({ throw createError({
status: 401, status: 401,
message: 'Incorrect Password', message: 'Incorrect Password',
@ -127,13 +104,13 @@ module.exports = class Server {
debug(`New Session: ${event.node.req.session.id}`); debug(`New Session: ${event.node.req.session.id}`);
return { success: true }; return { succcess: true };
})); }));
// WireGuard // WireGuard
app.use( app.use(
fromNodeMiddleware((req, res, next) => { fromNodeMiddleware((req, res, next) => {
if (!requiresPassword || !req.url.startsWith('/api/')) { if (!PASSWORD || !req.url.startsWith('/api/')) {
return next(); return next();
} }
@ -142,7 +119,7 @@ module.exports = class Server {
} }
if (req.url.startsWith('/api/') && req.headers['authorization']) { if (req.url.startsWith('/api/') && req.headers['authorization']) {
if (isPasswordValid(req.headers['authorization'])) { if (bcrypt.compareSync(req.headers['authorization'], bcrypt.hashSync(PASSWORD, 10))) {
return next(); return next();
} }
return res.status(401).json({ return res.status(401).json({
@ -235,58 +212,15 @@ module.exports = class Server {
return { success: true }; return { success: true };
})); }));
const safePathJoin = (base, target) => {
// Manage web root (edge case)
if (target === '/') {
return `${base}${sep}`;
}
// Prepend './' to prevent absolute paths
const targetPath = `.${sep}${target}`;
// Resolve the absolute path
const resolvedPath = resolve(base, targetPath);
// Check if resolvedPath is a subpath of base
if (resolvedPath.startsWith(`${base}${sep}`)) {
return resolvedPath;
}
throw createError({
status: 400,
message: 'Bad Request',
});
};
// backup_restore
const router3 = createRouter();
app.use(router3);
router3
.get('/api/wireguard/backup', defineEventHandler(async (event) => {
const config = await WireGuard.backupConfiguration();
setHeader(event, 'Content-Disposition', 'attachment; filename="wg0.json"');
setHeader(event, 'Content-Type', 'text/json');
return config;
}))
.put('/api/wireguard/restore', defineEventHandler(async (event) => {
const { file } = await readBody(event);
await WireGuard.restoreConfiguration(file);
return { success: true };
}));
// Static assets // Static assets
const publicDir = '/home/ubuntu/wg-easy/src/www'; const publicDir = '/home/ubuntu/wg-easy/src/www';
app.use( app.use(
defineEventHandler((event) => { defineEventHandler((event) => {
return serveStatic(event, { return serveStatic(event, {
getContents: (id) => { getContents: (id) => readFile(join(publicDir, id)),
return readFile(safePathJoin(publicDir, id));
},
getMeta: async (id) => { getMeta: async (id) => {
const filePath = safePathJoin(publicDir, id); const stats = await stat(join(publicDir, id)).catch(() => {});
const stats = await stat(filePath).catch(() => {});
if (!stats || !stats.isFile()) { if (!stats || !stats.isFile()) {
return; return;
} }

123
src/lib/WireGuard.js

@ -1,9 +1,10 @@
'use strict'; 'use strict';
const fs = require('node:fs/promises'); const fs = require('fs').promises;
const path = require('path'); const path = require('path');
const debug = require('debug')('WireGuard'); const debug = require('debug')('WireGuard');
const crypto = require('node:crypto'); const uuid = require('uuid');
const QRCode = require('qrcode'); const QRCode = require('qrcode');
const Util = require('./Util'); const Util = require('./Util');
@ -13,7 +14,6 @@ const {
WG_PATH, WG_PATH,
WG_HOST, WG_HOST,
WG_PORT, WG_PORT,
WG_CONFIG_PORT,
WG_MTU, WG_MTU,
WG_DEFAULT_DNS, WG_DEFAULT_DNS,
WG_DEFAULT_ADDRESS, WG_DEFAULT_ADDRESS,
@ -27,60 +27,54 @@ const {
module.exports = class WireGuard { module.exports = class WireGuard {
async __buildConfig() {
this.__configPromise = Promise.resolve().then(async () => {
if (!WG_HOST) {
throw new Error('WG_HOST Environment Variable Not Set!');
}
debug('Loading configuration...');
let config;
try {
config = await fs.readFile(path.join(WG_PATH, 'wg0.json'), 'utf8');
config = JSON.parse(config);
debug('Configuration loaded.');
} catch (err) {
const privateKey = await Util.exec('wg genkey');
const publicKey = await Util.exec(`echo ${privateKey} | wg pubkey`, {
log: 'echo ***hidden*** | wg pubkey',
});
const address = WG_DEFAULT_ADDRESS.replace('x', '1');
config = {
server: {
privateKey,
publicKey,
address,
},
clients: {},
};
debug('Configuration generated.');
}
return config;
});
return this.__configPromise;
}
async getConfig() { async getConfig() {
if (!this.__configPromise) { if (!this.__configPromise) {
const config = await this.__buildConfig(); this.__configPromise = Promise.resolve().then(async () => {
if (!WG_HOST) {
throw new Error('WG_HOST Environment Variable Not Set!');
}
await this.__saveConfig(config); debug('Loading configuration...');
await Util.exec('wg-quick down wg0').catch(() => {}); let config;
await Util.exec('wg-quick up wg0').catch((err) => { try {
if (err && err.message && err.message.includes('Cannot find device "wg0"')) { config = await fs.readFile(path.join(WG_PATH, 'wg0.json'), 'utf8');
throw new Error('WireGuard exited with the error: Cannot find device "wg0"\nThis usually means that your host\'s kernel does not support WireGuard!'); config = JSON.parse(config);
debug('Configuration loaded.');
} catch (err) {
const privateKey = await Util.exec('wg genkey');
const publicKey = await Util.exec(`echo ${privateKey} | wg pubkey`, {
log: 'echo ***hidden*** | wg pubkey',
});
const address = WG_DEFAULT_ADDRESS.replace('x', '1');
config = {
server: {
privateKey,
publicKey,
address,
},
clients: {},
};
debug('Configuration generated.');
} }
throw err; await this.__saveConfig(config);
await Util.exec('wg-quick down wg0').catch(() => { });
await Util.exec('wg-quick up wg0').catch((err) => {
if (err && err.message && err.message.includes('Cannot find device "wg0"')) {
throw new Error('WireGuard exited with the error: Cannot find device "wg0"\nThis usually means that your host\'s kernel does not support WireGuard!');
}
throw err;
});
// await Util.exec(`iptables -t nat -A POSTROUTING -s ${WG_DEFAULT_ADDRESS.replace('x', '0')}/24 -o ' + WG_DEVICE + ' -j MASQUERADE`);
// await Util.exec('iptables -A INPUT -p udp -m udp --dport 51820 -j ACCEPT');
// await Util.exec('iptables -A FORWARD -i wg0 -j ACCEPT');
// await Util.exec('iptables -A FORWARD -o wg0 -j ACCEPT');
await this.__syncConfig();
return config;
}); });
// await Util.exec(`iptables -t nat -A POSTROUTING -s ${WG_DEFAULT_ADDRESS.replace('x', '0')}/24 -o ' + WG_DEVICE + ' -j MASQUERADE`);
// await Util.exec('iptables -A INPUT -p udp -m udp --dport 51820 -j ACCEPT');
// await Util.exec('iptables -A FORWARD -i wg0 -j ACCEPT');
// await Util.exec('iptables -A FORWARD -o wg0 -j ACCEPT');
await this.__syncConfig();
} }
return this.__configPromise; return this.__configPromise;
@ -219,7 +213,7 @@ PublicKey = ${config.server.publicKey}
${client.preSharedKey ? `PresharedKey = ${client.preSharedKey}\n` : '' ${client.preSharedKey ? `PresharedKey = ${client.preSharedKey}\n` : ''
}AllowedIPs = ${WG_ALLOWED_IPS} }AllowedIPs = ${WG_ALLOWED_IPS}
PersistentKeepalive = ${WG_PERSISTENT_KEEPALIVE} PersistentKeepalive = ${WG_PERSISTENT_KEEPALIVE}
Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`; Endpoint = ${WG_HOST}:${WG_PORT}`;
} }
async getClientQRCodeSVG({ clientId }) { async getClientQRCodeSVG({ clientId }) {
@ -259,7 +253,7 @@ Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`;
} }
// Create Client // Create Client
const id = crypto.randomUUID(); const id = uuid.v4();
const client = { const client = {
id, id,
name, name,
@ -330,30 +324,9 @@ Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`;
await this.saveConfig(); await this.saveConfig();
} }
async __reloadConfig() {
await this.__buildConfig();
await this.__syncConfig();
}
async restoreConfiguration(config) {
debug('Starting configuration restore process.');
const _config = JSON.parse(config);
await this.__saveConfig(_config);
await this.__reloadConfig();
debug('Configuration restore process completed.');
}
async backupConfiguration() {
debug('Starting configuration backup.');
const config = await this.getConfig();
const backup = JSON.stringify(config, null, 2);
debug('Configuration backup completed.');
return backup;
}
// Shutdown wireguard // Shutdown wireguard
async Shutdown() { async Shutdown() {
await Util.exec('wg-quick down wg0').catch(() => {}); await Util.exec('wg-quick down wg0').catch(() => { });
} }
}; };

249
src/package-lock.json

@ -7,18 +7,19 @@
"": { "": {
"name": "wg-easy", "name": "wg-easy",
"version": "1.0.1", "version": "1.0.1",
"license": "CC BY-NC-SA 4.0", "license": "GPL",
"dependencies": { "dependencies": {
"bcryptjs": "^2.4.3", "bcryptjs": "^2.4.3",
"debug": "^4.3.5", "debug": "^4.3.4",
"express-session": "^1.18.0", "express-session": "^1.18.0",
"h3": "^1.12.0", "h3": "^1.11.1",
"qrcode": "^1.5.3" "qrcode": "^1.5.3",
"uuid": "^9.0.1"
}, },
"devDependencies": { "devDependencies": {
"eslint-config-athom": "^3.1.3", "eslint-config-athom": "^3.1.3",
"nodemon": "^3.1.4", "nodemon": "^3.1.0",
"tailwindcss": "^3.4.4" "tailwindcss": "^3.4.3"
}, },
"engines": { "engines": {
"node": ">=18" "node": ">=18"
@ -47,9 +48,9 @@
} }
}, },
"node_modules/@babel/helper-validator-identifier": { "node_modules/@babel/helper-validator-identifier": {
"version": "7.24.7", "version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz",
"integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==",
"dev": true, "dev": true,
"peer": true, "peer": true,
"engines": { "engines": {
@ -57,13 +58,13 @@
} }
}, },
"node_modules/@babel/highlight": { "node_modules/@babel/highlight": {
"version": "7.24.7", "version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz",
"integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==",
"dev": true, "dev": true,
"peer": true, "peer": true,
"dependencies": { "dependencies": {
"@babel/helper-validator-identifier": "^7.24.7", "@babel/helper-validator-identifier": "^7.24.5",
"chalk": "^2.4.2", "chalk": "^2.4.2",
"js-tokens": "^4.0.0", "js-tokens": "^4.0.0",
"picocolors": "^1.0.0" "picocolors": "^1.0.0"
@ -166,9 +167,9 @@
} }
}, },
"node_modules/@eslint-community/regexpp": { "node_modules/@eslint-community/regexpp": {
"version": "4.11.0", "version": "4.10.0",
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz",
"integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": "^12.0.0 || ^14.0.0 || >=16.0.0" "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
@ -209,7 +210,6 @@
"version": "0.5.0", "version": "0.5.0",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz",
"integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==",
"deprecated": "Use @eslint/config-array instead",
"dev": true, "dev": true,
"peer": true, "peer": true,
"dependencies": { "dependencies": {
@ -225,7 +225,6 @@
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
"deprecated": "Use @eslint/object-schema instead",
"dev": true, "dev": true,
"peer": true "peer": true
}, },
@ -358,9 +357,9 @@
} }
}, },
"node_modules/@jridgewell/sourcemap-codec": { "node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.0", "version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
"dev": true "dev": true
}, },
"node_modules/@jridgewell/trace-mapping": { "node_modules/@jridgewell/trace-mapping": {
@ -939,12 +938,12 @@
} }
}, },
"node_modules/braces": { "node_modules/braces": {
"version": "3.0.3", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"fill-range": "^7.1.1" "fill-range": "^7.0.1"
}, },
"engines": { "engines": {
"node": ">=8" "node": ">=8"
@ -1213,9 +1212,9 @@
} }
}, },
"node_modules/debug": { "node_modules/debug": {
"version": "4.3.5", "version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dependencies": { "dependencies": {
"ms": "2.1.2" "ms": "2.1.2"
}, },
@ -1917,9 +1916,9 @@
} }
}, },
"node_modules/esquery": { "node_modules/esquery": {
"version": "1.6.0", "version": "1.5.0",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
"integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
"dev": true, "dev": true,
"peer": true, "peer": true,
"dependencies": { "dependencies": {
@ -2061,13 +2060,6 @@
"dev": true, "dev": true,
"peer": true "peer": true
}, },
"node_modules/fast-uri": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz",
"integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==",
"dev": true,
"peer": true
},
"node_modules/fastq": { "node_modules/fastq": {
"version": "1.17.1", "version": "1.17.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
@ -2091,9 +2083,9 @@
} }
}, },
"node_modules/fill-range": { "node_modules/fill-range": {
"version": "7.1.1", "version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"to-regex-range": "^5.0.1" "to-regex-range": "^5.0.1"
@ -2146,9 +2138,9 @@
} }
}, },
"node_modules/foreground-child": { "node_modules/foreground-child": {
"version": "3.2.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
"integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"cross-spawn": "^7.0.0", "cross-spawn": "^7.0.0",
@ -2273,7 +2265,6 @@
"version": "7.2.3", "version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"deprecated": "Glob versions prior to v9 are no longer supported",
"dev": true, "dev": true,
"peer": true, "peer": true,
"dependencies": { "dependencies": {
@ -2374,18 +2365,18 @@
"dev": true "dev": true
}, },
"node_modules/h3": { "node_modules/h3": {
"version": "1.12.0", "version": "1.11.1",
"resolved": "https://registry.npmjs.org/h3/-/h3-1.12.0.tgz", "resolved": "https://registry.npmjs.org/h3/-/h3-1.11.1.tgz",
"integrity": "sha512-Zi/CcNeWBXDrFNlV0hUBJQR9F7a96RjMeAZweW/ZWkR9fuXrMcvKnSA63f/zZ9l0GgQOZDVHGvXivNN9PWOwhA==", "integrity": "sha512-AbaH6IDnZN6nmbnJOH72y3c5Wwh9P97soSVdGSBbcDACRdkC0FEWf25pzx4f/NuOCK6quHmW18yF2Wx+G4Zi1A==",
"dependencies": { "dependencies": {
"cookie-es": "^1.1.0", "cookie-es": "^1.0.0",
"crossws": "^0.2.4", "crossws": "^0.2.2",
"defu": "^6.1.4", "defu": "^6.1.4",
"destr": "^2.0.3", "destr": "^2.0.3",
"iron-webcrypto": "^1.1.1", "iron-webcrypto": "^1.0.0",
"ohash": "^1.1.3", "ohash": "^1.1.3",
"radix3": "^1.1.2", "radix3": "^1.1.0",
"ufo": "^1.5.3", "ufo": "^1.4.0",
"uncrypto": "^0.1.3", "uncrypto": "^0.1.3",
"unenv": "^1.9.0" "unenv": "^1.9.0"
} }
@ -2518,7 +2509,6 @@
"version": "1.0.6", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
"dev": true, "dev": true,
"peer": true, "peer": true,
"dependencies": { "dependencies": {
@ -2624,15 +2614,12 @@
} }
}, },
"node_modules/is-core-module": { "node_modules/is-core-module": {
"version": "2.14.0", "version": "2.13.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
"integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"hasown": "^2.0.2" "hasown": "^2.0.0"
},
"engines": {
"node": ">= 0.4"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
@ -2834,13 +2821,16 @@
"dev": true "dev": true
}, },
"node_modules/jackspeak": { "node_modules/jackspeak": {
"version": "3.4.3", "version": "2.3.6",
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz",
"integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@isaacs/cliui": "^8.0.2" "@isaacs/cliui": "^8.0.2"
}, },
"engines": {
"node": ">=14"
},
"funding": { "funding": {
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
}, },
@ -2849,9 +2839,9 @@
} }
}, },
"node_modules/jiti": { "node_modules/jiti": {
"version": "1.21.6", "version": "1.21.0",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz",
"integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==",
"dev": true, "dev": true,
"bin": { "bin": {
"jiti": "bin/jiti.js" "jiti": "bin/jiti.js"
@ -2976,10 +2966,13 @@
"peer": true "peer": true
}, },
"node_modules/lru-cache": { "node_modules/lru-cache": {
"version": "10.4.3", "version": "10.2.2",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz",
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==",
"dev": true "dev": true,
"engines": {
"node": "14 || >=16.14"
}
}, },
"node_modules/merge2": { "node_modules/merge2": {
"version": "1.4.1", "version": "1.4.1",
@ -2991,12 +2984,12 @@
} }
}, },
"node_modules/micromatch": { "node_modules/micromatch": {
"version": "4.0.7", "version": "4.0.5",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
"integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"braces": "^3.0.3", "braces": "^3.0.2",
"picomatch": "^2.3.1" "picomatch": "^2.3.1"
}, },
"engines": { "engines": {
@ -3036,9 +3029,9 @@
} }
}, },
"node_modules/minipass": { "node_modules/minipass": {
"version": "7.1.2", "version": "7.1.1",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.1.tgz",
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "integrity": "sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=16 || 14 >=14.17" "node": ">=16 || 14 >=14.17"
@ -3090,9 +3083,9 @@
"integrity": "sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==" "integrity": "sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ=="
}, },
"node_modules/nodemon": { "node_modules/nodemon": {
"version": "3.1.4", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.4.tgz", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.0.tgz",
"integrity": "sha512-wjPBbFhtpJwmIeY2yP7QF+UKzPfltVGtfce1g/bB15/8vCGZj8uxD62b/b9M9/WVgme0NZudpownKN+c0plXlQ==", "integrity": "sha512-xqlktYlDMCepBJd43ZQhjWwMw2obW/JRvkrLxq5RCNcuDDX1DbcPT+qT1IlIIdf+DhnWs90JpTMe+Y5KxOchvA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"chokidar": "^3.5.2", "chokidar": "^3.5.2",
@ -3166,13 +3159,10 @@
} }
}, },
"node_modules/object-inspect": { "node_modules/object-inspect": {
"version": "1.13.2", "version": "1.13.1",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
"integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
"dev": true, "dev": true,
"engines": {
"node": ">= 0.4"
},
"funding": { "funding": {
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
@ -3341,12 +3331,6 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/package-json-from-dist": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz",
"integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==",
"dev": true
},
"node_modules/parent-module": { "node_modules/parent-module": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@ -3485,9 +3469,9 @@
} }
}, },
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.4.39", "version": "8.4.38",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
"integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==", "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@ -3505,7 +3489,7 @@
], ],
"dependencies": { "dependencies": {
"nanoid": "^3.3.7", "nanoid": "^3.3.7",
"picocolors": "^1.0.1", "picocolors": "^1.0.0",
"source-map-js": "^1.2.0" "source-map-js": "^1.2.0"
}, },
"engines": { "engines": {
@ -3584,9 +3568,9 @@
} }
}, },
"node_modules/postcss-load-config/node_modules/lilconfig": { "node_modules/postcss-load-config/node_modules/lilconfig": {
"version": "3.1.2", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz",
"integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=14" "node": ">=14"
@ -3615,9 +3599,9 @@
} }
}, },
"node_modules/postcss-selector-parser": { "node_modules/postcss-selector-parser": {
"version": "6.1.1", "version": "6.0.16",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz",
"integrity": "sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==", "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"cssesc": "^3.0.0", "cssesc": "^3.0.0",
@ -3840,7 +3824,6 @@
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
"deprecated": "Rimraf versions prior to v4 are no longer supported",
"dev": true, "dev": true,
"peer": true, "peer": true,
"dependencies": { "dependencies": {
@ -4240,29 +4223,31 @@
} }
}, },
"node_modules/sucrase/node_modules/glob": { "node_modules/sucrase/node_modules/glob": {
"version": "10.4.5", "version": "10.3.15",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.15.tgz",
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "integrity": "sha512-0c6RlJt1TICLyvJYIApxb8GsXoai0KUP7AxKKAtsYXdgJR1mGEUa7DgwShbdk1nly0PYoZj01xd4hzbq3fsjpw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"foreground-child": "^3.1.0", "foreground-child": "^3.1.0",
"jackspeak": "^3.1.2", "jackspeak": "^2.3.6",
"minimatch": "^9.0.4", "minimatch": "^9.0.1",
"minipass": "^7.1.2", "minipass": "^7.0.4",
"package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.0"
"path-scurry": "^1.11.1"
}, },
"bin": { "bin": {
"glob": "dist/esm/bin.mjs" "glob": "dist/esm/bin.mjs"
}, },
"engines": {
"node": ">=16 || 14 >=14.18"
},
"funding": { "funding": {
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/sucrase/node_modules/minimatch": { "node_modules/sucrase/node_modules/minimatch": {
"version": "9.0.5", "version": "9.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"brace-expansion": "^2.0.1" "brace-expansion": "^2.0.1"
@ -4317,16 +4302,16 @@
} }
}, },
"node_modules/table/node_modules/ajv": { "node_modules/table/node_modules/ajv": {
"version": "8.17.1", "version": "8.13.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==",
"dev": true, "dev": true,
"peer": true, "peer": true,
"dependencies": { "dependencies": {
"fast-deep-equal": "^3.1.3", "fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
"json-schema-traverse": "^1.0.0", "json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2" "require-from-string": "^2.0.2",
"uri-js": "^4.4.1"
}, },
"funding": { "funding": {
"type": "github", "type": "github",
@ -4341,9 +4326,9 @@
"peer": true "peer": true
}, },
"node_modules/tailwindcss": { "node_modules/tailwindcss": {
"version": "3.4.4", "version": "3.4.3",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.4.tgz", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz",
"integrity": "sha512-ZoyXOdJjISB7/BcLTR6SEsLgKtDStYyYZVLsUtWChO4Ps20CBad7lfJKVDiejocV4ME1hLmyY0WJE3hSDcmQ2A==", "integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@alloc/quick-lru": "^5.2.0", "@alloc/quick-lru": "^5.2.0",
@ -4638,6 +4623,18 @@
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"dev": true "dev": true
}, },
"node_modules/uuid": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/v8-compile-cache": { "node_modules/v8-compile-cache": {
"version": "2.4.0", "version": "2.4.0",
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz",
@ -4754,9 +4751,9 @@
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="
}, },
"node_modules/yaml": { "node_modules/yaml": {
"version": "2.4.5", "version": "2.4.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz",
"integrity": "sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==", "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==",
"dev": true, "dev": true,
"bin": { "bin": {
"yaml": "bin.mjs" "yaml": "bin.mjs"

13
src/package.json

@ -11,18 +11,19 @@
"buildcss": "npx tailwindcss -i ./www/src/css/app.css -o ./www/css/app.css" "buildcss": "npx tailwindcss -i ./www/src/css/app.css -o ./www/css/app.css"
}, },
"author": "Emile Nijssen", "author": "Emile Nijssen",
"license": "CC BY-NC-SA 4.0", "license": "GPL",
"dependencies": { "dependencies": {
"bcryptjs": "^2.4.3", "bcryptjs": "^2.4.3",
"debug": "^4.3.5", "debug": "^4.3.4",
"express-session": "^1.18.0", "express-session": "^1.18.0",
"h3": "^1.12.0", "h3": "^1.11.1",
"qrcode": "^1.5.3" "qrcode": "^1.5.3",
"uuid": "^9.0.1"
}, },
"devDependencies": { "devDependencies": {
"eslint-config-athom": "^3.1.3", "eslint-config-athom": "^3.1.3",
"nodemon": "^3.1.4", "nodemon": "^3.1.0",
"tailwindcss": "^3.4.4" "tailwindcss": "^3.4.3"
}, },
"nodemonConfig": { "nodemonConfig": {
"ignore": [ "ignore": [

15
src/www/css/app.css

@ -1,5 +1,5 @@
/* /*
! tailwindcss v3.4.4 | MIT License | https://tailwindcss.com ! tailwindcss v3.4.3 | MIT License | https://tailwindcss.com
*/ */
/* /*
@ -802,11 +802,6 @@ video {
display: none; display: none;
} }
.size-6 {
width: 1.5rem;
height: 1.5rem;
}
.h-1 { .h-1 {
height: 0.25rem; height: 0.25rem;
} }
@ -851,10 +846,6 @@ video {
min-height: 100vh; min-height: 100vh;
} }
.w-1 {
width: 0.25rem;
}
.w-10 { .w-10 {
width: 2.5rem; width: 2.5rem;
} }
@ -1463,10 +1454,6 @@ video {
border-bottom-width: 0px; border-bottom-width: 0px;
} }
.hover\:cursor-pointer:hover {
cursor: pointer;
}
.hover\:border-red-800:hover { .hover\:border-red-800:hover {
--tw-border-opacity: 1; --tw-border-opacity: 1;
border-color: rgb(153 27 27 / var(--tw-border-opacity)); border-color: rgb(153 27 27 / var(--tw-border-opacity));

18
src/www/index.html

@ -91,24 +91,6 @@
<p class="text-2xl font-medium dark:text-neutral-200">{{$t("clients")}}</p> <p class="text-2xl font-medium dark:text-neutral-200">{{$t("clients")}}</p>
</div> </div>
<div class="flex-shrink-0"> <div class="flex-shrink-0">
<!-- Restore configuration -->
<label for="inputRC" :title="$t('titleRestoreConfig')"
class="hover:cursor-pointer hover:bg-red-800 hover:border-red-800 hover:text-white text-gray-700 dark:text-neutral-200 border-2 border-gray-100 dark:border-neutral-600 py-2 px-4 rounded inline-flex items-center transition">
<svg inline class="w-4 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182m0-4.991v4.99"></path>
</svg>
<span class="text-sm">{{$t("restore")}}</span>
<input id="inputRC" type="file" name="configurationfile" accept="text/*,.json" @change="restoreConfig" class="hidden"/>
</label>
<!-- Backup configuration -->
<a href="./api/wireguard/backup" :title="$t('titleBackupConfig')"
class="hover:bg-red-800 hover:border-red-800 hover:text-white text-gray-700 dark:text-neutral-200 border-2 border-gray-100 dark:border-neutral-600 py-2 px-4 rounded inline-flex items-center transition">
<svg inline class="w-4 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M5.25 14.25h13.5m-13.5 0a3 3 0 0 1-3-3m3 3a3 3 0 1 0 0 6h13.5a3 3 0 1 0 0-6m-16.5-3a3 3 0 0 1 3-3h13.5a3 3 0 0 1 3 3m-19.5 0a4.5 4.5 0 0 1 .9-2.7L5.737 5.1a3.375 3.375 0 0 1 2.7-1.35h7.126c1.062 0 2.062.5 2.7 1.35l2.587 3.45a4.5 4.5 0 0 1 .9 2.7m0 0a3 3 0 0 1-3 3m0 3h.008v.008h-.008v-.008Zm0-6h.008v.008h-.008v-.008Zm-3 6h.008v.008h-.008v-.008Zm0-6h.008v.008h-.008v-.008Z"></path>
</svg>
<span class="text-sm">{{$t("backup")}}</span>
</a>
<!-- New client -->
<button @click="clientCreate = true; clientCreateName = '';" <button @click="clientCreate = true; clientCreateName = '';"
class="hover:bg-red-800 hover:border-red-800 hover:text-white text-gray-700 dark:text-neutral-200 border-2 border-gray-100 dark:border-neutral-600 py-2 px-4 rounded inline-flex items-center transition"> class="hover:bg-red-800 hover:border-red-800 hover:text-white text-gray-700 dark:text-neutral-200 border-2 border-gray-100 dark:border-neutral-600 py-2 px-4 rounded inline-flex items-center transition">
<svg class="w-4 mr-2" inline xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" <svg class="w-4 mr-2" inline xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"

8
src/www/js/api.js

@ -138,12 +138,4 @@ class API {
}); });
} }
async restoreConfiguration(file) {
return this.call({
method: 'put',
path: '/wireguard/restore',
body: { file },
});
}
} }

19
src/www/js/app.js

@ -299,22 +299,6 @@ new Vue({
.catch((err) => alert(err.message || err.toString())) .catch((err) => alert(err.message || err.toString()))
.finally(() => this.refresh().catch(console.error)); .finally(() => this.refresh().catch(console.error));
}, },
restoreConfig(e) {
e.preventDefault();
const file = e.currentTarget.files.item(0);
if (file) {
file.text()
.then((content) => {
this.api.restoreConfiguration(content)
.then((_result) => alert('The configuration was updated.'))
.catch((err) => alert(err.message || err.toString()))
.finally(() => this.refresh().catch(console.error));
})
.catch((err) => alert(err.message || err.toString()));
} else {
alert('Failed to load your file!');
}
},
toggleTheme() { toggleTheme() {
const themes = ['light', 'dark', 'auto']; const themes = ['light', 'dark', 'auto'];
const currentIndex = themes.indexOf(this.uiTheme); const currentIndex = themes.indexOf(this.uiTheme);
@ -406,6 +390,9 @@ new Vue({
return releasesArray[0]; return releasesArray[0];
}); });
console.log(`Current Release: ${currentRelease}`);
console.log(`Latest Release: ${latestRelease.version}`);
if (currentRelease >= latestRelease.version) return; if (currentRelease >= latestRelease.version) return;
this.currentRelease = currentRelease; this.currentRelease = currentRelease;

46
src/www/js/i18n.js

@ -30,10 +30,6 @@ const messages = { // eslint-disable-line no-unused-vars
donate: 'Donate', donate: 'Donate',
toggleCharts: 'Show/hide Charts', toggleCharts: 'Show/hide Charts',
theme: { dark: 'Dark theme', light: 'Light theme', auto: 'Auto theme' }, theme: { dark: 'Dark theme', light: 'Light theme', auto: 'Auto theme' },
restore: 'Restore',
backup: 'Backup',
titleRestoreConfig: 'Restore your configuration',
titleBackupConfig: 'Backup your configuration',
}, },
ua: { ua: {
name: 'Ім`я', name: 'Ім`я',
@ -197,10 +193,6 @@ const messages = { // eslint-disable-line no-unused-vars
downloadConfig: 'Télécharger la configuration', downloadConfig: 'Télécharger la configuration',
madeBy: 'Développé par', madeBy: 'Développé par',
donate: 'Soutenir', donate: 'Soutenir',
restore: 'Restaurer',
backup: 'Sauvegarder',
titleRestoreConfig: 'Restaurer votre configuration',
titleBackupConfig: 'Sauvegarder votre configuration',
}, },
de: { // github.com/florian-asche de: { // github.com/florian-asche
name: 'Name', name: 'Name',
@ -229,10 +221,6 @@ const messages = { // eslint-disable-line no-unused-vars
downloadConfig: 'Konfiguration herunterladen', downloadConfig: 'Konfiguration herunterladen',
madeBy: 'Erstellt von', madeBy: 'Erstellt von',
donate: 'Spenden', donate: 'Spenden',
restore: 'Wiederherstellen',
backup: 'Sichern',
titleRestoreConfig: 'Stelle deine Konfiguration wieder her',
titleBackupConfig: 'Sichere deine Konfiguration',
}, },
ca: { // github.com/guillembonet ca: { // github.com/guillembonet
name: 'Nom', name: 'Nom',
@ -289,10 +277,6 @@ const messages = { // eslint-disable-line no-unused-vars
donate: 'Donar', donate: 'Donar',
toggleCharts: 'Mostrar/Ocultar gráficos', toggleCharts: 'Mostrar/Ocultar gráficos',
theme: { dark: 'Modo oscuro', light: 'Modo claro', auto: 'Modo automático' }, theme: { dark: 'Modo oscuro', light: 'Modo claro', auto: 'Modo automático' },
restore: 'Restaurar',
backup: 'Realizar copia de seguridad',
titleRestoreConfig: 'Restaurar su configuración',
titleBackupConfig: 'Realizar copia de seguridad de su configuración',
}, },
ko: { ko: {
name: '이름', name: '이름',
@ -461,27 +445,27 @@ const messages = { // eslint-disable-line no-unused-vars
password: '密碼', password: '密碼',
signIn: '登入', signIn: '登入',
logout: '登出', logout: '登出',
updateAvailable: '有新版本可以使用!', updateAvailable: '有新版本可用!',
update: '更新', update: '更新',
clients: '使用者', clients: '客戶',
new: '建', new: '建',
deleteClient: '刪除使用者', deleteClient: '刪除客戶',
deleteDialog1: '您確定要刪除', deleteDialog1: '您確定要刪除',
deleteDialog2: '此作業無法復原。', deleteDialog2: '此操作無法撤銷。',
cancel: '取消', cancel: '取消',
create: '建立', create: '建立',
createdOn: '建立於 ', createdOn: '建立於 ',
lastSeen: '最後存取於 ', lastSeen: '最後訪問於 ',
totalDownload: '總下載: ', totalDownload: '總下載: ',
totalUpload: '總上傳: ', totalUpload: '總上傳: ',
newClient: '新戶', newClient: '新戶',
disableClient: '停用使用者', disableClient: '禁用客戶',
enableClient: '啟用使用者', enableClient: '啟用客戶',
noClients: '目前沒有使用者。', noClients: '目前沒有客戶。',
showQR: '顯示 QR Code', showQR: '顯示二維碼',
downloadConfig: '下載 Config 檔', downloadConfig: '下載配置',
madeBy: '由', madeBy: '由',
donate: '抖內', donate: '捐贈',
}, },
it: { it: {
name: 'Nome', name: 'Nome',
@ -509,10 +493,6 @@ const messages = { // eslint-disable-line no-unused-vars
downloadConfig: 'Scarica configurazione', downloadConfig: 'Scarica configurazione',
madeBy: 'Realizzato da', madeBy: 'Realizzato da',
donate: 'Donazione', donate: 'Donazione',
restore: 'Ripristina',
backup: 'Backup',
titleRestoreConfig: 'Ripristina la tua configurazione',
titleBackupConfig: 'Esegui il backup della tua configurazione',
}, },
th: { th: {
name: 'ชื่อ', name: 'ชื่อ',

8
src/www/js/vendor/apexcharts.min.js

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save