V 0.1.2 Ended writing backend utils
This commit is contained in:
parent
3eda2cf0a1
commit
67c8e9c31d
@ -8,6 +8,11 @@ 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';
|
||||
import { EndpointManagerApp } from '$lib/server/classes/endpoints/endpoint-manager';
|
||||
import { SSLTerminationEndpointApp } from '$lib/server/classes/endpoints/ssl-termination-endpoint';
|
||||
import { SSLTerminationFSBroker } from '$lib/server/broker-utils/FileSystem/SSLTerminations';
|
||||
import { ManualEndpointApp } from '$lib/server/classes/endpoints/manual-endpoint';
|
||||
import { ManualFSBroker } from '$lib/server/broker-utils/FileSystem/Manual';
|
||||
|
||||
export const init: ServerInit = async () => {
|
||||
|
||||
@ -34,6 +39,23 @@ export const init: ServerInit = async () => {
|
||||
await JoseApp.init()
|
||||
}
|
||||
|
||||
if(!EndpointManagerApp.ready) {
|
||||
// This is async
|
||||
await EndpointManagerApp.init()
|
||||
}
|
||||
|
||||
if (!SSLTerminationEndpointApp.ready) {
|
||||
SSLTerminationEndpointApp.init(
|
||||
new SSLTerminationFSBroker()
|
||||
)
|
||||
}
|
||||
|
||||
if (!ManualEndpointApp.ready) {
|
||||
ManualEndpointApp.init(
|
||||
new ManualFSBroker()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
logger.debug("Init run successfully", "App Init")
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import type { FSHeader, IEndpointFS } from "$lib/server/broker-utils/FileSystem/endpoints/endpoints"
|
||||
import { NGINX_ACTIVE, NGINX_BASE, NGINX_INACTIVE, NGINX_TRACKED } from "$lib/server/utils/constants"
|
||||
import { doesFileExist, isDir, loadFile } from "$lib/server/utils/filesystem-utils"
|
||||
import { doesFileExist, isDir, listFiles, loadFile } from "$lib/server/utils/filesystem-utils"
|
||||
import { watch, type FSWatcher } from "node:fs"
|
||||
import { parseConf } from "./utils"
|
||||
import { logger } from "$lib/server/utils/logger"
|
||||
@ -29,10 +29,44 @@ export class EndpointBrokerManagerFS {
|
||||
// UGLY: be specific
|
||||
throw new Error("Broker already initialized")
|
||||
}
|
||||
// TODO: Read all files
|
||||
|
||||
const configurations = (await listFiles(NGINX_TRACKED, true)).filter( async (path) => {
|
||||
if (await isDir(path)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// TODO: QUICK parse them
|
||||
parseConf()
|
||||
if (!path.endsWith(".conf")) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
for (const confPath of configurations) {
|
||||
const file = await loadFile(confPath)
|
||||
await file.lock()
|
||||
|
||||
const conf = await file.text()
|
||||
const fileStats = await file.getStats()
|
||||
|
||||
const fsHeader: FSHeader = {
|
||||
name: confPath.split("/").pop()!,
|
||||
stats: fileStats,
|
||||
path: confPath,
|
||||
hash: await file.hash()
|
||||
}
|
||||
|
||||
await file.release()
|
||||
const endpoint = await parseConf(fsHeader, conf)
|
||||
|
||||
const relativePath = confPath.replace(NGINX_TRACKED, "")
|
||||
EndpointBrokerManagerFS.endpoints.set(
|
||||
relativePath,
|
||||
endpoint
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
|
||||
// TODO: Initialize a file watcher
|
||||
EndpointBrokerManagerFS.watcher = EndpointBrokerManagerFS.watchNginxDirectory()
|
||||
@ -72,14 +106,24 @@ export class EndpointBrokerManagerFS {
|
||||
|
||||
const file = await loadFile(REAL_PATH)
|
||||
await file.delete()
|
||||
const endpoint = EndpointBrokerManagerFS.endpoints.get(
|
||||
path
|
||||
)
|
||||
EndpointBrokerManagerFS.endpoints.delete(
|
||||
path
|
||||
)
|
||||
|
||||
return endpoint
|
||||
|
||||
}
|
||||
|
||||
public static async changeEndpoint(path: string, newEndpoint: IEndpointFS) {
|
||||
|
||||
if (newEndpoint.type === EndpointType.MANUAL) {
|
||||
// UGLY: be specific
|
||||
throw new Error("Change of Manual endpoint is not supported yet")
|
||||
}
|
||||
|
||||
validatePath(path)
|
||||
|
||||
const REAL_PATH = `${NGINX_TRACKED}/${path}`
|
||||
@ -305,7 +349,7 @@ export class EndpointBrokerManagerFS {
|
||||
const fsHeader: FSHeader = {
|
||||
name: filename!.split("/").pop()!,
|
||||
stats: stats,
|
||||
path: RELATIVE_PATH,
|
||||
path: FULL_PATH,
|
||||
hash: hash
|
||||
}
|
||||
|
||||
48
src/lib/server/broker-utils/FileSystem/Manual.ts
Normal file
48
src/lib/server/broker-utils/FileSystem/Manual.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import type { IManualBroker, Manual } from "$lib/server/classes/endpoints/manual-endpoint";
|
||||
import { EndpointType } from "$lib/server/enums/endpoints";
|
||||
import { EndpointBrokerManagerFS } from "./Endpoint-Manager";
|
||||
import type { ManualFS } from "./endpoints/manual-fs";
|
||||
|
||||
export class ManualFSBroker implements IManualBroker {
|
||||
public async init(): Promise<void> {
|
||||
// Do nothing?
|
||||
}
|
||||
public async getManualByPath(path: string): Promise<Manual| null> {
|
||||
const endpoint = EndpointBrokerManagerFS.getEndpointByPath(path)
|
||||
|
||||
if (!endpoint) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (endpoint.type !== EndpointType.MANUAL) {
|
||||
// UGLY: be specific
|
||||
throw new Error("This is not a Manual Endpoint")
|
||||
}
|
||||
|
||||
return endpoint.toIEndpoint() as Manual
|
||||
}
|
||||
|
||||
public async getAllManuals(): Promise<Manual[]> {
|
||||
const endpoints = (await EndpointBrokerManagerFS.getAll()).filter(async (endpoint) => {
|
||||
if (endpoint.type !== EndpointType.MANUAL) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}) as ManualFS[]
|
||||
|
||||
return endpoints.map( (endpoint) => {
|
||||
return endpoint.toIEndpoint() as Manual
|
||||
})
|
||||
}
|
||||
|
||||
public async activateEndpointByPath(path: string): Promise<boolean> {
|
||||
return await EndpointBrokerManagerFS.activateEndpoint(path)
|
||||
}
|
||||
|
||||
public async deactivateEndpointByPath(path: string): Promise<boolean> {
|
||||
return await EndpointBrokerManagerFS.deactivateEndpoint(path)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -1,57 +1,139 @@
|
||||
import { type ISSLTerminationBroker, type SSLTerminationChanges } from "$lib/server/classes/endpoints/ssl-termination-endpoint";
|
||||
import type { NginxProtocol } from "$lib/server/enums/protocols";
|
||||
import type { ISSLTerminationBroker, SSLTermination, SSLTerminationChanges } from "$lib/server/classes/endpoints/ssl-termination-endpoint"
|
||||
import { EndpointType } from "$lib/server/enums/endpoints"
|
||||
import type { NginxProtocol } from "$lib/server/enums/protocols"
|
||||
import { isPortAvailable, validatePort } from "$lib/server/utils/ports-utils"
|
||||
import { validatePath } from "$lib/shared/utils/path-utils"
|
||||
import { EndpointBrokerManagerFS } from "./Endpoint-Manager"
|
||||
import { SSLTerminationFS } from "./endpoints/ssltermination-fs"
|
||||
|
||||
export class SSLTerminationBroker implements ISSLTerminationBroker {
|
||||
|
||||
private static initialized = false
|
||||
export class SSLTerminationFSBroker implements ISSLTerminationBroker {
|
||||
|
||||
async init(): Promise<void> {
|
||||
|
||||
if (SSLTerminationBroker.initialized) {
|
||||
// UGLY: more specific
|
||||
throw new Error("SSLTerminationBroker was already initialized")
|
||||
}
|
||||
|
||||
public async init(): Promise<void> {
|
||||
// Do nothing?
|
||||
}
|
||||
|
||||
|
||||
async createSSLTerminationSimple(
|
||||
name: string,
|
||||
servicePort: number,
|
||||
serviceEndpoint: string,
|
||||
certificateURI: string,
|
||||
privateKeyURI: string
|
||||
): Promise<SSLTermination> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
|
||||
async createSSLTerminationComplete(
|
||||
public async createSSLTermination(
|
||||
name: string,
|
||||
sslPort: number,
|
||||
clearPort: number,
|
||||
servicePort: number,
|
||||
serviceEndpoint: string,
|
||||
protocol: NginxProtocol,
|
||||
certificateURI: string,
|
||||
privateKeyURI: string
|
||||
): Promise<SSLTermination> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
async getSSLTerminationByPath(name: string): Promise<SSLTermination | null> {
|
||||
throw new Error("Method not implemented.");
|
||||
|
||||
if (
|
||||
!isPortAvailable(sslPort) ||
|
||||
!isPortAvailable(clearPort)
|
||||
) {
|
||||
// UGLY be specific
|
||||
throw new Error("some ports were already in use")
|
||||
}
|
||||
|
||||
validatePort(servicePort)
|
||||
|
||||
const newEndpoint = new SSLTerminationFS(
|
||||
name,
|
||||
null,
|
||||
sslPort,
|
||||
clearPort,
|
||||
servicePort,
|
||||
serviceEndpoint,
|
||||
protocol,
|
||||
certificateURI,
|
||||
privateKeyURI
|
||||
)
|
||||
|
||||
await EndpointBrokerManagerFS.createEndpoint(newEndpoint)
|
||||
return (await this.getSSLTerminationFSByPath(newEndpoint.path))?.toIEndpoint() as SSLTermination
|
||||
}
|
||||
|
||||
async modifySSLTerminationByPath(name: string, changes: SSLTerminationChanges): Promise<SSLTermination> {
|
||||
throw new Error("Method not implemented.");
|
||||
|
||||
public async activateEndpointByPath(path: string): Promise<boolean> {
|
||||
return await EndpointBrokerManagerFS.activateEndpoint(path)
|
||||
}
|
||||
|
||||
async deleteSSLTerminationByPath(name: string): Promise<SSLTermination | null> {
|
||||
throw new Error("Method not implemented.");
|
||||
|
||||
public async deactivateEndpointByPath(path: string): Promise<boolean> {
|
||||
return await EndpointBrokerManagerFS.deactivateEndpoint(path)
|
||||
}
|
||||
|
||||
async getAllSSLTerminations(): Promise<SSLTermination[]> {
|
||||
throw new Error("Method not implemented.");
|
||||
|
||||
public async getSSLTerminationByPath(path: string): Promise<SSLTermination | null> {
|
||||
const endpoint = await this.getSSLTerminationFSByPath(path)
|
||||
return endpoint?.toIEndpoint() as SSLTermination
|
||||
}
|
||||
|
||||
|
||||
public async modifySSLTerminationByPath(path: string, changes: SSLTerminationChanges): Promise<SSLTermination> {
|
||||
const oldEndpoint = await this.getSSLTerminationFSByPath(path)
|
||||
|
||||
if (!oldEndpoint) {
|
||||
// UGLY: be specific
|
||||
throw new Error("There was no old endpoint at this path")
|
||||
}
|
||||
|
||||
const newEndpoint = new SSLTerminationFS(
|
||||
changes.name ?? oldEndpoint.name,
|
||||
oldEndpoint.stats,
|
||||
changes.sslPort ?? oldEndpoint.sslPort,
|
||||
changes.clearPort ?? oldEndpoint.clearPort,
|
||||
changes.servicePort ?? oldEndpoint.servicePort,
|
||||
changes.serviceEndpoint ?? oldEndpoint.serviceEndpoint,
|
||||
changes.protocol ?? oldEndpoint.protocol,
|
||||
changes.certificateURI ?? oldEndpoint.certificateURI,
|
||||
changes.privateKeyURI ?? oldEndpoint.privateKeyURI
|
||||
)
|
||||
|
||||
EndpointBrokerManagerFS.changeEndpoint(path, newEndpoint)
|
||||
|
||||
return newEndpoint.toIEndpoint() as SSLTermination
|
||||
}
|
||||
|
||||
|
||||
public async deleteSSLTerminationByPath(path: string): Promise<SSLTermination | null> {
|
||||
const candidate = await EndpointBrokerManagerFS.deleteEndpoint(path)
|
||||
|
||||
if (!candidate) {
|
||||
return null
|
||||
}
|
||||
|
||||
return candidate as SSLTerminationFS
|
||||
}
|
||||
|
||||
// Technically expensive to implement
|
||||
public async getAllSSLTerminations(): Promise<SSLTermination[]> {
|
||||
|
||||
const endpoints = (await EndpointBrokerManagerFS.getAll()).filter((endpoint) => {
|
||||
if (endpoint.type !== EndpointType.SSL_TERMINATION) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}) as SSLTerminationFS[]
|
||||
|
||||
return endpoints.map((endpoint) => {
|
||||
return endpoint.toIEndpoint() as SSLTermination
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
private async getSSLTerminationFSByPath(path: string): Promise<SSLTerminationFS | null> {
|
||||
const endpoint = EndpointBrokerManagerFS.getEndpointByPath(path)
|
||||
|
||||
if (!endpoint) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (endpoint.type !== EndpointType.SSL_TERMINATION) {
|
||||
// UGLY: be specific
|
||||
throw new Error("This is not an SSLEndpoint")
|
||||
}
|
||||
|
||||
return endpoint as SSLTerminationFS
|
||||
}
|
||||
|
||||
}
|
||||
@ -16,7 +16,7 @@ export interface IEndpointFS {
|
||||
* whether the file has been actually
|
||||
* parsed by nginx during last reload
|
||||
*/
|
||||
stats: FileStats
|
||||
stats: FileStats | null
|
||||
/** File path */
|
||||
path: string
|
||||
/** Hash of the file */
|
||||
|
||||
@ -6,7 +6,8 @@ import type { FSHeader, IEndpointFS } from "./endpoints"
|
||||
import { createHeader, parseDefaultHeader, parseGenericHeader } from "../utils"
|
||||
import { hashUtil } from "$lib/server/utils/filesystem-utils"
|
||||
import type { IEndpoint } from "$lib/server/classes/endpoints/endpoints-interfaces"
|
||||
import { SSLTermination } from "$lib/server/classes/endpoints/ssl-termination-endpoint"
|
||||
import { SSLTermination, type ISSLTerminationBroker, type SSLTerminationChanges } from "$lib/server/classes/endpoints/ssl-termination-endpoint"
|
||||
import { EndpointBrokerManagerFS } from "../Endpoint-Manager"
|
||||
|
||||
// TODO: add broker implementation
|
||||
|
||||
@ -21,11 +22,15 @@ export class SSLTerminationFS implements IEndpointFS {
|
||||
|
||||
|
||||
public name: string
|
||||
public stats: Stats
|
||||
public stats: Stats|null
|
||||
public get path() {
|
||||
return `${this.protocol}/name.conf`
|
||||
}
|
||||
public hash: string
|
||||
public get hash() {
|
||||
return hashUtil(
|
||||
this.toConf()
|
||||
)
|
||||
}
|
||||
public sslPort: number
|
||||
public clearPort: number
|
||||
public servicePort: number
|
||||
@ -38,8 +43,7 @@ export class SSLTerminationFS implements IEndpointFS {
|
||||
|
||||
constructor(
|
||||
name: string,
|
||||
stats: Stats,
|
||||
hash: string,
|
||||
stats: Stats|null,
|
||||
sslPort: number,
|
||||
clearPort: number,
|
||||
servicePort: number,
|
||||
@ -51,7 +55,6 @@ export class SSLTerminationFS implements IEndpointFS {
|
||||
|
||||
this.name = name
|
||||
this.stats = stats
|
||||
this.hash = hash
|
||||
this.sslPort = sslPort
|
||||
this.clearPort = clearPort
|
||||
this.servicePort = servicePort
|
||||
@ -121,7 +124,7 @@ export class SSLTerminationFS implements IEndpointFS {
|
||||
|
||||
const sslPort = Number.parseInt(
|
||||
keyValue.get(
|
||||
"SSL_PORT"
|
||||
"SSL_PORT"
|
||||
) ?? ""
|
||||
)
|
||||
|
||||
@ -129,7 +132,7 @@ export class SSLTerminationFS implements IEndpointFS {
|
||||
|
||||
const clearPort = Number.parseInt(
|
||||
keyValue.get(
|
||||
"CLEAR_PORT"
|
||||
"CLEAR_PORT"
|
||||
) ?? ""
|
||||
)
|
||||
|
||||
@ -137,7 +140,7 @@ export class SSLTerminationFS implements IEndpointFS {
|
||||
|
||||
const servicePort = Number.parseInt(
|
||||
keyValue.get(
|
||||
"SERVICE_PORT"
|
||||
"SERVICE_PORT"
|
||||
) ?? ""
|
||||
)
|
||||
|
||||
@ -164,7 +167,6 @@ export class SSLTerminationFS implements IEndpointFS {
|
||||
return new SSLTerminationFS(
|
||||
name,
|
||||
fsHeader.stats,
|
||||
fsHeader.hash,
|
||||
sslPort,
|
||||
clearPort,
|
||||
servicePort,
|
||||
@ -174,7 +176,7 @@ export class SSLTerminationFS implements IEndpointFS {
|
||||
privateKeyURI
|
||||
)
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -288,4 +290,5 @@ export class SSLTerminationFS implements IEndpointFS {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { EndpointBrokerManagerFS } from "$lib/server/broker-utils/FileSystem/Endpoint"
|
||||
import { EndpointBrokerManagerFS } from "$lib/server/broker-utils/FileSystem/Endpoint-Manager"
|
||||
import type { IEndpoint } from "./endpoints-interfaces"
|
||||
|
||||
|
||||
@ -15,13 +15,8 @@ export class EndpointManagerApp {
|
||||
return EndpointManagerApp.initialized
|
||||
}
|
||||
|
||||
public static init() {
|
||||
// TODO: Read all files
|
||||
|
||||
// TODO: QUICK parse them
|
||||
|
||||
// TODO: Initialize a file watcher
|
||||
|
||||
public static async init() {
|
||||
await EndpointBrokerManagerFS.init()
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ export interface IManualBroker {
|
||||
|
||||
init(): Promise<void>
|
||||
|
||||
getManualByPath(path: string): Promise<Manual>
|
||||
getManualByPath(path: string): Promise<Manual| null>
|
||||
|
||||
getAllManuals(): Promise<Manual[]>
|
||||
|
||||
|
||||
@ -14,22 +14,17 @@ export interface ISSLTerminationBroker {
|
||||
// TODO: in the next version support
|
||||
// TODO: creation of endpoints
|
||||
// TODO: according to path
|
||||
// Creation should throw if something goes wrong
|
||||
// with reasons why
|
||||
createSSLTerminationSimple(
|
||||
name: string,
|
||||
servicePort: number,
|
||||
serviceEndpoint: string,
|
||||
certificateURI: string,
|
||||
privateKeyURI: string
|
||||
): Promise<SSLTermination>
|
||||
|
||||
createSSLTerminationComplete(
|
||||
// NOTES: it's useless to generate ports backend
|
||||
// NOTES: generate them frontend and validate backend
|
||||
|
||||
createSSLTermination(
|
||||
name: string,
|
||||
sslPort: number,
|
||||
clearPort: number,
|
||||
servicePort: number,
|
||||
serviceEndpoint: string,
|
||||
protocol: NginxProtocol,
|
||||
certificateURI: string,
|
||||
privateKeyURI: string
|
||||
): Promise<SSLTermination>
|
||||
@ -150,47 +145,26 @@ export class SSLTerminationEndpointApp {
|
||||
SSLTerminationEndpointApp.initialized = true
|
||||
}
|
||||
|
||||
|
||||
// Creation should throw if something goes wrong
|
||||
// with reasons why
|
||||
public static async createSSLTerminationSimple(
|
||||
name: string,
|
||||
servicePort: number,
|
||||
serviceEndpoint: string,
|
||||
certificateURI: string,
|
||||
privateKeyURI: string
|
||||
): Promise<SSLTermination> {
|
||||
|
||||
SSLTerminationEndpointApp.assureInitialized()
|
||||
|
||||
return await this.broker.createSSLTerminationSimple(
|
||||
name,
|
||||
servicePort,
|
||||
serviceEndpoint,
|
||||
certificateURI,
|
||||
privateKeyURI
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
public static async createSSLTerminationComplete(
|
||||
public static async createSSLTermination(
|
||||
name: string,
|
||||
sslPort: number,
|
||||
clearPort: number,
|
||||
servicePort: number,
|
||||
serviceEndpoint: string,
|
||||
protocol: NginxProtocol,
|
||||
certificateURI: string,
|
||||
privateKeyURI: string
|
||||
): Promise<SSLTermination> {
|
||||
|
||||
SSLTerminationEndpointApp.assureInitialized()
|
||||
|
||||
return await this.broker.createSSLTerminationComplete(
|
||||
return await this.broker.createSSLTermination(
|
||||
name,
|
||||
sslPort,
|
||||
clearPort,
|
||||
servicePort,
|
||||
serviceEndpoint,
|
||||
protocol,
|
||||
certificateURI,
|
||||
privateKeyURI
|
||||
)
|
||||
|
||||
@ -157,3 +157,18 @@ export function hashUtil(data: BinaryLike) {
|
||||
).digest('base64')
|
||||
return hash
|
||||
}
|
||||
|
||||
export async function listFiles(path: string, recursive?: boolean): Promise<string[]> {
|
||||
|
||||
if (!recursive) {
|
||||
recursive = false
|
||||
}
|
||||
|
||||
if (!await isDir(path)) {
|
||||
// UGLY: be specific
|
||||
throw new Error("This is not a directory")
|
||||
}
|
||||
|
||||
return await Node.readdir(path, {recursive: recursive})
|
||||
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
// TODO: remove bun dependecies
|
||||
|
||||
import { shell } from "./shell-commands"
|
||||
|
||||
/**
|
||||
* This methods runs `netstat -ltun`
|
||||
@ -14,8 +15,8 @@
|
||||
export async function portScan(): Promise<Set<number>> {
|
||||
|
||||
const portRegex = new RegExp("(?:\:)(?<port_number>[0-9]+)", "gm")
|
||||
const netstatOutput : string = await $`netstat -ltun`.text()
|
||||
const ports = netstatOutput.matchAll(portRegex)
|
||||
const netstatOutput = await shell(`netstat -ltun`)
|
||||
const ports = netstatOutput.stdout.matchAll(portRegex)
|
||||
|
||||
const portArray : Set<number>= new Set()
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user