mirror of https://github.com/wg-easy/wg-easy
Browse Source
* add migrations * improve migration runner * improve migration runner * document what each migration doespull/1648/head
committed by
Bernd Storath
11 changed files with 152 additions and 191 deletions
@ -1,4 +1,5 @@ |
|||
export default defineEventHandler((event) => { |
|||
export default defineEventHandler(async (event) => { |
|||
setHeader(event, 'Content-Type', 'application/json'); |
|||
return Database.getLang(); |
|||
const system = await Database.getSystem(); |
|||
return system.lang; |
|||
}); |
|||
|
@ -1,95 +0,0 @@ |
|||
import crypto from 'node:crypto'; |
|||
import debug from 'debug'; |
|||
|
|||
import { |
|||
DatabaseProvider, |
|||
DatabaseError, |
|||
DEFAULT_DATABASE, |
|||
} from './repositories/database'; |
|||
import { DEFAULT_SYSTEM } from './repositories/system'; |
|||
|
|||
import type { User } from './repositories/user'; |
|||
|
|||
const DEBUG = debug('InMemoryDB'); |
|||
|
|||
export default class InMemory extends DatabaseProvider { |
|||
#data = DEFAULT_DATABASE; |
|||
|
|||
async connect() { |
|||
this.#data.system = DEFAULT_SYSTEM; |
|||
DEBUG('Connected successfully'); |
|||
} |
|||
|
|||
async disconnect() { |
|||
this.#data = { system: null, users: [] }; |
|||
DEBUG('Disconnected successfully'); |
|||
} |
|||
|
|||
async getSystem() { |
|||
DEBUG('Get System'); |
|||
return this.#data.system; |
|||
} |
|||
|
|||
async getLang() { |
|||
return this.#data.system?.lang || 'en'; |
|||
} |
|||
|
|||
async getUsers() { |
|||
return this.#data.users; |
|||
} |
|||
|
|||
async getUser(id: string) { |
|||
DEBUG('Get User'); |
|||
return this.#data.users.find((user) => user.id === id); |
|||
} |
|||
|
|||
async newUserWithPassword(username: string, password: string) { |
|||
DEBUG('New User'); |
|||
|
|||
if (username.length < 8) { |
|||
throw new DatabaseError(DatabaseError.ERROR_USERNAME_REQ); |
|||
} |
|||
|
|||
if (!isPasswordStrong(password)) { |
|||
throw new DatabaseError(DatabaseError.ERROR_PASSWORD_REQ); |
|||
} |
|||
|
|||
const isUserExist = this.#data.users.find( |
|||
(user) => user.username === username |
|||
); |
|||
if (isUserExist) { |
|||
throw new DatabaseError(DatabaseError.ERROR_USER_EXIST); |
|||
} |
|||
|
|||
const now = new Date(); |
|||
const isUserEmpty = this.#data.users.length === 0; |
|||
|
|||
const newUser: User = { |
|||
id: crypto.randomUUID(), |
|||
password: hashPassword(password), |
|||
username, |
|||
role: isUserEmpty ? 'ADMIN' : 'CLIENT', |
|||
enabled: true, |
|||
createdAt: now, |
|||
updatedAt: now, |
|||
}; |
|||
|
|||
this.#data.users.push(newUser); |
|||
} |
|||
|
|||
async updateUser(user: User) { |
|||
let oldUser = await this.getUser(user.id); |
|||
if (oldUser) { |
|||
DEBUG('Update User'); |
|||
oldUser = user; |
|||
} |
|||
} |
|||
|
|||
async deleteUser(id: string) { |
|||
DEBUG('Delete User'); |
|||
const idx = this.#data.users.findIndex((user) => user.id === id); |
|||
if (idx !== -1) { |
|||
this.#data.users.splice(idx, 1); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,90 @@ |
|||
import type { Low } from 'lowdb'; |
|||
import type { Database } from '../repositories/database'; |
|||
import packageJson from '@@/package.json'; |
|||
import { ChartType } from '../repositories/system'; |
|||
|
|||
// TODO: use variables inside up/down script
|
|||
const DEFAULT_ADDRESS = '10.8.0.x'; |
|||
const DEFAULT_DEVICE = 'eth0'; |
|||
const DEFAULT_WG_PORT = 51820; |
|||
const DEFAULT_POST_UP = ` |
|||
iptables -t nat -A POSTROUTING -s ${DEFAULT_ADDRESS.replace('x', '0')}/24 -o ${DEFAULT_DEVICE} -j MASQUERADE; |
|||
iptables -A INPUT -p udp -m udp --dport ${DEFAULT_WG_PORT} -j ACCEPT; |
|||
iptables -A FORWARD -i wg0 -j ACCEPT; |
|||
iptables -A FORWARD -o wg0 -j ACCEPT; |
|||
` |
|||
.split('\n') |
|||
.join(' '); |
|||
const DEFAULT_POST_DOWN = ` |
|||
iptables -t nat -D POSTROUTING -s ${DEFAULT_ADDRESS.replace('x', '0')}/24 -o ${DEFAULT_DEVICE} -j MASQUERADE; |
|||
iptables -D INPUT -p udp -m udp --dport ${DEFAULT_WG_PORT} -j ACCEPT; |
|||
iptables -D FORWARD -i wg0 -j ACCEPT; |
|||
iptables -D FORWARD -o wg0 -j ACCEPT; |
|||
` |
|||
.split('\n') |
|||
.join(' '); |
|||
|
|||
export async function run1(db: Low<Database>) { |
|||
const privateKey = await exec('wg genkey'); |
|||
const publicKey = await exec(`echo ${privateKey} | wg pubkey`, { |
|||
log: 'echo ***hidden*** | wg pubkey', |
|||
}); |
|||
const database: Database = { |
|||
migrations: [], |
|||
system: { |
|||
release: packageJson.release.version, |
|||
interface: { |
|||
privateKey: privateKey, |
|||
publicKey: publicKey, |
|||
address: DEFAULT_ADDRESS.replace('x', '1'), |
|||
}, |
|||
sessionTimeout: 3600, // 1 hour
|
|||
lang: 'en', |
|||
userConfig: { |
|||
mtu: 1420, |
|||
persistentKeepalive: 0, |
|||
// TODO: assume handle CIDR to compute next ip in WireGuard
|
|||
rangeAddress: '10.8.0.0/24', |
|||
defaultDns: ['1.1.1.1'], |
|||
allowedIps: ['0.0.0.0/0', '::/0'], |
|||
}, |
|||
wgPath: WG_PATH, |
|||
wgDevice: DEFAULT_DEVICE, |
|||
wgHost: WG_HOST || '', |
|||
wgPort: DEFAULT_WG_PORT, |
|||
wgConfigPort: 51820, |
|||
iptables: { |
|||
PreUp: '', |
|||
PostUp: DEFAULT_POST_UP, |
|||
PreDown: '', |
|||
PostDown: DEFAULT_POST_DOWN, |
|||
}, |
|||
trafficStats: { |
|||
enabled: false, |
|||
type: ChartType.None, |
|||
}, |
|||
clientExpiration: { |
|||
enabled: false, |
|||
}, |
|||
oneTimeLinks: { |
|||
enabled: false, |
|||
}, |
|||
sortClients: { |
|||
enabled: false, |
|||
}, |
|||
prometheus: { |
|||
enabled: false, |
|||
password: null, |
|||
}, |
|||
sessionConfig: { |
|||
password: getRandomHex(256), |
|||
name: 'wg-easy', |
|||
cookie: undefined, |
|||
}, |
|||
}, |
|||
users: [], |
|||
}; |
|||
|
|||
db.data = database; |
|||
db.write(); |
|||
} |
@ -0,0 +1,33 @@ |
|||
import type { Low } from 'lowdb'; |
|||
import type { Database } from '../repositories/database'; |
|||
import { run1 } from './1'; |
|||
|
|||
export type MIGRATION_FN = (db: Low<Database>) => Promise<void>; |
|||
|
|||
const MIGRATION_LIST = { |
|||
// Adds Initial Database Structure
|
|||
'1': run1, |
|||
} satisfies Record<string, MIGRATION_FN>; |
|||
|
|||
/** |
|||
* Runs all migrations |
|||
* @throws |
|||
*/ |
|||
export async function migrationRunner(db: Low<Database>) { |
|||
const ranMigrations = db.data.migrations; |
|||
const runMigrations = Object.keys( |
|||
MIGRATION_LIST |
|||
) as (keyof typeof MIGRATION_LIST)[]; |
|||
for (const migrationId of runMigrations) { |
|||
if (ranMigrations.includes(migrationId)) { |
|||
continue; |
|||
} |
|||
try { |
|||
await MIGRATION_LIST[migrationId](db); |
|||
db.data.migrations.push(migrationId); |
|||
} catch (e) { |
|||
throw new Error(`Failed to run Migration ${migrationId}: ${e}`); |
|||
} |
|||
} |
|||
await db.write(); |
|||
} |
@ -1 +0,0 @@ |
|||
export type Lang = 'en' | 'fr'; |
Loading…
Reference in new issue