mirror of
https://github.com/wireadmin/wireadmin
synced 2025-01-23 04:17:00 +00:00
install pino logger and update deps
This commit is contained in:
parent
0706f13216
commit
75013113b0
@ -15,7 +15,7 @@ RUN apk update && apk upgrade \
|
||||
# Install required packages
|
||||
&& apk add -U --no-cache \
|
||||
iproute2 iptables net-tools \
|
||||
screen vim curl bash \
|
||||
screen curl bash \
|
||||
wireguard-tools \
|
||||
openssl \
|
||||
tor \
|
||||
@ -63,8 +63,9 @@ HEALTHCHECK --interval=60s --timeout=3s --start-period=20s --retries=3 \
|
||||
|
||||
RUN mkdir -p /data && chmod 700 /data
|
||||
RUN mkdir -p /etc/torrc.d && chmod -R 400 /etc/torrc.d
|
||||
RUN mkdir -p /var/vlogs && chmod -R 600 /var/vlogs && touch /var/vlogs/web.log
|
||||
|
||||
VOLUME ["/etc/torrc.d", "/data"]
|
||||
VOLUME ["/etc/torrc.d", "/data", "/var/vlogs"]
|
||||
|
||||
# run the app
|
||||
EXPOSE 3000/tcp
|
||||
|
@ -47,8 +47,9 @@ ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
||||
RUN mkdir -p /data && chmod 700 /data
|
||||
RUN mkdir -p /etc/torrc.d && chmod -R 400 /etc/torrc.d
|
||||
RUN mkdir -p /var/vlogs && chmod -R 600 /var/vlogs && touch /var/vlogs/web.log
|
||||
|
||||
VOLUME ["/etc/torrc.d", "/data"]
|
||||
VOLUME ["/etc/torrc.d", "/data", "/var/vlogs"]
|
||||
|
||||
# run the appc
|
||||
EXPOSE 5173/tcp
|
||||
|
5
web/.mocharc.json
Normal file
5
web/.mocharc.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/mocharc.json",
|
||||
"require": ["tsx", "chai/register-expect"],
|
||||
"timeout": 10000
|
||||
}
|
@ -8,43 +8,49 @@
|
||||
"preview": "vite preview",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"test": "vitest",
|
||||
"test": "mocha",
|
||||
"lint": "prettier --plugin-search-dir . --check .",
|
||||
"format": "prettier --plugin-search-dir . --write .",
|
||||
"start": "node ./build/index.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-node": "^1.3.1",
|
||||
"@sveltejs/kit": "^1.27.7",
|
||||
"@types/crypto-js": "^4.2.1",
|
||||
"@sveltejs/adapter-node": "^2.0.0",
|
||||
"@sveltejs/kit": "^2.0.3",
|
||||
"@types/chai": "^4.3.11",
|
||||
"@types/jsonwebtoken": "^9.0.5",
|
||||
"@types/node": "^20.10.4",
|
||||
"@types/mocha": "^10.0.6",
|
||||
"@types/node": "^20.10.5",
|
||||
"@types/qrcode": "^1.5.5",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"chai": "^4.3.10",
|
||||
"mocha": "^10.2.0",
|
||||
"postcss": "^8.4.32",
|
||||
"postcss-load-config": "^5.0.2",
|
||||
"postcss-load-config": "^4.0.2",
|
||||
"prettier": "^3.1.1",
|
||||
"prettier-plugin-svelte": "^3.1.2",
|
||||
"svelte": "^4.2.8",
|
||||
"svelte-check": "^3.6.2",
|
||||
"sveltekit-superforms": "^1.11.0",
|
||||
"tailwindcss": "^3.3.6",
|
||||
"svelte-preprocess": "^5.1.3",
|
||||
"sveltekit-superforms": "^1.12.0",
|
||||
"tailwindcss": "^3.3.7",
|
||||
"tslib": "^2.6.2",
|
||||
"tsx": "^4.6.2",
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^5.0.7",
|
||||
"vite": "^5.0.10",
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"bits-ui": "^0.11.6",
|
||||
"clsx": "^2.0.0",
|
||||
"crypto-js": "^4.2.0",
|
||||
"deepmerge": "^4.3.1",
|
||||
"dotenv": "^16.3.1",
|
||||
"formsnap": "^0.4.1",
|
||||
"ioredis": "^5.3.2",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"lucide-svelte": "^0.294.0",
|
||||
"pino": "^8.17.1",
|
||||
"pino-pretty": "^10.3.0",
|
||||
"qrcode": "^1.5.3",
|
||||
"tailwind-merge": "^2.1.0",
|
||||
"tailwind-variants": "^0.1.18"
|
||||
|
1181
web/pnpm-lock.yaml
1181
web/pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
@ -1,11 +1,10 @@
|
||||
import jwt from 'jsonwebtoken';
|
||||
import 'dotenv/config';
|
||||
import Hex from 'crypto-js/enc-hex';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import SHA256 from 'crypto-js/sha256';
|
||||
import { client } from '$lib/redis';
|
||||
import { sha256 } from '$lib/hash';
|
||||
import 'dotenv/config';
|
||||
|
||||
export const AUTH_SECRET = process.env.AUTH_SECRET || Hex.stringify(SHA256(randomUUID()));
|
||||
export const AUTH_SECRET = process.env.AUTH_SECRET || sha256(randomUUID());
|
||||
|
||||
export async function generateToken(): Promise<string> {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
|
15
web/src/lib/fs-extra.ts
Normal file
15
web/src/lib/fs-extra.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { promises } from 'fs';
|
||||
|
||||
export async function fsAccess(path: string): Promise<boolean> {
|
||||
try {
|
||||
await promises.access(path);
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function fsTouch(filePath: string): Promise<void> {
|
||||
const fd = await promises.open(filePath, 'a');
|
||||
await fd.close();
|
||||
}
|
7
web/src/lib/hash.ts
Normal file
7
web/src/lib/hash.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { createHash } from 'crypto';
|
||||
|
||||
export function sha256(data: Buffer | string): string {
|
||||
const hash = createHash('sha256');
|
||||
hash.update(data);
|
||||
return hash.digest('hex');
|
||||
}
|
44
web/src/lib/logger.ts
Normal file
44
web/src/lib/logger.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import pino, { type Logger } from 'pino';
|
||||
import pretty from 'pino-pretty';
|
||||
import { createWriteStream } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
import { fsAccess, fsTouch } from '$lib/fs-extra';
|
||||
|
||||
const LOG_LEVEL = process.env.LOG_LEVEL || 'trace';
|
||||
const LOG_FILE_PATH = process.env.LOG_FILE_PATH || '/var/vlogs/web.log';
|
||||
const LOG_COLORS = process.env.LOG_COLORS || 'true';
|
||||
|
||||
const prettyStream = pretty({
|
||||
colorize: LOG_COLORS === 'true',
|
||||
});
|
||||
|
||||
let logger: Logger = pino(
|
||||
{
|
||||
level: LOG_LEVEL,
|
||||
},
|
||||
pino.multistream([prettyStream]),
|
||||
);
|
||||
|
||||
fsTouch(LOG_FILE_PATH)
|
||||
.then(() => fsAccess(LOG_FILE_PATH))
|
||||
.then((ok) => {
|
||||
if (!ok) {
|
||||
logger.warn('Log file is not accessible');
|
||||
}
|
||||
logger = pino(
|
||||
{
|
||||
level: LOG_LEVEL,
|
||||
},
|
||||
pino.multistream([
|
||||
prettyStream,
|
||||
createWriteStream(resolve(LOG_FILE_PATH), {
|
||||
flags: 'a',
|
||||
}),
|
||||
]),
|
||||
);
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error(error);
|
||||
});
|
||||
|
||||
export default logger;
|
@ -4,6 +4,4 @@ export const client = new IORedis({
|
||||
port: 6479,
|
||||
});
|
||||
|
||||
export type RedisClient = typeof client;
|
||||
|
||||
export const WG_SEVER_PATH = `WG::SERVERS`;
|
||||
|
@ -1,20 +1,36 @@
|
||||
import childProcess from 'child_process';
|
||||
import { exec } from 'child_process';
|
||||
import logger from '$lib/logger';
|
||||
|
||||
export default class Shell {
|
||||
public static async exec(command: string, safe: boolean = false, ...args: string[]): Promise<string> {
|
||||
if (process.platform !== 'linux') {
|
||||
throw new Error('This program is not meant to run non UNIX systems');
|
||||
}
|
||||
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const cmd = `${command}${args.length > 0 ? ` ${args.join(' ')}` : ''}`;
|
||||
childProcess.exec(cmd, { shell: 'bash' }, (err, stdout, stderr) => {
|
||||
exec(cmd, { shell: 'bash' }, (err, stdout, stderr) => {
|
||||
if (err) {
|
||||
console.error(
|
||||
`${safe ? 'Ignored::' : 'CRITICAL::'} Shell Command Failed:`,
|
||||
JSON.stringify({ cmd, code: err.code, killed: err.killed, stderr }),
|
||||
);
|
||||
return safe ? resolve(stderr) : reject(err);
|
||||
const message = `Command Failed: ${JSON.stringify(
|
||||
{
|
||||
cmd,
|
||||
code: err.code,
|
||||
killed: err.killed,
|
||||
stderr,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
)}`;
|
||||
|
||||
if (safe) {
|
||||
logger.warn(message);
|
||||
return resolve(stderr);
|
||||
}
|
||||
|
||||
logger.error(message);
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
return resolve(String(stdout).trim());
|
||||
});
|
||||
});
|
||||
|
@ -1,16 +1,10 @@
|
||||
import { type Actions, error } from '@sveltejs/kit';
|
||||
import type { PageServerLoad } from './$types';
|
||||
import {
|
||||
findServer,
|
||||
generateWgServer,
|
||||
getServers,
|
||||
isIPReserved,
|
||||
isPortReserved,
|
||||
WGServer,
|
||||
} from '$lib/wireguard';
|
||||
import { findServer, generateWgServer, getServers, isIPReserved, isPortReserved, WGServer } from '$lib/wireguard';
|
||||
import { setError, superValidate } from 'sveltekit-superforms/server';
|
||||
import { CreateServerSchema } from './schema';
|
||||
import { NameSchema } from '$lib/wireguard/schema';
|
||||
import logger from '$lib/logger';
|
||||
|
||||
export const load: PageServerLoad = async () => {
|
||||
return {
|
||||
@ -27,12 +21,12 @@ export const actions: Actions = {
|
||||
|
||||
const server = await findServer(serverId ?? '');
|
||||
if (!server) {
|
||||
console.error('Server not found');
|
||||
logger.error('Server not found');
|
||||
return error(404, 'Not found');
|
||||
}
|
||||
|
||||
if (!NameSchema.safeParse(name).success) {
|
||||
console.error('Peer name is invalid');
|
||||
logger.error('Peer name is invalid');
|
||||
return error(400, 'Bad Request');
|
||||
}
|
||||
|
||||
@ -71,7 +65,7 @@ export const actions: Actions = {
|
||||
serverId,
|
||||
};
|
||||
} catch (e: any) {
|
||||
console.error('Exception:', e);
|
||||
logger.error('Exception:', e);
|
||||
return setError(form, 'Unhandled Exception');
|
||||
}
|
||||
},
|
||||
|
@ -4,7 +4,7 @@ import { findServer, generateWgKey, WGServer } from '$lib/wireguard';
|
||||
import { NameSchema } from '$lib/wireguard/schema';
|
||||
import { setError, superValidate } from 'sveltekit-superforms/server';
|
||||
import { CreatePeerSchema } from './schema';
|
||||
import { WgServerStatusSchema } from '$lib/typings';
|
||||
import logger from '$lib/logger';
|
||||
|
||||
export const load: PageServerLoad = async ({ params }) => {
|
||||
const { serverId } = params;
|
||||
@ -22,7 +22,7 @@ export const actions: Actions = {
|
||||
const { serverId } = params;
|
||||
const server = await findServer(serverId ?? '');
|
||||
if (!server) {
|
||||
console.error('Server not found');
|
||||
logger.error('Server not found');
|
||||
throw error(404, 'Not found');
|
||||
}
|
||||
|
||||
@ -30,13 +30,13 @@ export const actions: Actions = {
|
||||
const peerId = (form.get('id') ?? '').toString();
|
||||
const peer = server.peers.find((p) => p.id === peerId);
|
||||
if (!peer) {
|
||||
console.error('Peer not found');
|
||||
logger.error('Peer not found');
|
||||
throw error(404, 'Not found');
|
||||
}
|
||||
|
||||
const name = (form.get('name') ?? '').toString();
|
||||
if (!NameSchema.safeParse(name).success) {
|
||||
console.error('Peer name is invalid');
|
||||
logger.error('Peer name is invalid');
|
||||
throw error(400, 'Bad Request');
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ export const actions: Actions = {
|
||||
|
||||
return { ok: true };
|
||||
} catch (e) {
|
||||
console.error('Exception:', e);
|
||||
logger.error('Exception:', e);
|
||||
throw error(500, 'Unhandled Exception');
|
||||
}
|
||||
},
|
||||
|
@ -1,5 +1,6 @@
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { getConfigHash, getServers, WGServer } from '$lib/wireguard';
|
||||
import logger from '$lib/logger';
|
||||
|
||||
export const GET: RequestHandler = async () => {
|
||||
try {
|
||||
@ -18,7 +19,7 @@ export const GET: RequestHandler = async () => {
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('APIFailed: HealthCheck:', e);
|
||||
logger.error('APIFailed: HealthCheck:', e);
|
||||
return new Response('FAILED', { status: 500, headers: { 'Content-Type': 'text/plain' } });
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import Shell from '$lib/shell';
|
||||
import 'dotenv/config';
|
||||
import logger from '$lib/logger';
|
||||
|
||||
export const GET: RequestHandler = async () => {
|
||||
|
||||
let { WG_HOST } = process.env
|
||||
let { WG_HOST } = process.env;
|
||||
|
||||
// if the host is not set, then we are using the server's public IP
|
||||
if (!WG_HOST) {
|
||||
@ -14,7 +14,7 @@ export const GET: RequestHandler = async () => {
|
||||
|
||||
// check if WG_HOST is still not set
|
||||
if (!WG_HOST) {
|
||||
console.error('WG_HOST is not set');
|
||||
logger.error('WG_HOST is not set');
|
||||
return new Response('NOT_SET', { status: 500, headers: { 'Content-Type': 'text/plain' } });
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ export const POST: RequestHandler = async ({ request }) => {
|
||||
|
||||
const body = await request.text();
|
||||
const data = await QRCode.toDataURL(body, {
|
||||
errorCorrectionLevel: 'H',
|
||||
errorCorrectionLevel: 'M',
|
||||
width: 500,
|
||||
});
|
||||
|
||||
|
@ -5,6 +5,7 @@ import { setError, superValidate } from 'sveltekit-superforms/server';
|
||||
import { formSchema } from './schema';
|
||||
import { generateToken } from '$lib/auth';
|
||||
import 'dotenv/config';
|
||||
import logger from '$lib/logger';
|
||||
|
||||
export const load: PageServerLoad = () => {
|
||||
return {
|
||||
@ -14,6 +15,7 @@ export const load: PageServerLoad = () => {
|
||||
|
||||
export const actions: Actions = {
|
||||
default: async (event) => {
|
||||
const { cookies } = event;
|
||||
const form = await superValidate(event, formSchema);
|
||||
|
||||
if (!form.valid) {
|
||||
@ -33,22 +35,19 @@ export const actions: Actions = {
|
||||
}
|
||||
|
||||
if (!HASHED_PASSWORD) {
|
||||
console.warn('No password is set!');
|
||||
logger.warn('No password is set!');
|
||||
}
|
||||
|
||||
const token = await generateToken();
|
||||
|
||||
const { ORIGIN } = process.env;
|
||||
if (ORIGIN) {
|
||||
const secure = ORIGIN.startsWith('https://');
|
||||
event.cookies.set('authorization', token, {
|
||||
secure,
|
||||
httpOnly: true,
|
||||
path: '/',
|
||||
});
|
||||
} else {
|
||||
event.cookies.set('authorization', token);
|
||||
}
|
||||
|
||||
const secure = ORIGIN?.startsWith('https://') ?? false;
|
||||
cookies.set('authorization', token, {
|
||||
secure,
|
||||
httpOnly: true,
|
||||
path: '/',
|
||||
});
|
||||
|
||||
return { form, ok: true };
|
||||
},
|
||||
|
@ -7,6 +7,8 @@ export const load: PageServerLoad = async ({ cookies }) => {
|
||||
const token = cookies.get('authorization')!;
|
||||
await revokeToken(token).catch(() => {});
|
||||
}
|
||||
cookies.delete('authorization');
|
||||
cookies.delete('authorization', {
|
||||
path: '/',
|
||||
});
|
||||
throw redirect(302, '/login');
|
||||
};
|
||||
|
@ -1,21 +1,21 @@
|
||||
import adapter from '@sveltejs/adapter-node';
|
||||
import { vitePreprocess } from '@sveltejs/kit/vite';
|
||||
import sveltePreprocess from 'svelte-preprocess';
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
|
||||
// for more information about preprocessors
|
||||
preprocess: [ vitePreprocess({}) ],
|
||||
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
|
||||
// for more information about preprocessors
|
||||
preprocess: [sveltePreprocess()],
|
||||
|
||||
kit: {
|
||||
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
|
||||
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
|
||||
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
|
||||
adapter: adapter(),
|
||||
alias: {
|
||||
$lib: './src/lib'
|
||||
}
|
||||
}
|
||||
kit: {
|
||||
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
|
||||
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
|
||||
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
|
||||
adapter: adapter(),
|
||||
alias: {
|
||||
$lib: './src/lib',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
Loading…
Reference in New Issue
Block a user