Browse Source

update

pull/1345/head
Bernd Storath 11 months ago
parent
commit
ad24f54dfd
  1. 1
      src/app/app.vue
  2. 2
      src/app/pages/login.vue
  3. 8
      src/app/stores/global.ts
  4. 6
      src/app/utils/api.ts
  5. 5
      src/server/api/remember-me.get.ts
  6. 5
      src/server/api/session.post.ts
  7. 27
      src/server/utils/WireGuard.ts
  8. 51
      src/server/utils/config.ts
  9. 2
      src/services/database/lowdb.ts
  10. 60
      src/services/database/migrations/1.ts
  11. 4
      src/services/database/repositories/system.ts

1
src/app/app.vue

@ -14,7 +14,6 @@ globalStore.fetchRelease();
globalStore.fetchOneTimeLinks(); globalStore.fetchOneTimeLinks();
globalStore.fetchSortClients(); globalStore.fetchSortClients();
globalStore.fetchExpireTime(); globalStore.fetchExpireTime();
globalStore.fetchRememberMe();
useHead({ useHead({
bodyAttrs: { bodyAttrs: {
class: 'bg-gray-50 dark:bg-neutral-800', class: 'bg-gray-50 dark:bg-neutral-800',

2
src/app/pages/login.vue

@ -37,7 +37,6 @@
/> />
<label <label
v-if="globalStore.rememberMeEnabled"
class="inline-block mb-5 cursor-pointer whitespace-nowrap" class="inline-block mb-5 cursor-pointer whitespace-nowrap"
:title="$t('titleRememberMe')" :title="$t('titleRememberMe')"
> >
@ -89,7 +88,6 @@ const remember = ref(false);
const username = ref<null | string>(null); const username = ref<null | string>(null);
const password = ref<null | string>(null); const password = ref<null | string>(null);
const authStore = useAuthStore(); const authStore = useAuthStore();
const globalStore = useGlobalStore();
async function login(e: Event) { async function login(e: Event) {
e.preventDefault(); e.preventDefault();

8
src/app/stores/global.ts

@ -8,7 +8,6 @@ export const useGlobalStore = defineStore('Global', () => {
null null
); );
const uiTrafficStats = ref(false); const uiTrafficStats = ref(false);
const rememberMeEnabled = ref(false);
const enableExpireTime = ref(false); const enableExpireTime = ref(false);
const enableOneTimeLinks = ref(false); const enableOneTimeLinks = ref(false);
const enableSortClient = ref(false); const enableSortClient = ref(false);
@ -65,11 +64,6 @@ export const useGlobalStore = defineStore('Global', () => {
enableExpireTime.value = expireTime.value ?? false; enableExpireTime.value = expireTime.value ?? false;
} }
async function fetchRememberMe() {
const { data: rememberMe } = await api.getRememberMeEnabled();
rememberMeEnabled.value = rememberMe.value ?? false;
}
const updateCharts = computed(() => { const updateCharts = computed(() => {
return uiChartType.value > 0 && uiShowCharts.value; return uiChartType.value > 0 && uiShowCharts.value;
}); });
@ -79,7 +73,6 @@ export const useGlobalStore = defineStore('Global', () => {
uiShowCharts, uiShowCharts,
uiTrafficStats, uiTrafficStats,
updateCharts, updateCharts,
rememberMeEnabled,
enableSortClient, enableSortClient,
sortClient, sortClient,
enableExpireTime, enableExpireTime,
@ -90,6 +83,5 @@ export const useGlobalStore = defineStore('Global', () => {
fetchOneTimeLinks, fetchOneTimeLinks,
fetchSortClients, fetchSortClients,
fetchExpireTime, fetchExpireTime,
fetchRememberMe,
}; };
}); });

6
src/app/utils/api.ts

@ -11,12 +11,6 @@ class API {
}); });
} }
async getRememberMeEnabled() {
return useFetch('/api/remember-me', {
method: 'get',
});
}
async getTrafficStats() { async getTrafficStats() {
return useFetch('/api/ui-traffic-stats', { return useFetch('/api/ui-traffic-stats', {
method: 'get', method: 'get',

5
src/server/api/remember-me.get.ts

@ -1,5 +0,0 @@
export default defineEventHandler(async (event) => {
setHeader(event, 'Content-Type', 'application/json');
// TODO: enable by default
return MAX_AGE > 0;
});

5
src/server/api/session.post.ts

@ -30,10 +30,11 @@ export default defineEventHandler(async (event) => {
}); });
const conf: SessionConfig = system.sessionConfig; const conf: SessionConfig = system.sessionConfig;
if (MAX_AGE && remember) {
if (remember) {
conf.cookie = { conf.cookie = {
...(system.sessionConfig.cookie ?? {}), ...(system.sessionConfig.cookie ?? {}),
maxAge: MAX_AGE, maxAge: system.cookieMaxAge * 60,
}; };
} }

27
src/server/utils/WireGuard.ts

@ -1,6 +1,6 @@
import fs from 'node:fs/promises'; import fs from 'node:fs/promises';
import path from 'path'; import path from 'path';
import debug from 'DEBUG'; import debug from 'debug';
import crypto from 'node:crypto'; import crypto from 'node:crypto';
import QRCode from 'qrcode'; import QRCode from 'qrcode';
import CRC32 from 'crc-32'; import CRC32 from 'crc-32';
@ -47,7 +47,7 @@ ${
} }
DEBUG('Config saving...'); DEBUG('Config saving...');
await fs.writeFile(path.join(WG_PATH, 'wg0.conf'), result, { await fs.writeFile(path.join('/etc/wireguard', 'wg0.conf'), result, {
mode: 0o600, mode: 0o600,
}); });
DEBUG('Config saved.'); DEBUG('Config saved.');
@ -136,16 +136,15 @@ ${
[Interface] [Interface]
PrivateKey = ${client.privateKey ? `${client.privateKey}` : 'REPLACE_ME'} PrivateKey = ${client.privateKey ? `${client.privateKey}` : 'REPLACE_ME'}
Address = ${client.address}/24 Address = ${client.address}/24
${WG_DEFAULT_DNS ? `DNS = ${WG_DEFAULT_DNS}\n` : ''}\ DNS = ${system.userConfig.defaultDns.join(',')}
${WG_MTU ? `MTU = ${WG_MTU}\n` : ''}\ MTU = ${system.userConfig.mtu}
[Peer] [Peer]
PublicKey = ${system.interface.publicKey} PublicKey = ${system.interface.publicKey}
${ PresharedKey = ${client.preSharedKey}
client.preSharedKey ? `PresharedKey = ${client.preSharedKey}\n` : '' AllowedIPs = ${client.allowedIPs}
}AllowedIPs = ${client.allowedIPs}
PersistentKeepalive = ${client.persistentKeepalive} PersistentKeepalive = ${client.persistentKeepalive}
Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`; Endpoint = ${system.wgHost}:${system.wgConfigPort}`;
} }
async getClientQRCodeSVG({ clientId }: { clientId: string }) { async getClientQRCodeSVG({ clientId }: { clientId: string }) {
@ -167,6 +166,7 @@ Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`;
throw new Error('Missing: Name'); throw new Error('Missing: Name');
} }
const system = await Database.getSystem();
const clients = await Database.getClients(); const clients = await Database.getClients();
const privateKey = await exec('wg genkey'); const privateKey = await exec('wg genkey');
@ -180,11 +180,14 @@ Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`;
let address; let address;
for (let i = 2; i < 255; i++) { for (let i = 2; i < 255; i++) {
const client = Object.values(clients).find((client) => { const client = Object.values(clients).find((client) => {
return client.address === WG_DEFAULT_ADDRESS.replace('x', i.toString()); return (
client.address ===
system.userConfig.addressRange.replace('x', i.toString())
);
}); });
if (!client) { if (!client) {
address = WG_DEFAULT_ADDRESS.replace('x', i.toString()); address = system.userConfig.addressRange.replace('x', i.toString());
break; break;
} }
} }
@ -207,8 +210,8 @@ Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`;
oneTimeLink: null, oneTimeLink: null,
expiresAt: null, expiresAt: null,
enabled: true, enabled: true,
allowedIPs: WG_ALLOWED_IPS.split(', '), allowedIPs: system.userConfig.allowedIps,
persistentKeepalive: Number(WG_PERSISTENT_KEEPALIVE), persistentKeepalive: system.userConfig.persistentKeepalive,
}; };
if (expireDate) { if (expireDate) {

51
src/server/utils/config.ts

@ -1,50 +1,5 @@
import type { SessionConfig } from 'h3';
import debug from 'debug'; import debug from 'debug';
export const MAX_AGE = process.env.MAX_AGE
? parseInt(process.env.MAX_AGE, 10) * 60
: 0;
export const WG_PATH = process.env.WG_PATH || '/etc/wireguard/';
export const WG_DEVICE = process.env.WG_DEVICE || 'eth0';
export const WG_HOST = process.env.WG_HOST;
export const WG_PORT = process.env.WG_PORT || '51820';
export const WG_CONFIG_PORT =
process.env.WG_CONFIG_PORT || process.env.WG_PORT || '51820';
export const WG_MTU = process.env.WG_MTU || null;
export const WG_PERSISTENT_KEEPALIVE =
process.env.WG_PERSISTENT_KEEPALIVE || '0';
export const WG_DEFAULT_ADDRESS = process.env.WG_DEFAULT_ADDRESS || '10.8.0.x';
export const WG_DEFAULT_DNS =
typeof process.env.WG_DEFAULT_DNS === 'string'
? process.env.WG_DEFAULT_DNS
: '1.1.1.1';
export const WG_ALLOWED_IPS = process.env.WG_ALLOWED_IPS || '0.0.0.0/0, ::/0';
export const WG_PRE_UP = process.env.WG_PRE_UP || '';
export const WG_POST_UP =
process.env.WG_POST_UP ||
`
iptables -t nat -A POSTROUTING -s ${WG_DEFAULT_ADDRESS.replace('x', '0')}/24 -o ${WG_DEVICE} -j MASQUERADE;
iptables -A INPUT -p udp -m udp --dport ${WG_PORT} -j ACCEPT;
iptables -A FORWARD -i wg0 -j ACCEPT;
iptables -A FORWARD -o wg0 -j ACCEPT;
`
.split('\n')
.join(' ');
export const WG_PRE_DOWN = process.env.WG_PRE_DOWN || '';
export const WG_POST_DOWN =
process.env.WG_POST_DOWN ||
`
iptables -t nat -D POSTROUTING -s ${WG_DEFAULT_ADDRESS.replace('x', '0')}/24 -o ${WG_DEVICE} -j MASQUERADE;
iptables -D INPUT -p udp -m udp --dport ${WG_PORT} -j ACCEPT;
iptables -D FORWARD -i wg0 -j ACCEPT;
iptables -D FORWARD -o wg0 -j ACCEPT;
`
.split('\n')
.join(' ');
export const LANG = process.env.LANG || 'en';
export const UI_TRAFFIC_STATS = process.env.UI_TRAFFIC_STATS || 'false'; export const UI_TRAFFIC_STATS = process.env.UI_TRAFFIC_STATS || 'false';
export const UI_CHART_TYPE = process.env.UI_CHART_TYPE || '0'; export const UI_CHART_TYPE = process.env.UI_CHART_TYPE || '0';
export const WG_ENABLE_ONE_TIME_LINKS = export const WG_ENABLE_ONE_TIME_LINKS =
@ -60,10 +15,4 @@ export const PROMETHEUS_METRICS_PASSWORD =
export const REQUIRES_PROMETHEUS_PASSWORD = !!PROMETHEUS_METRICS_PASSWORD; export const REQUIRES_PROMETHEUS_PASSWORD = !!PROMETHEUS_METRICS_PASSWORD;
export const SESSION_CONFIG = {
password: getRandomHex(256),
name: 'wg-easy',
cookie: undefined,
} satisfies SessionConfig;
export const SERVER_DEBUG = debug('Server'); export const SERVER_DEBUG = debug('Server');

2
src/services/database/lowdb.ts

@ -23,7 +23,7 @@ export default class LowDB extends DatabaseProvider {
// is this really needed? // is this really needed?
private async __init() { private async __init() {
// TODO: assume path to db file // TODO: assume path to db file
const dbFilePath = join(WG_PATH, 'db.json'); const dbFilePath = join('/etc/wireguard', 'db.json');
this.#db = await JSONFilePreset(dbFilePath, DEFAULT_DATABASE); this.#db = await JSONFilePreset(dbFilePath, DEFAULT_DATABASE);
} }

60
src/services/database/migrations/1.ts

@ -3,32 +3,12 @@ import type { Database } from '../repositories/database';
import packageJson from '@@/package.json'; import packageJson from '@@/package.json';
import { ChartType } from '../repositories/system'; import { ChartType } from '../repositories/system';
// TODO: use variables inside up/down script
const DEFAULT_ADDRESS = '10.8.0.x';
const DEFAULT_DEVICE = 'eth0';
const DEFAULT_WG_PORT = 51820;
const DEFAULT_POST_UP = `
iptables -t nat -A POSTROUTING -s ${DEFAULT_ADDRESS.replace('x', '0')}/24 -o ${DEFAULT_DEVICE} -j MASQUERADE;
iptables -A INPUT -p udp -m udp --dport ${DEFAULT_WG_PORT} -j ACCEPT;
iptables -A FORWARD -i wg0 -j ACCEPT;
iptables -A FORWARD -o wg0 -j ACCEPT;
`
.split('\n')
.join(' ');
const DEFAULT_POST_DOWN = `
iptables -t nat -D POSTROUTING -s ${DEFAULT_ADDRESS.replace('x', '0')}/24 -o ${DEFAULT_DEVICE} -j MASQUERADE;
iptables -D INPUT -p udp -m udp --dport ${DEFAULT_WG_PORT} -j ACCEPT;
iptables -D FORWARD -i wg0 -j ACCEPT;
iptables -D FORWARD -o wg0 -j ACCEPT;
`
.split('\n')
.join(' ');
export async function run1(db: Low<Database>) { export async function run1(db: Low<Database>) {
const privateKey = await exec('wg genkey'); const privateKey = await exec('wg genkey');
const publicKey = await exec(`echo ${privateKey} | wg pubkey`, { const publicKey = await exec(`echo ${privateKey} | wg pubkey`, {
log: 'echo ***hidden*** | wg pubkey', log: 'echo ***hidden*** | wg pubkey',
}); });
const addressRange = '10.8.0.x';
const database: Database = { const database: Database = {
migrations: [], migrations: [],
system: { system: {
@ -36,7 +16,7 @@ export async function run1(db: Low<Database>) {
interface: { interface: {
privateKey: privateKey, privateKey: privateKey,
publicKey: publicKey, publicKey: publicKey,
address: DEFAULT_ADDRESS.replace('x', '1'), address: addressRange.replace('x', '1'),
}, },
sessionTimeout: 3600, // 1 hour sessionTimeout: 3600, // 1 hour
lang: 'en', lang: 'en',
@ -44,20 +24,21 @@ export async function run1(db: Low<Database>) {
mtu: 1420, mtu: 1420,
persistentKeepalive: 0, persistentKeepalive: 0,
// TODO: assume handle CIDR to compute next ip in WireGuard // TODO: assume handle CIDR to compute next ip in WireGuard
rangeAddress: '10.8.0.0/24', //addressRange: '10.8.0.0/24',
addressRange: addressRange,
defaultDns: ['1.1.1.1'], defaultDns: ['1.1.1.1'],
allowedIps: ['0.0.0.0/0', '::/0'], allowedIps: ['0.0.0.0/0', '::/0'],
}, },
wgPath: WG_PATH, wgDevice: 'wg0',
wgDevice: DEFAULT_DEVICE, // TODO: wgHost has to be configured when onboarding
wgHost: WG_HOST || '', wgHost: '',
wgPort: DEFAULT_WG_PORT, wgPort: 51820,
wgConfigPort: 51820, wgConfigPort: 51820,
iptables: { iptables: {
PreUp: '', PreUp: '',
PostUp: DEFAULT_POST_UP, PostUp: '',
PreDown: '', PreDown: '',
PostDown: DEFAULT_POST_DOWN, PostDown: '',
}, },
trafficStats: { trafficStats: {
enabled: false, enabled: false,
@ -79,13 +60,32 @@ export async function run1(db: Low<Database>) {
sessionConfig: { sessionConfig: {
password: getRandomHex(256), password: getRandomHex(256),
name: 'wg-easy', name: 'wg-easy',
cookie: undefined, cookie: {},
}, },
cookieMaxAge: 24 * 60,
}, },
users: [], users: [],
clients: {}, clients: {},
}; };
// TODO: use variables inside up/down script
database.system.iptables.PostUp = `
iptables -t nat -A POSTROUTING -s ${database.system.userConfig.addressRange.replace('x', '0')}/24 -o ${database.system.wgDevice} -j MASQUERADE;
iptables -A INPUT -p udp -m udp --dport ${database.system.wgPort} -j ACCEPT;
iptables -A FORWARD -i wg0 -j ACCEPT;
iptables -A FORWARD -o wg0 -j ACCEPT;
`
.split('\n')
.join(' ');
database.system.iptables.PostDown = `
iptables -t nat -D POSTROUTING -s ${database.system.userConfig.addressRange.replace('x', '0')}/24 -o ${database.system.wgDevice} -j MASQUERADE;
iptables -D INPUT -p udp -m udp --dport ${database.system.wgPort} -j ACCEPT;
iptables -D FORWARD -i wg0 -j ACCEPT;
iptables -D FORWARD -o wg0 -j ACCEPT;
`
.split('\n')
.join(' ');
db.data = database; db.data = database;
db.write(); db.write();
} }

4
src/services/database/repositories/system.ts

@ -18,7 +18,7 @@ export type WGInterface = {
export type WGConfig = { export type WGConfig = {
mtu: number; mtu: number;
persistentKeepalive: number; persistentKeepalive: number;
rangeAddress: string; addressRange: string;
defaultDns: string[]; defaultDns: string[];
allowedIps: string[]; allowedIps: string[];
}; };
@ -57,7 +57,6 @@ export type System = {
userConfig: WGConfig; userConfig: WGConfig;
wgPath: string;
wgDevice: string; wgDevice: string;
wgHost: string; wgHost: string;
wgPort: number; wgPort: number;
@ -72,6 +71,7 @@ export type System = {
prometheus: Prometheus; prometheus: Prometheus;
sessionConfig: SessionConfig; sessionConfig: SessionConfig;
cookieMaxAge: number;
}; };
/** /**

Loading…
Cancel
Save