mirror of
https://github.com/wireadmin/wireadmin
synced 2025-06-26 18:28:06 +00:00
install pino logger and update deps
This commit is contained in:
@@ -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');
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user