|
|
@ -9,52 +9,26 @@ import { |
|
|
|
import { JSONFilePreset } from 'lowdb/node'; |
|
|
|
|
|
|
|
import type { Low } from 'lowdb'; |
|
|
|
import type { User } from './repositories/user'; |
|
|
|
import { UserRepository, type User } from './repositories/user'; |
|
|
|
import type { Database } from './repositories/database'; |
|
|
|
import { migrationRunner } from './migrations'; |
|
|
|
import type { Client, NewClient, OneTimeLink } from './repositories/client'; |
|
|
|
import { |
|
|
|
ClientRepository, |
|
|
|
type Client, |
|
|
|
type NewClient, |
|
|
|
type OneTimeLink, |
|
|
|
} from './repositories/client'; |
|
|
|
import { SystemRepository } from './repositories/system'; |
|
|
|
|
|
|
|
const DEBUG = debug('LowDB'); |
|
|
|
|
|
|
|
export default class LowDB extends DatabaseProvider { |
|
|
|
#db!: Low<Database>; |
|
|
|
#connected = false; |
|
|
|
|
|
|
|
private async __init() { |
|
|
|
const dbFilePath = '/etc/wireguard/db.json'; |
|
|
|
this.#db = await JSONFilePreset(dbFilePath, DEFAULT_DATABASE); |
|
|
|
export class LowDBSystem extends SystemRepository { |
|
|
|
#db: Low<Database>; |
|
|
|
constructor(db: Low<Database>) { |
|
|
|
super(); |
|
|
|
this.#db = db; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @throws |
|
|
|
*/ |
|
|
|
async connect() { |
|
|
|
if (this.#connected) { |
|
|
|
return; |
|
|
|
} |
|
|
|
try { |
|
|
|
await this.__init(); |
|
|
|
DEBUG('Running Migrations'); |
|
|
|
await migrationRunner(this.#db); |
|
|
|
DEBUG('Migrations ran successfully'); |
|
|
|
} catch (e) { |
|
|
|
DEBUG(e); |
|
|
|
throw new Error('Failed to initialize Database'); |
|
|
|
} |
|
|
|
this.#connected = true; |
|
|
|
DEBUG('Connected successfully'); |
|
|
|
} |
|
|
|
|
|
|
|
get connected() { |
|
|
|
return this.#connected; |
|
|
|
} |
|
|
|
|
|
|
|
async disconnect() { |
|
|
|
this.#connected = false; |
|
|
|
DEBUG('Disconnected successfully'); |
|
|
|
} |
|
|
|
|
|
|
|
async getSystem() { |
|
|
|
async get() { |
|
|
|
DEBUG('Get System'); |
|
|
|
const system = this.#db.data.system; |
|
|
|
// system is only null if migration failed
|
|
|
@ -63,18 +37,25 @@ export default class LowDB extends DatabaseProvider { |
|
|
|
} |
|
|
|
return system; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
export class LowDBUser extends UserRepository { |
|
|
|
#db: Low<Database>; |
|
|
|
constructor(db: Low<Database>) { |
|
|
|
super(); |
|
|
|
this.#db = db; |
|
|
|
} |
|
|
|
// TODO: return copy to avoid mutation (everywhere)
|
|
|
|
async getUsers() { |
|
|
|
async findAll() { |
|
|
|
return this.#db.data.users; |
|
|
|
} |
|
|
|
|
|
|
|
async getUser(id: string) { |
|
|
|
async findById(id: string) { |
|
|
|
DEBUG('Get User'); |
|
|
|
return this.#db.data.users.find((user) => user.id === id); |
|
|
|
} |
|
|
|
|
|
|
|
async createUser(username: string, password: string) { |
|
|
|
async create(username: string, password: string) { |
|
|
|
DEBUG('Create User'); |
|
|
|
|
|
|
|
const isUserExist = this.#db.data.users.find( |
|
|
@ -106,9 +87,9 @@ export default class LowDB extends DatabaseProvider { |
|
|
|
await this.#db.update((data) => data.users.push(newUser)); |
|
|
|
} |
|
|
|
|
|
|
|
async updateUser(user: User) { |
|
|
|
async update(user: User) { |
|
|
|
// TODO: avoid mutation, prefer .update, updatedAt
|
|
|
|
let oldUser = await this.getUser(user.id); |
|
|
|
let oldUser = await this.findById(user.id); |
|
|
|
if (oldUser) { |
|
|
|
DEBUG('Update User'); |
|
|
|
oldUser = user; |
|
|
@ -116,25 +97,32 @@ export default class LowDB extends DatabaseProvider { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
async deleteUser(id: string) { |
|
|
|
async delete(id: string) { |
|
|
|
DEBUG('Delete User'); |
|
|
|
const idx = this.#db.data.users.findIndex((user) => user.id === id); |
|
|
|
if (idx !== -1) { |
|
|
|
await this.#db.update((data) => data.users.splice(idx, 1)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
async getClients() { |
|
|
|
export class LowDBClient extends ClientRepository { |
|
|
|
#db: Low<Database>; |
|
|
|
constructor(db: Low<Database>) { |
|
|
|
super(); |
|
|
|
this.#db = db; |
|
|
|
} |
|
|
|
async findAll() { |
|
|
|
DEBUG('GET Clients'); |
|
|
|
return this.#db.data.clients; |
|
|
|
} |
|
|
|
|
|
|
|
async getClient(id: string) { |
|
|
|
async findById(id: string) { |
|
|
|
DEBUG('Get Client'); |
|
|
|
return this.#db.data.clients[id]; |
|
|
|
} |
|
|
|
|
|
|
|
async createClient(client: NewClient) { |
|
|
|
async create(client: NewClient) { |
|
|
|
DEBUG('Create Client'); |
|
|
|
const now = new Date().toISOString(); |
|
|
|
const newClient: Client = { ...client, createdAt: now, updatedAt: now }; |
|
|
@ -143,7 +131,7 @@ export default class LowDB extends DatabaseProvider { |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
async deleteClient(id: string) { |
|
|
|
async delete(id: string) { |
|
|
|
DEBUG('Delete Client'); |
|
|
|
await this.#db.update((data) => { |
|
|
|
// TODO: find something better than delete
|
|
|
@ -152,7 +140,7 @@ export default class LowDB extends DatabaseProvider { |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
async toggleClient(id: string, enable: boolean) { |
|
|
|
async toggle(id: string, enable: boolean) { |
|
|
|
DEBUG('Toggle Client'); |
|
|
|
await this.#db.update((data) => { |
|
|
|
if (data.clients[id]) { |
|
|
@ -161,7 +149,7 @@ export default class LowDB extends DatabaseProvider { |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
async updateClientName(id: string, name: string) { |
|
|
|
async updateName(id: string, name: string) { |
|
|
|
DEBUG('Update Client Name'); |
|
|
|
await this.#db.update((data) => { |
|
|
|
if (data.clients[id]) { |
|
|
@ -170,7 +158,7 @@ export default class LowDB extends DatabaseProvider { |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
async updateClientAddress4(id: string, address4: string) { |
|
|
|
async updateAddress4(id: string, address4: string) { |
|
|
|
DEBUG('Update Client Address4'); |
|
|
|
await this.#db.update((data) => { |
|
|
|
if (data.clients[id]) { |
|
|
@ -179,7 +167,7 @@ export default class LowDB extends DatabaseProvider { |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
async updateClientExpirationDate(id: string, expirationDate: string | null) { |
|
|
|
async updateExpirationDate(id: string, expirationDate: string | null) { |
|
|
|
DEBUG('Update Client Expiration Date'); |
|
|
|
await this.#db.update((data) => { |
|
|
|
if (data.clients[id]) { |
|
|
@ -211,3 +199,49 @@ export default class LowDB extends DatabaseProvider { |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
export default class LowDB extends DatabaseProvider { |
|
|
|
#db!: Low<Database>; |
|
|
|
#connected = false; |
|
|
|
|
|
|
|
system!: LowDBSystem; |
|
|
|
user!: LowDBUser; |
|
|
|
client!: LowDBClient; |
|
|
|
|
|
|
|
/** |
|
|
|
* @throws |
|
|
|
*/ |
|
|
|
async connect() { |
|
|
|
if (this.#connected) { |
|
|
|
return; |
|
|
|
} |
|
|
|
try { |
|
|
|
DEBUG('Connecting'); |
|
|
|
this.#db = await JSONFilePreset( |
|
|
|
'/etc/wireguard/db.json', |
|
|
|
DEFAULT_DATABASE |
|
|
|
); |
|
|
|
|
|
|
|
DEBUG('Running Migrations'); |
|
|
|
await migrationRunner(this.#db); |
|
|
|
DEBUG('Migrations ran successfully'); |
|
|
|
} catch (e) { |
|
|
|
DEBUG(e); |
|
|
|
throw new Error('Failed to initialize Database'); |
|
|
|
} |
|
|
|
this.system = new LowDBSystem(this.#db); |
|
|
|
this.user = new LowDBUser(this.#db); |
|
|
|
this.client = new LowDBClient(this.#db); |
|
|
|
this.#connected = true; |
|
|
|
DEBUG('Connected successfully'); |
|
|
|
} |
|
|
|
|
|
|
|
get connected() { |
|
|
|
return this.#connected; |
|
|
|
} |
|
|
|
|
|
|
|
async disconnect() { |
|
|
|
this.#connected = false; |
|
|
|
DEBUG('Disconnected successfully'); |
|
|
|
} |
|
|
|
} |
|
|
|