Porting from bun to node

This commit is contained in:
2025-07-02 14:49:23 +00:00
parent 0fbbfec737
commit d7282c0c89
46 changed files with 3339 additions and 831 deletions

2
src/app.d.ts vendored
View File

@@ -1,4 +1,4 @@
import type { AppData } from "$lib/classes/appdata";
import type { AppData } from "$lib/server/classes/appdata";
// See https://svelte.dev/docs/kit/types#app.d.ts
// for information about these interfaces

View File

@@ -1,34 +1,43 @@
import type { ServerInit } from '@sveltejs/kit';
import { handles } from './handles/handle';
import { DatabaseBrokerManager } from '$lib/broker-utils/SQLite/Database';
import { UserApp } from '$lib/classes/users';
import { UserDBBroker } from '$lib/broker-utils/SQLite/Users';
import { SessionApp } from '$lib/classes/sessions';
import { SessionDBBroker } from '$lib/broker-utils/SQLite/Sessions';
import { AppData } from '$lib/classes/appdata';
import { logger } from '$lib/utils/logger';
import { JoseApp } from '$lib/utils/jtw-utils';
import { handles } from './lib/server/handles/handle';
import { DatabaseBrokerManager } from '$lib/server/broker-utils/SQLite/Database';
import { UserApp } from '$lib/server/classes/users';
import { UserDBBroker } from '$lib/server/broker-utils/SQLite/Users';
import { SessionApp } from '$lib/server/classes/sessions';
import { SessionDBBroker } from '$lib/server/broker-utils/SQLite/Sessions';
import { AppData } from '$lib/server/classes/appdata';
import { logger } from '$lib/server/utils/logger';
import { JoseApp } from '$lib/server/utils/jtw-utils';
export const init: ServerInit = async () => {
logger.debug("Starting app", "App Init")
if(!DatabaseBrokerManager.ready) {
if (!DatabaseBrokerManager.ready) {
DatabaseBrokerManager.init()
}
UserApp.init(
new UserDBBroker()
)
SessionApp.init(
new SessionDBBroker()
)
// This is async
await JoseApp.init()
if (!UserApp.ready) {
UserApp.init(
new UserDBBroker()
)
}
if (!SessionApp.ready) {
SessionApp.init(
new SessionDBBroker()
)
}
if (!JoseApp.ready) {
// This is async
await JoseApp.init()
}
logger.debug("Init run successfully", "App Init")
};
export const handle = handles

View File

@@ -1,12 +1,13 @@
import { DB_PATH } from "$lib/utils/constants";
import { logger } from "$lib/utils/logger";
import { Database, Statement } from "bun:sqlite";
import { DB_PATH } from "$lib/server/utils/constants";
import { logger } from "$lib/server/utils/logger";
// TODO: remove bun dependencies
import { DatabaseSync } from 'node:sqlite';
export class DatabaseBrokerManager {
private static initialized = false
private static db: Database
private static db: DatabaseSync
// UGLY: should be more flexible
public static init() {
@@ -36,13 +37,7 @@ export class DatabaseBrokerManager {
private static initDatabase() {
const db = new Database(
DB_PATH,
{
create: true,
strict: true
}
)
const db = new DatabaseSync(DB_PATH)
// Improve performance
db.exec("PRAGMA journal_mode = WAL;");
@@ -52,15 +47,8 @@ export class DatabaseBrokerManager {
}
private static closeDatabase(graceful?: boolean) {
if (!graceful) {
graceful = true
}
// Change of variable to make it more readable
const forceful = !graceful
DatabaseBrokerManager.db.close(forceful)
private static closeDatabase() {
DatabaseBrokerManager.db.close()
}
}

View File

@@ -1,5 +1,5 @@
import { Session, type ISessionBroker } from "$lib/classes/sessions"
import { logger } from "$lib/utils/logger"
import { Session, type ISessionBroker } from "$lib/server/classes/sessions"
import { logger } from "$lib/server/utils/logger"
import { DatabaseBrokerManager } from "./Database"
class SessionDB {
@@ -52,7 +52,7 @@ export class SessionDBBroker implements ISessionBroker {
)
stmt.run()
stmt.finalize()
}
@@ -81,7 +81,7 @@ export class SessionDBBroker implements ISessionBroker {
userID: userID,
token: token
})
stmt.finalize()
// Check if Session has been successfully created
const session = this.getSessionFromUserID(userID)
@@ -140,7 +140,7 @@ export class SessionDBBroker implements ISessionBroker {
const sessions = stmt.all({
token: token
})
stmt.finalize()
return this.parseSessionDBUnique(sessions)
@@ -158,7 +158,7 @@ export class SessionDBBroker implements ISessionBroker {
const sessions = stmt.all({
userID: userID
})
stmt.finalize()
return this.parseSessionDBUnique(sessions)
}
@@ -176,7 +176,7 @@ export class SessionDBBroker implements ISessionBroker {
const sessions = stmt.all({
sessionID: sessionID
})
stmt.finalize()
return this.parseSessionDBUnique(sessions)
}

View File

@@ -1,6 +1,6 @@
import type { Session, SessionApp } from "$lib/classes/sessions";
import { User, type IUserBroker } from "$lib/classes/users";
import { logger } from "$lib/utils/logger";
import type { Session, SessionApp } from "$lib/server/classes/sessions";
import { User, type IUserBroker } from "$lib/server/classes/users";
import { logger } from "$lib/server/utils/logger";
import { DatabaseBrokerManager } from "./Database";
import * as argon2 from "argon2";
@@ -47,7 +47,7 @@ export class UserDBBroker implements IUserBroker {
`
)
stmt.run()
stmt.finalize()
}
public async createUser(username: string, password: string): Promise<User> {
@@ -76,7 +76,7 @@ export class UserDBBroker implements IUserBroker {
throw new Error("You can't have duplicates")
}
insertUser.finalize()
const user = await this.getUser(username, password)
@@ -139,7 +139,7 @@ export class UserDBBroker implements IUserBroker {
username: userToUpdate.username,
newPassword: passwordHash
})
stmt.finalize()
}
@@ -185,7 +185,7 @@ export class UserDBBroker implements IUserBroker {
username: username,
})
stmt.finalize()
if (!user) {
return null
@@ -213,7 +213,7 @@ export class UserDBBroker implements IUserBroker {
user_id: userID,
})
stmt.finalize()
if (!user) {
return null

View File

@@ -1,9 +1,9 @@
import type { Cookies } from "@sveltejs/kit";
import { SessionApp, type Session } from "./sessions";
import { UserApp, type User } from "./users";
import { JoseApp } from "$lib/utils/jtw-utils";
import { logger } from "$lib/utils/logger";
import { SESSION_COOKIE_NAME } from "$lib/utils/constants";
import { JoseApp } from "$lib/server/utils/jtw-utils";
import { logger } from "$lib/server/utils/logger";
import { SESSION_COOKIE_NAME } from "$lib/shared/constants";
export class AppData {

View File

@@ -1,4 +1,4 @@
import type { EndpointType } from "$lib/enums/endpoints";
import type { EndpointType } from "$lib/server/enums/endpoints";
export interface IEndpoint {

View File

@@ -35,6 +35,10 @@ export class SessionApp {
private static broker: ISessionBroker
private static initialized: boolean = false
public static get ready() {
return SessionApp.initialized
}
public static init(broker: ISessionBroker) {
if (SessionApp.initialized) {
// UGLY: make this Error more specific

View File

@@ -1,8 +1,8 @@
import { EndpointType } from "$lib/enums/endpoints"
import type { NginxProtocol } from "$lib/enums/protocols"
import { doesFileExists } from "$lib/utils/filesystem-utils"
import { isPortAvailable, validatePort } from "$lib/utils/ports-utils"
import type { init } from "../../hooks.server"
import { EndpointType } from "$lib/server/enums/endpoints"
import type { NginxProtocol } from "$lib/server/enums/protocols"
import { doesFileExist } from "$lib/server/utils/filesystem-utils"
import { isPortAvailable, validatePort } from "$lib/server/utils/ports-utils"
import type { init } from "../../../hooks.server"
import type { IEndpoint } from "./endpoints"
// TODO: inherit from a super class

View File

@@ -36,6 +36,10 @@ export class UserApp {
private static broker : IUserBroker
private static initialized: boolean = false
public static get ready() {
return UserApp.initialized
}
public static init(broker: IUserBroker) {

View File

@@ -1,12 +1,12 @@
import { AppData } from "$lib/classes/appdata";
import { SESSION_COOKIE_NAME } from "$lib/utils/constants";
import { logger } from "$lib/utils/logger";
import { AppData } from "$lib/server/classes/appdata";
import { logger } from "$lib/server/utils/logger";
import { APP_HOME, SESSION_COOKIE_NAME } from "$lib/shared/constants";
import { error, redirect, type Handle } from "@sveltejs/kit";
import { sequence } from "@sveltejs/kit/hooks";
const sessionConstructorHandle = (async ({ event, resolve }) => {
const data = await AppData.extractAppDataFromCookies(event.cookies)
// Prevents stray cookies from remaining
@@ -86,7 +86,7 @@ const appNonAuthHandle = (async ({ event, resolve }) => {
// It's for frontend, should redirect
if (event.locals.session) {
return redirect(302, "/app/program")
return redirect(302, APP_HOME)
}
return await resolve(event)
@@ -98,4 +98,7 @@ export const handles = sequence(
apiHandle,
appHandle,
appNonAuthHandle
)
)

View File

@@ -0,0 +1,9 @@
export const PKG = __PKG__
export const DB_PATH = "src/db/db.sqlite"
export const SERVER_PRIVATE_DIR = "src/private"
export const SERVER_PRIVATE_KEY_PATH = `${SERVER_PRIVATE_DIR}/key.pem`
export const SERVER_PUBLIC_KEY_PATH = `${SERVER_PRIVATE_DIR}/pub.pem`
export const DEBUG = import.meta.env.DEV
// NGINX
export const NGINX_BASE = "/etc/nginx"

View File

@@ -0,0 +1,99 @@
import type { OpenMode } from 'node:fs';
import * as Node from 'node:fs/promises';
export class FileHandle {
private path: string
constructor(
path: string
) {
this.path = path
}
public async text(encoding?: BufferEncoding) {
if (!encoding) {
encoding = "utf-8"
}
const fileContent = await Node.readFile(this.path, {encoding: encoding})
return fileContent
}
public async write(text: string, append?: boolean) {
if (!append) {
append = true
}
const flag : OpenMode = append ? "a+" : "w"
await Node.writeFile(this.path, text, {flag: flag})
}
}
/**
* Checks if the file exists
*
* @param path `string` path for the file
* @returns if the file is readable
*/
export async function doesFileExist(path: string): Promise<boolean> {
try {
await Node.access(path)
} catch {
return false
}
return true
}
export async function loadFile(path: string, create?: boolean): Promise<FileHandle> {
const DEFAULT_MODE = 0o600
// Safe to use
// worst case: create = false -> create = false
if (!create) {
create = false
}
let fd : Node.FileHandle | null = null
try {
fd = await Node.open(path, "r+", DEFAULT_MODE)
} catch {
}
// We have a FD, return it
if (fd) {
await fd.close()
return new FileHandle(path)
}
if (!create) {
// UGLY: make more specific
throw new Error("The required file does not exist")
}
// We do want this to throw without catching here
fd = await Node.open(path, "w", DEFAULT_MODE)
await fd.close()
return new FileHandle(path)
}

View File

View File

@@ -1,5 +1,5 @@
import * as jose from "jose";
import { doesFileExists, loadFile } from "./filesystem-utils";
import { doesFileExist, loadFile } from "./filesystem-utils";
import { SERVER_PRIVATE_KEY_PATH, SERVER_PUBLIC_KEY_PATH } from "./constants";
import { openSSLInit } from "./openssl-utils";
import { logger } from "./logger";
@@ -12,13 +12,17 @@ export class JoseApp {
private static privateKey: CryptoKey
private static publicKey: CryptoKey
public static get ready() {
return JoseApp.initialized
}
public static async init() {
JoseApp.assureNotInitialized()
if (
!await doesFileExists(SERVER_PRIVATE_KEY_PATH) ||
!await doesFileExists(SERVER_PUBLIC_KEY_PATH)
!await doesFileExist(SERVER_PRIVATE_KEY_PATH) ||
!await doesFileExist(SERVER_PUBLIC_KEY_PATH)
) {
await openSSLInit()
}

View File

@@ -0,0 +1,45 @@
// TODO: remove bun dependencies
import { logger } from "./logger"
import { shell } from "./shell-commands"
export async function reloadNginx() {
if (!await validateSchema()) {
// UGLY: make this a specific error
throw new Error("Something went wrong while validating")
}
// Start nginx, should be side-effect free
startNginx()
const output = await shell(`rc-service nginx reload`)
logger.debug(`rc-service reload output:\n${output.stdout}`, "NGINX - RELOAD")
}
export async function startNginx() {
if (!await validateSchema()) {
// UGLY: make this a specific error
throw new Error("Something went wrong while validating")
}
const output = await shell(`rc-service nginx start`)
}
export async function validateSchema() {
const output = await shell(`nginx -t 2>&1`)
logger.debug(`nginx -t output:\n${output.stdout}`, "NGINX - VALIDATE")
const successRegex = new RegExp("test is successful", "gm")
const result = successRegex.test(output.stdout)
return result
}

View File

@@ -1,6 +1,8 @@
import { $ } from "bun";
import { doesFileExists, loadFile } from "./filesystem-utils";
// TODO: remove bu dependencies
import { doesFileExist, loadFile, type FileHandle } from "./filesystem-utils";
import { SERVER_PRIVATE_KEY_PATH, SERVER_PUBLIC_KEY_PATH } from "./constants";
import { exec } from "node:child_process"
import { shell, type shellOutput } from "./shell-commands";
export async function openSSLInit() {
@@ -12,16 +14,16 @@ export async function openSSLInit() {
export async function openSSLCreatePrivateKey() {
// UGLY: may be refactored to output only the private key
const outputPromise = $`openssl ecparam -genkey -name secp521r1 -noout | openssl pkcs8 -topk8 -nocrypt`.text()
const outputPromise = shell(`openssl ecparam -genkey -name secp521r1 -noout | openssl pkcs8 -topk8 -nocrypt`)
// const outputPromise = $`openssl ecparam -genkey -name secp521r1 -noout | openssl pkcs8 -topk8 -nocrypt`.text()
const filePromise = loadFile(SERVER_PRIVATE_KEY_PATH, true)
const [output, file] = await Promise.all([
const [output, file] : [shellOutput, FileHandle]= await Promise.all([
outputPromise,
filePromise
])
await file.write(output)
await file.write(output.stdout)
}
@@ -29,12 +31,12 @@ export async function openSSLCreatePrivateKey() {
export async function openSSLCreatePublicKey() {
// UGLY: may be refactored to output only the private key
if (! await doesFileExists(SERVER_PRIVATE_KEY_PATH)) {
if (! await doesFileExist(SERVER_PRIVATE_KEY_PATH)) {
// UGLY: make more specific
throw new Error("You must generate the private key before attempting to generate the public one")
}
const outputPromise = $`openssl ec -in ${SERVER_PRIVATE_KEY_PATH} -pubout `.text()
const outputPromise = shell(`openssl ec -in ${SERVER_PRIVATE_KEY_PATH} -pubout `)
const filePromise = loadFile(SERVER_PUBLIC_KEY_PATH, true)
const [output, file] = await Promise.all([
@@ -42,7 +44,7 @@ export async function openSSLCreatePublicKey() {
filePromise
])
await file.write(output)
await file.write(output.stdout)
}

View File

@@ -1,4 +1,4 @@
import { $ } from "bun";
// TODO: remove bun dependecies
/**
* This methods runs `netstat -ltun`

View File

@@ -0,0 +1,9 @@
import { exec , spawn } from "node:child_process"
import { promisify } from "node:util"
export const shell = promisify(exec)
export type shellOutput = {
stdout: string,
stderr: string
}

View File

@@ -0,0 +1,12 @@
// API ROUTES
export const API_BASE = "/api"
export const PROTECTED_API_BASE = `${API_BASE}/program`
// APP ROUTES
export const APP_BASE = "/app"
export const PROTECTED_APP_BASE = `${APP_BASE}/program`
export const APP_HOME = `${PROTECTED_APP_BASE}/home`
// Cookies
export const SESSION_COOKIE_NAME = "session"

View File

@@ -1,22 +0,0 @@
export const PKG = __PKG__
export const DB_PATH = "src/db/db.sqlite"
export const SERVER_PRIVATE_DIR = "src/private"
export const SERVER_PRIVATE_KEY_PATH = `${SERVER_PRIVATE_DIR}/key.pem`
export const SERVER_PUBLIC_KEY_PATH = `${SERVER_PRIVATE_DIR}/pub.pem`
export const DEBUG = import.meta.env.DEV
// NGINX
export const NGINX_BASE = "/etc/nginx"
// API ROUTES
export const API_BASE = "/api"
export const PROTECTED_API_BASE = `${API_BASE}/program`
// APP ROUTES
export const APP_BASE = "/app"
export const PROTECTED_APP_BASE = `${APP_BASE}/program`
export const APP_HOME = `${PROTECTED_APP_BASE}/home`
// Cookies
export const SESSION_COOKIE_NAME = "session"

View File

@@ -1,29 +0,0 @@
export async function doesFileExists(path: string) {
const file = Bun.file(path)
return file.exists()
}
export async function loadFile(path: string, create?: boolean): Promise<Bun.BunFile> {
if (!create) {
create = false
}
if (await doesFileExists(path)) {
return Bun.file(path)
}
if (create) {
const file = Bun.file(path)
file.write("")
return file
}
// UGLY: make more specific
throw new Error("The required file does not exist")
}

View File

@@ -1,43 +0,0 @@
import { $ } from "bun";
export async function reloadNginx() {
if (!await validateSchema()) {
const output = await $`nginx -t 2>&1`
.nothrow()
.text()
// UGLY: make this a specific error
throw new Error(output)
}
// Start nginx, should be side-effect free
startNginx()
const output = await $`rc-service nginx reload`.text()
}
export async function startNginx() {
if (!await validateSchema()) {
const output = await $`nginx -t 2>&1`
.nothrow()
.text()
// UGLY: make this a specific error
throw new Error(output)
}
const output = await $`rc-service nginx start`.text()
}
export async function validateSchema() {
const output = await $`nginx -t 2>&1`.nothrow().text()
console.log(output)
const successRegex = new RegExp("test is successful", "gm")
const result = successRegex.test(output)
return result
}

View File

@@ -5,6 +5,12 @@
<h1>SSL-Sniffer</h1>
<p>A Sniffer for all your needs</p>
<nav data-sveltekit-reload>
<a href="/app/login">Login</a>
or
<a href="/app/register">Register</a>
</nav>
<style>

View File

@@ -1,9 +1,9 @@
import { error, json, text, type Cookies } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import { User, UserApp } from '$lib/classes/users';
import { SessionApp } from '$lib/classes/sessions';
import { AppData } from '$lib/classes/appdata';
import { logger } from '$lib/utils/logger';
import { User, UserApp } from '$lib/server/classes/users';
import { SessionApp } from '$lib/server/classes/sessions';
import { AppData } from '$lib/server/classes/appdata';
import { logger } from '$lib/server/utils/logger';
/***********************************************************
*

View File

@@ -1,10 +1,10 @@
import { error, json, text, type Cookies } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import { User, UserApp } from '$lib/classes/users';
import { SessionApp } from '$lib/classes/sessions';
import { AppData } from '$lib/classes/appdata';
import { logger } from '$lib/utils/logger';
import { SESSION_COOKIE_NAME } from '$lib/utils/constants';
import { User, UserApp } from '$lib/server/classes/users';
import { SessionApp } from '$lib/server/classes/sessions';
import { AppData } from '$lib/server/classes/appdata';
import { logger } from '$lib/server/utils/logger';
import { SESSION_COOKIE_NAME } from '$lib/server/utils/constants';
/***********************************************************
*

View File

@@ -1,9 +1,9 @@
import { error, json, text, type Cookies } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import { UserApp, User } from '$lib/classes/users';
import { SessionApp, Session } from '$lib/classes/sessions';
import { AppData } from '$lib/classes/appdata';
import { logger } from '$lib/utils/logger';
import { UserApp, User } from '$lib/server/classes/users';
import { SessionApp, Session } from '$lib/server/classes/sessions';
import { AppData } from '$lib/server/classes/appdata';
import { logger } from '$lib/server/utils/logger';
/***********************************************************
*

View File

@@ -1,4 +1,4 @@
import { PKG } from '$lib';
import { PKG } from '$lib/server';
import { json } from '@sveltejs/kit';
export function GET() {

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { goto } from "$app/navigation";
import { APP_HOME } from "$lib/utils/constants";
import { APP_HOME } from "$lib/shared/constants";
import { redirect } from "@sveltejs/kit";
@@ -34,7 +34,7 @@
return
}
goto(APP_HOME)
await goto(APP_HOME)
}

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { goto } from "$app/navigation";
import { APP_HOME } from "$lib/utils/constants";
import { APP_HOME } from "$lib/shared/constants";
import { redirect } from "@sveltejs/kit";