mirror of https://github.com/wg-easy/wg-easy
Browse Source
* add migrations * improve migration runner * improve migration runner * document what each migration doespull/1618/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'); |
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