Browse Source

start refactoring

pull/1864/head
Bernd Storath 3 months ago
parent
commit
a88e36319b
  1. 27
      src/eslint.config.js
  2. 11
      src/eslint.config.mjs
  3. 5
      src/server/database/repositories/client/schema.ts
  4. 8
      src/server/routes/metrics/prometheus.get.ts
  5. 4
      src/server/utils/Database.ts
  6. 13
      src/server/utils/WireGuard.ts
  7. 9
      src/server/utils/cmd.ts
  8. 10
      src/server/utils/handler.ts
  9. 15
      src/server/utils/ip.ts
  10. 2
      src/server/utils/release.ts
  11. 7
      src/server/utils/template.ts
  12. 95
      src/server/utils/types.ts
  13. 2
      src/server/utils/wgHelper.ts
  14. 2
      src/shared/utils/permissions.ts

27
src/eslint.config.js

@ -0,0 +1,27 @@
// @ts-check
import eslintConfigPrettier from 'eslint-config-prettier';
import withNuxt from './.nuxt/eslint.config.mjs';
export default withNuxt([
{
rules: {
'import/order': 'warn',
},
},
eslintConfigPrettier,
]).override('nuxt/typescript/rules', {
rules: {
'@typescript-eslint/restrict-template-expressions': [
'error',
{
allowAny: false,
allowBoolean: true,
allowNever: false,
allowNullish: false,
allowNumber: true,
allowRegExp: false,
},
],
},
});

11
src/eslint.config.mjs

@ -1,11 +0,0 @@
import eslintConfigPrettier from 'eslint-config-prettier';
import withNuxt from './.nuxt/eslint.config.mjs';
export default withNuxt([
{
rules: {
'import/order': 'warn',
},
},
eslintConfigPrettier,
]);

5
src/server/database/repositories/client/schema.ts

@ -43,10 +43,7 @@ export const client = sqliteTable('clients_table', {
}); });
export const clientsRelations = relations(client, ({ one }) => ({ export const clientsRelations = relations(client, ({ one }) => ({
oneTimeLink: one(oneTimeLink, { oneTimeLink: one(oneTimeLink),
fields: [client.id],
references: [oneTimeLink.id],
}),
user: one(user, { user: one(user, {
fields: [client.userId], fields: [client.userId],
references: [user.id], references: [user.id],

8
src/server/routes/metrics/prometheus.get.ts

@ -14,7 +14,7 @@ async function getPrometheusResponse() {
const wireguardLatestHandshakeSeconds = []; const wireguardLatestHandshakeSeconds = [];
for (const client of clients) { for (const client of clients) {
wireguardPeerCount++; wireguardPeerCount++;
if (client.enabled === true) { if (client.enabled) {
wireguardEnabledPeersCount++; wireguardEnabledPeersCount++;
} }
@ -55,15 +55,15 @@ async function getPrometheusResponse() {
'', '',
'# HELP wireguard_sent_bytes Bytes sent to the peer', '# HELP wireguard_sent_bytes Bytes sent to the peer',
'# TYPE wireguard_sent_bytes counter', '# TYPE wireguard_sent_bytes counter',
`${wireguardSentBytes.join('\n')}`, wireguardSentBytes.join('\n'),
'', '',
'# HELP wireguard_received_bytes Bytes received from the peer', '# HELP wireguard_received_bytes Bytes received from the peer',
'# TYPE wireguard_received_bytes counter', '# TYPE wireguard_received_bytes counter',
`${wireguardReceivedBytes.join('\n')}`, wireguardReceivedBytes.join('\n'),
'', '',
'# HELP wireguard_latest_handshake_seconds UNIX timestamp seconds of the last handshake', '# HELP wireguard_latest_handshake_seconds UNIX timestamp seconds of the last handshake',
'# TYPE wireguard_latest_handshake_seconds gauge', '# TYPE wireguard_latest_handshake_seconds gauge',
`${wireguardLatestHandshakeSeconds.join('\n')}`, wireguardLatestHandshakeSeconds.join('\n'),
]; ];
return returnText.join('\n'); return returnText.join('\n');

4
src/server/utils/Database.ts

@ -16,9 +16,9 @@ const nullObject = new Proxy(
// eslint-disable-next-line import/no-mutable-exports // eslint-disable-next-line import/no-mutable-exports
let provider = nullObject as never as DBServiceType; let provider = nullObject as never as DBServiceType;
connect().then((db) => { void connect().then((db) => {
provider = db; provider = db;
WireGuard.Startup(); void WireGuard.Startup();
}); });
export default provider; export default provider;

13
src/server/utils/WireGuard.ts

@ -158,10 +158,12 @@ class WireGuard {
WG_DEBUG(`Starting Wireguard Interface ${wgInterface.name}...`); WG_DEBUG(`Starting Wireguard Interface ${wgInterface.name}...`);
await this.#saveWireguardConfig(wgInterface); await this.#saveWireguardConfig(wgInterface);
await wg.down(wgInterface.name).catch(() => {}); await wg.down(wgInterface.name).catch(() => {});
await wg.up(wgInterface.name).catch((err) => { await wg.up(wgInterface.name).catch((err: unknown) => {
if ( if (
err && err &&
err.message && typeof err === 'object' &&
'message' in err &&
typeof err.message === 'string' &&
err.message.includes(`Cannot find device "${wgInterface.name}"`) err.message.includes(`Cannot find device "${wgInterface.name}"`)
) { ) {
throw new Error( throw new Error(
@ -181,13 +183,15 @@ class WireGuard {
} }
// TODO: handle as worker_thread // TODO: handle as worker_thread
// eslint-disable-next-line @typescript-eslint/require-await
async startCronJob() { async startCronJob() {
setIntervalImmediately(() => { setIntervalImmediately(() => {
this.cronJob().catch((err) => { this.cronJob().catch((err: unknown) => {
WG_DEBUG('Running Cron Job failed.'); WG_DEBUG('Running Cron Job failed.');
console.error(err); console.error(err);
}); });
}, 60 * 1000); }, 60 * 1000);
return;
} }
// Shutdown wireguard // Shutdown wireguard
@ -206,7 +210,7 @@ class WireGuard {
let needsSave = false; let needsSave = false;
// Expires Feature // Expires Feature
for (const client of clients) { for (const client of clients) {
if (client.enabled !== true) continue; if (!client.enabled) continue;
if ( if (
client.expiresAt !== null && client.expiresAt !== null &&
new Date() > new Date(client.expiresAt) new Date() > new Date(client.expiresAt)
@ -234,6 +238,7 @@ class WireGuard {
} }
} }
// eslint-disable-next-line @typescript-eslint/no-deprecated
if (OLD_ENV.PASSWORD || OLD_ENV.PASSWORD_HASH) { if (OLD_ENV.PASSWORD || OLD_ENV.PASSWORD_HASH) {
throw new Error( throw new Error(
` `

9
src/server/utils/cmd.ts

@ -9,7 +9,7 @@ export function exec(
) { ) {
if (typeof log === 'string') { if (typeof log === 'string') {
CMD_DEBUG(`$ ${log}`); CMD_DEBUG(`$ ${log}`);
} else if (log === true) { } else if (log) {
CMD_DEBUG(`$ ${cmd}`); CMD_DEBUG(`$ ${cmd}`);
} }
@ -24,8 +24,11 @@ export function exec(
shell: 'bash', shell: 'bash',
}, },
(err, stdout) => { (err, stdout) => {
if (err) return reject(err); if (err) {
return resolve(String(stdout).trim()); reject(err);
return;
}
resolve(String(stdout).trim());
} }
); );
}); });

10
src/server/utils/handler.ts

@ -99,16 +99,16 @@ export const defineSetupEventHandler = <
}); });
} }
const validSetupSteps = if (!(setup.step in ValidSetupSteps)) {
ValidSetupSteps[setup.step as keyof typeof ValidSetupSteps];
if (!validSetupSteps) {
throw createError({ throw createError({
statusCode: 500, statusCode: 500,
statusMessage: 'Invalid setup step', statusMessage: 'Invalid setup step',
}); });
} }
const validSetupSteps =
ValidSetupSteps[setup.step as keyof typeof ValidSetupSteps];
if (!validSetupSteps.includes(step as never)) { if (!validSetupSteps.includes(step as never)) {
throw createError({ throw createError({
statusCode: 400, statusCode: 400,
@ -169,7 +169,7 @@ export const defineMetricsHandler = <
} }
} }
if (metricsConfig[type] !== true) { if (!metricsConfig[type]) {
throw createError({ throw createError({
statusCode: 400, statusCode: 400,
statusMessage: 'Metrics not enabled', statusMessage: 'Metrics not enabled',

15
src/server/utils/ip.ts

@ -104,17 +104,22 @@ function getPrivateInformation() {
if (internal) { if (internal) {
continue; continue;
} }
if (!obj[name]) { if (!(name in obj)) {
obj[name] = { obj[name] = {
ipv4: [], ipv4: [],
ipv6: [], ipv6: [],
}; };
} }
if (family === 'IPv4') {
obj[name].ipv4.push(address); switch (family) {
} else if (family === 'IPv6') { case 'IPv4':
obj[name].ipv6.push(address); obj[name].ipv4.push(address);
continue;
case 'IPv6':
obj[name].ipv6.push(address);
continue;
} }
assertUnreachable(family);
} }
} }

2
src/server/utils/release.ts

@ -5,7 +5,7 @@ type GithubRelease = {
async function fetchLatestRelease() { async function fetchLatestRelease() {
try { try {
const response = await $fetch<GithubRelease>( const response = await $fetch<GithubRelease | ''>(
'https://api.github.com/repos/wg-easy/wg-easy/releases/latest', 'https://api.github.com/repos/wg-easy/wg-easy/releases/latest',
{ method: 'get', timeout: 5000 } { method: 'get', timeout: 5000 }
); );

7
src/server/utils/template.ts

@ -4,8 +4,11 @@ import type { InterfaceType } from '#db/repositories/interface/types';
* Replace all {{key}} in the template with the values[key] * Replace all {{key}} in the template with the values[key]
*/ */
export function template(templ: string, values: Record<string, string>) { export function template(templ: string, values: Record<string, string>) {
return templ.replace(/\{\{(\w+)\}\}/g, (match, key) => { return templ.replace(/\{\{(\w+)\}\}/g, (match, key: string) => {
return values[key] !== undefined ? values[key] : match; if (key in values) {
return values[key];
}
return match;
}); });
} }

95
src/server/utils/types.ts

@ -1,6 +1,6 @@
import type { ZodSchema } from 'zod'; import type { ZodSchema } from 'zod';
import z from 'zod'; import z from 'zod';
import type { H3Event, EventHandlerRequest } from 'h3'; import type { H3Event } from 'h3';
export type ID = number; export type ID = number;
@ -63,10 +63,7 @@ export const schemaForType =
return arg; return arg;
}; };
export function validateZod<T>( export function validateZod<T>(schema: ZodSchema<T>, event: H3Event) {
schema: ZodSchema<T>,
event: H3Event<EventHandlerRequest>
) {
return async (data: unknown) => { return async (data: unknown) => {
try { try {
return await schema.parseAsync(data); return await schema.parseAsync(data);
@ -79,64 +76,60 @@ export function validateZod<T>(
.map((v) => { .map((v) => {
let m = v.message; let m = v.message;
if (t) { let newMessage = null;
let newMessage = null; if (v.message.startsWith('zod.')) {
if (v.message.startsWith('zod.')) { switch (v.code) {
switch (v.code) { case 'too_small':
case 'too_small': switch (v.type) {
switch (v.type) { case 'string':
newMessage = t('zod.generic.stringMin', [
t(v.message),
v.minimum,
]);
break;
case 'number':
newMessage = t('zod.generic.numberMin', [
t(v.message),
v.minimum,
]);
break;
}
break;
case 'invalid_type': {
if (v.received === 'null' || v.received === 'undefined') {
newMessage = t('zod.generic.required', [v.path.join('.')]);
} else {
switch (v.expected) {
case 'string': case 'string':
newMessage = t('zod.generic.stringMin', [ newMessage = t('zod.generic.validString', [
t(v.message),
]);
break;
case 'boolean':
newMessage = t('zod.generic.validBoolean', [
t(v.message), t(v.message),
v.minimum,
]); ]);
break; break;
case 'number': case 'number':
newMessage = t('zod.generic.numberMin', [ newMessage = t('zod.generic.validNumber', [
t(v.message),
]);
break;
case 'array':
newMessage = t('zod.generic.validArray', [
t(v.message), t(v.message),
v.minimum,
]); ]);
break; break;
} }
break;
case 'invalid_type': {
if (v.received === 'null' || v.received === 'undefined') {
newMessage = t('zod.generic.required', [
v.path.join('.'),
]);
} else {
switch (v.expected) {
case 'string':
newMessage = t('zod.generic.validString', [
t(v.message),
]);
break;
case 'boolean':
newMessage = t('zod.generic.validBoolean', [
t(v.message),
]);
break;
case 'number':
newMessage = t('zod.generic.validNumber', [
t(v.message),
]);
break;
case 'array':
newMessage = t('zod.generic.validArray', [
t(v.message),
]);
break;
}
}
break;
} }
break;
} }
} }
if (newMessage) { }
m = newMessage; if (newMessage) {
} else { m = newMessage;
m = t(v.message); } else {
} m = t(v.message);
} }
return m; return m;

2
src/server/utils/wgHelper.ts

@ -10,7 +10,7 @@ export const wg = {
const allowedIps = [ const allowedIps = [
`${client.ipv4Address}/32`, `${client.ipv4Address}/32`,
`${client.ipv6Address}/128`, `${client.ipv6Address}/128`,
...(client.serverAllowedIps ?? []), ...client.serverAllowedIps,
]; ];
const extraLines = []; const extraLines = [];

2
src/shared/utils/permissions.ts

@ -134,7 +134,7 @@ export function hasPermissionsWithData<Resource extends keyof Permissions>(
) { ) {
let checked = false; let checked = false;
return { return {
check(data?: Permissions[Resource]['dataType']) { check(this: void, data?: Permissions[Resource]['dataType']) {
checked = true; checked = true;
const isAllowed = hasPermissions(user, resource, action, data); const isAllowed = hasPermissions(user, resource, action, data);

Loading…
Cancel
Save