Add tests for authentication and security features
- Implement unit tests for password handling in `auth_test.ts`, covering bcrypt and legacy password hashes. - Create a fake database for user management to facilitate testing of the `AdminHandler`. - Validate JWT-based identity verification against database records. - Introduce tests for credential encryption and registry management in `security_test.ts`. - Ensure registry passwords are securely stored and can be decrypted correctly, including legacy support. - Add utility functions for password hashing and verification in `auth.ts`.
This commit is contained in:
@@ -2,9 +2,12 @@ import * as plugins from '../../plugins.ts';
|
||||
import { logger } from '../../logging.ts';
|
||||
import type { OpsServer } from '../classes.opsserver.ts';
|
||||
import * as interfaces from '../../../ts_interfaces/index.ts';
|
||||
import { hashPassword, needsPasswordUpgrade, verifyPassword } from '../../utils/auth.ts';
|
||||
|
||||
export interface IJwtData {
|
||||
userId: string;
|
||||
username: string;
|
||||
role: 'admin' | 'user';
|
||||
status: 'loggedIn' | 'loggedOut';
|
||||
expiresAt: number;
|
||||
}
|
||||
@@ -18,12 +21,80 @@ export class AdminHandler {
|
||||
}
|
||||
|
||||
public async initialize(): Promise<void> {
|
||||
this.smartjwtInstance = new plugins.smartjwt.SmartJwt();
|
||||
this.smartjwtInstance = new plugins.smartjwt.SmartJwt<IJwtData>();
|
||||
await this.smartjwtInstance.init();
|
||||
await this.smartjwtInstance.createNewKeyPair();
|
||||
this.registerHandlers();
|
||||
}
|
||||
|
||||
private async createIdentityForUser(
|
||||
user: interfaces.data.IUser & { id?: number },
|
||||
expiresAt: number,
|
||||
): Promise<interfaces.data.IIdentity> {
|
||||
const userId = String(user.id || user.username);
|
||||
const jwt = await this.smartjwtInstance.createJWT({
|
||||
userId,
|
||||
username: user.username,
|
||||
role: user.role,
|
||||
status: 'loggedIn',
|
||||
expiresAt,
|
||||
});
|
||||
|
||||
return {
|
||||
jwt,
|
||||
userId,
|
||||
username: user.username,
|
||||
expiresAt,
|
||||
role: user.role,
|
||||
};
|
||||
}
|
||||
|
||||
public async getVerifiedIdentity(
|
||||
identityArg: interfaces.data.IIdentity | null | undefined,
|
||||
): Promise<interfaces.data.IIdentity> {
|
||||
if (!identityArg?.jwt) {
|
||||
throw new plugins.typedrequest.TypedResponseError('No identity provided');
|
||||
}
|
||||
|
||||
let jwtData: IJwtData;
|
||||
try {
|
||||
jwtData = await this.smartjwtInstance.verifyJWTAndGetData(identityArg.jwt);
|
||||
} catch {
|
||||
throw new plugins.typedrequest.TypedResponseError('Valid identity required');
|
||||
}
|
||||
|
||||
if (jwtData.expiresAt < Date.now() || jwtData.status !== 'loggedIn') {
|
||||
throw new plugins.typedrequest.TypedResponseError('Valid identity required');
|
||||
}
|
||||
|
||||
const user = this.opsServerRef.oneboxRef.database.getUserByUsername(jwtData.username);
|
||||
if (!user) {
|
||||
throw new plugins.typedrequest.TypedResponseError('Valid identity required');
|
||||
}
|
||||
|
||||
const userId = String(user.id || user.username);
|
||||
if (jwtData.userId !== userId) {
|
||||
throw new plugins.typedrequest.TypedResponseError('Valid identity required');
|
||||
}
|
||||
|
||||
return {
|
||||
jwt: identityArg.jwt,
|
||||
userId,
|
||||
username: user.username,
|
||||
expiresAt: jwtData.expiresAt,
|
||||
role: user.role,
|
||||
};
|
||||
}
|
||||
|
||||
public async getVerifiedAdminIdentity(
|
||||
identityArg: interfaces.data.IIdentity | null | undefined,
|
||||
): Promise<interfaces.data.IIdentity> {
|
||||
const identity = await this.getVerifiedIdentity(identityArg);
|
||||
if (identity.role !== 'admin') {
|
||||
throw new plugins.typedrequest.TypedResponseError('Admin access required');
|
||||
}
|
||||
return identity;
|
||||
}
|
||||
|
||||
private registerHandlers(): void {
|
||||
// Login
|
||||
this.typedrouter.addTypedHandler(
|
||||
@@ -36,30 +107,24 @@ export class AdminHandler {
|
||||
throw new plugins.typedrequest.TypedResponseError('Invalid credentials');
|
||||
}
|
||||
|
||||
// Verify password (base64 comparison to match existing DB scheme)
|
||||
const passwordHash = btoa(dataArg.password);
|
||||
if (passwordHash !== user.passwordHash) {
|
||||
const passwordMatches = await verifyPassword(dataArg.password, user.passwordHash);
|
||||
if (!passwordMatches) {
|
||||
throw new plugins.typedrequest.TypedResponseError('Invalid credentials');
|
||||
}
|
||||
|
||||
if (needsPasswordUpgrade(user.passwordHash)) {
|
||||
const upgradedHash = await hashPassword(dataArg.password);
|
||||
this.opsServerRef.oneboxRef.database.updateUserPassword(user.username, upgradedHash);
|
||||
}
|
||||
|
||||
const expiresAt = Date.now() + 24 * 3600 * 1000;
|
||||
const userId = String(user.id || user.username);
|
||||
const jwt = await this.smartjwtInstance.createJWT({
|
||||
userId,
|
||||
status: 'loggedIn',
|
||||
expiresAt,
|
||||
});
|
||||
const freshUser = this.opsServerRef.oneboxRef.database.getUserByUsername(user.username) || user;
|
||||
const identity = await this.createIdentityForUser(freshUser, expiresAt);
|
||||
|
||||
logger.info(`User logged in: ${user.username}`);
|
||||
|
||||
return {
|
||||
identity: {
|
||||
jwt,
|
||||
userId,
|
||||
username: user.username,
|
||||
expiresAt,
|
||||
role: user.role,
|
||||
},
|
||||
identity,
|
||||
};
|
||||
} catch (error) {
|
||||
if (error instanceof plugins.typedrequest.TypedResponseError) throw error;
|
||||
@@ -84,22 +149,11 @@ export class AdminHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_VerifyIdentity>(
|
||||
'verifyIdentity',
|
||||
async (dataArg) => {
|
||||
if (!dataArg.identity?.jwt) {
|
||||
return { valid: false };
|
||||
}
|
||||
try {
|
||||
const jwtData = await this.smartjwtInstance.verifyJWTAndGetData(dataArg.identity.jwt);
|
||||
if (jwtData.expiresAt < Date.now()) return { valid: false };
|
||||
if (jwtData.status !== 'loggedIn') return { valid: false };
|
||||
const identity = await this.getVerifiedIdentity(dataArg.identity);
|
||||
return {
|
||||
valid: true,
|
||||
identity: {
|
||||
jwt: dataArg.identity.jwt,
|
||||
userId: jwtData.userId,
|
||||
username: dataArg.identity.username,
|
||||
expiresAt: jwtData.expiresAt,
|
||||
role: dataArg.identity.role,
|
||||
},
|
||||
identity,
|
||||
};
|
||||
} catch {
|
||||
return { valid: false };
|
||||
@@ -110,21 +164,21 @@ export class AdminHandler {
|
||||
|
||||
// Change Password
|
||||
this.typedrouter.addTypedHandler(
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_ChangePassword>(
|
||||
'changePassword',
|
||||
async (dataArg) => {
|
||||
await this.requireValidIdentity(dataArg);
|
||||
const user = this.opsServerRef.oneboxRef.database.getUserByUsername(dataArg.identity.username);
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_ChangePassword>(
|
||||
'changePassword',
|
||||
async (dataArg) => {
|
||||
const identity = await this.getVerifiedIdentity(dataArg.identity);
|
||||
const user = this.opsServerRef.oneboxRef.database.getUserByUsername(identity.username);
|
||||
if (!user) {
|
||||
throw new plugins.typedrequest.TypedResponseError('User not found');
|
||||
}
|
||||
|
||||
const currentHash = btoa(dataArg.currentPassword);
|
||||
if (currentHash !== user.passwordHash) {
|
||||
const currentPasswordMatches = await verifyPassword(dataArg.currentPassword, user.passwordHash);
|
||||
if (!currentPasswordMatches) {
|
||||
throw new plugins.typedrequest.TypedResponseError('Current password is incorrect');
|
||||
}
|
||||
|
||||
const newHash = btoa(dataArg.newPassword);
|
||||
const newHash = await hashPassword(dataArg.newPassword);
|
||||
this.opsServerRef.oneboxRef.database.updateUserPassword(user.username, newHash);
|
||||
logger.info(`Password changed for user: ${user.username}`);
|
||||
|
||||
@@ -134,25 +188,13 @@ export class AdminHandler {
|
||||
);
|
||||
}
|
||||
|
||||
private async requireValidIdentity(dataArg: { identity: interfaces.data.IIdentity }): Promise<void> {
|
||||
const passed = await this.validIdentityGuard.exec({ identity: dataArg.identity });
|
||||
if (!passed) {
|
||||
throw new plugins.typedrequest.TypedResponseError('Valid identity required');
|
||||
}
|
||||
}
|
||||
|
||||
// Guard for valid identity
|
||||
public validIdentityGuard = new plugins.smartguard.Guard<{
|
||||
identity: interfaces.data.IIdentity;
|
||||
}>(
|
||||
async (dataArg) => {
|
||||
if (!dataArg.identity?.jwt) return false;
|
||||
try {
|
||||
const jwtData = await this.smartjwtInstance.verifyJWTAndGetData(dataArg.identity.jwt);
|
||||
if (jwtData.expiresAt < Date.now()) return false;
|
||||
if (jwtData.status !== 'loggedIn') return false;
|
||||
if (dataArg.identity.expiresAt !== jwtData.expiresAt) return false;
|
||||
if (dataArg.identity.userId !== jwtData.userId) return false;
|
||||
await this.getVerifiedIdentity(dataArg.identity);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
@@ -166,9 +208,12 @@ export class AdminHandler {
|
||||
identity: interfaces.data.IIdentity;
|
||||
}>(
|
||||
async (dataArg) => {
|
||||
const isValid = await this.validIdentityGuard.exec(dataArg);
|
||||
if (!isValid) return false;
|
||||
return dataArg.identity.role === 'admin';
|
||||
try {
|
||||
const identity = await this.getVerifiedIdentity(dataArg.identity);
|
||||
return identity.role === 'admin';
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
{ failedHint: 'user is not admin', name: 'adminIdentityGuard' },
|
||||
);
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as plugins from '../../plugins.ts';
|
||||
import { logger } from '../../logging.ts';
|
||||
import type { OpsServer } from '../classes.opsserver.ts';
|
||||
import * as interfaces from '../../../ts_interfaces/index.ts';
|
||||
import { requireValidIdentity } from '../helpers/guards.ts';
|
||||
import { requireAdminIdentity } from '../helpers/guards.ts';
|
||||
|
||||
export class AppStoreHandler {
|
||||
public typedrouter = new plugins.typedrequest.TypedRouter();
|
||||
@@ -18,7 +18,7 @@ export class AppStoreHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetAppTemplates>(
|
||||
'getAppTemplates',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const apps = await this.opsServerRef.oneboxRef.appStore.getApps();
|
||||
return { apps };
|
||||
},
|
||||
@@ -30,7 +30,7 @@ export class AppStoreHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetAppConfig>(
|
||||
'getAppConfig',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const config = await this.opsServerRef.oneboxRef.appStore.getAppVersionConfig(
|
||||
dataArg.appId,
|
||||
dataArg.version,
|
||||
@@ -46,7 +46,7 @@ export class AppStoreHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetUpgradeableServices>(
|
||||
'getUpgradeableServices',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const services = await this.opsServerRef.oneboxRef.appStore.getUpgradeableServices();
|
||||
return { services };
|
||||
},
|
||||
@@ -58,7 +58,7 @@ export class AppStoreHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_UpgradeService>(
|
||||
'upgradeService',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
|
||||
const existingService = this.opsServerRef.oneboxRef.database.getServiceByName(dataArg.serviceName);
|
||||
if (!existingService) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as plugins from '../../plugins.ts';
|
||||
import type { OpsServer } from '../classes.opsserver.ts';
|
||||
import * as interfaces from '../../../ts_interfaces/index.ts';
|
||||
import { requireValidIdentity } from '../helpers/guards.ts';
|
||||
import { requireAdminIdentity } from '../helpers/guards.ts';
|
||||
|
||||
export class BackupsHandler {
|
||||
public typedrouter = new plugins.typedrequest.TypedRouter();
|
||||
@@ -16,7 +16,7 @@ export class BackupsHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetBackups>(
|
||||
'getBackups',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const backups = this.opsServerRef.oneboxRef.backupManager.listBackups();
|
||||
return { backups };
|
||||
},
|
||||
@@ -27,7 +27,7 @@ export class BackupsHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetBackup>(
|
||||
'getBackup',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const backup = this.opsServerRef.oneboxRef.database.getBackupById(dataArg.backupId);
|
||||
if (!backup) {
|
||||
throw new plugins.typedrequest.TypedResponseError('Backup not found');
|
||||
@@ -41,7 +41,7 @@ export class BackupsHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_DeleteBackup>(
|
||||
'deleteBackup',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await this.opsServerRef.oneboxRef.backupManager.deleteBackup(dataArg.backupId);
|
||||
return { ok: true };
|
||||
},
|
||||
@@ -52,7 +52,7 @@ export class BackupsHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_RestoreBackup>(
|
||||
'restoreBackup',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const rawResult = await this.opsServerRef.oneboxRef.backupManager.restoreBackup(
|
||||
dataArg.backupId,
|
||||
dataArg.options,
|
||||
@@ -75,7 +75,7 @@ export class BackupsHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_DownloadBackup>(
|
||||
'downloadBackup',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const backup = this.opsServerRef.oneboxRef.database.getBackupById(dataArg.backupId);
|
||||
if (!backup) {
|
||||
throw new plugins.typedrequest.TypedResponseError('Backup not found');
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as plugins from '../../plugins.ts';
|
||||
import type { OpsServer } from '../classes.opsserver.ts';
|
||||
import * as interfaces from '../../../ts_interfaces/index.ts';
|
||||
import { requireValidIdentity } from '../helpers/guards.ts';
|
||||
import { requireAdminIdentity } from '../helpers/guards.ts';
|
||||
|
||||
export class DnsHandler {
|
||||
public typedrouter = new plugins.typedrequest.TypedRouter();
|
||||
@@ -16,7 +16,7 @@ export class DnsHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetDnsRecords>(
|
||||
'getDnsRecords',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const records = this.opsServerRef.oneboxRef.dns.listDNSRecords();
|
||||
return { records };
|
||||
},
|
||||
@@ -27,7 +27,7 @@ export class DnsHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_CreateDnsRecord>(
|
||||
'createDnsRecord',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await this.opsServerRef.oneboxRef.dns.addDNSRecord(dataArg.domain, dataArg.value);
|
||||
const records = this.opsServerRef.oneboxRef.dns.listDNSRecords();
|
||||
const record = records.find((r: any) => r.domain === dataArg.domain);
|
||||
@@ -40,7 +40,7 @@ export class DnsHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_DeleteDnsRecord>(
|
||||
'deleteDnsRecord',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await this.opsServerRef.oneboxRef.dns.removeDNSRecord(dataArg.domain);
|
||||
return { ok: true };
|
||||
},
|
||||
@@ -51,7 +51,7 @@ export class DnsHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_SyncDns>(
|
||||
'syncDns',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
if (!this.opsServerRef.oneboxRef.dns.isConfigured()) {
|
||||
throw new plugins.typedrequest.TypedResponseError('DNS manager not configured');
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as plugins from '../../plugins.ts';
|
||||
import type { OpsServer } from '../classes.opsserver.ts';
|
||||
import * as interfaces from '../../../ts_interfaces/index.ts';
|
||||
import { requireValidIdentity } from '../helpers/guards.ts';
|
||||
import { requireAdminIdentity } from '../helpers/guards.ts';
|
||||
|
||||
export class DomainsHandler {
|
||||
public typedrouter = new plugins.typedrequest.TypedRouter();
|
||||
@@ -57,7 +57,7 @@ export class DomainsHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetDomains>(
|
||||
'getDomains',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const domains = this.buildDomainViews();
|
||||
return { domains };
|
||||
},
|
||||
@@ -68,7 +68,7 @@ export class DomainsHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetDomain>(
|
||||
'getDomain',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const domain = this.opsServerRef.oneboxRef.database.getDomainByName(dataArg.domainName);
|
||||
if (!domain) {
|
||||
throw new plugins.typedrequest.TypedResponseError('Domain not found');
|
||||
@@ -87,7 +87,7 @@ export class DomainsHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_SyncDomains>(
|
||||
'syncDomains',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
if (!this.opsServerRef.oneboxRef.cloudflareDomainSync) {
|
||||
throw new plugins.typedrequest.TypedResponseError('Cloudflare domain sync not configured');
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as plugins from '../../plugins.ts';
|
||||
import { logger } from '../../logging.ts';
|
||||
import type { OpsServer } from '../classes.opsserver.ts';
|
||||
import * as interfaces from '../../../ts_interfaces/index.ts';
|
||||
import { requireValidIdentity } from '../helpers/guards.ts';
|
||||
import { requireAdminIdentity } from '../helpers/guards.ts';
|
||||
|
||||
export class LogsHandler {
|
||||
public typedrouter = new plugins.typedrequest.TypedRouter();
|
||||
@@ -18,7 +18,7 @@ export class LogsHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetServiceLogStream>(
|
||||
'getServiceLogStream',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
|
||||
const service = this.opsServerRef.oneboxRef.database.getServiceByName(dataArg.serviceName);
|
||||
if (!service) {
|
||||
@@ -99,7 +99,7 @@ export class LogsHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetPlatformServiceLogStream>(
|
||||
'getPlatformServiceLogStream',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
|
||||
const platformService = this.opsServerRef.oneboxRef.database.getPlatformServiceByType(
|
||||
dataArg.serviceType,
|
||||
@@ -160,7 +160,7 @@ export class LogsHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetNetworkLogStream>(
|
||||
'getNetworkLogStream',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
|
||||
const virtualStream = new plugins.typedrequest.VirtualStream<Uint8Array>();
|
||||
const encoder = new TextEncoder();
|
||||
@@ -195,7 +195,7 @@ export class LogsHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetEventStream>(
|
||||
'getEventStream',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
|
||||
const virtualStream = new plugins.typedrequest.VirtualStream<Uint8Array>();
|
||||
const encoder = new TextEncoder();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as plugins from '../../plugins.ts';
|
||||
import type { OpsServer } from '../classes.opsserver.ts';
|
||||
import * as interfaces from '../../../ts_interfaces/index.ts';
|
||||
import { requireValidIdentity } from '../helpers/guards.ts';
|
||||
import { requireAdminIdentity } from '../helpers/guards.ts';
|
||||
import type { TPlatformServiceType } from '../../types.ts';
|
||||
|
||||
export class NetworkHandler {
|
||||
@@ -31,7 +31,7 @@ export class NetworkHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetNetworkTargets>(
|
||||
'getNetworkTargets',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const targets: interfaces.data.INetworkTarget[] = [];
|
||||
|
||||
// Services
|
||||
@@ -83,7 +83,7 @@ export class NetworkHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetNetworkStats>(
|
||||
'getNetworkStats',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const proxyStatus = this.opsServerRef.oneboxRef.reverseProxy.getStatus() as any;
|
||||
const logReceiverStats = this.opsServerRef.oneboxRef.caddyLogReceiver.getStats();
|
||||
|
||||
@@ -114,7 +114,7 @@ export class NetworkHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetTrafficStats>(
|
||||
'getTrafficStats',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const trafficStats = this.opsServerRef.oneboxRef.caddyLogReceiver.getTrafficStats(60);
|
||||
return { stats: trafficStats };
|
||||
},
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as plugins from '../../plugins.ts';
|
||||
import { logger } from '../../logging.ts';
|
||||
import type { OpsServer } from '../classes.opsserver.ts';
|
||||
import * as interfaces from '../../../ts_interfaces/index.ts';
|
||||
import { requireValidIdentity } from '../helpers/guards.ts';
|
||||
import { requireAdminIdentity } from '../helpers/guards.ts';
|
||||
|
||||
export class PlatformHandler {
|
||||
public typedrouter = new plugins.typedrequest.TypedRouter();
|
||||
@@ -99,7 +99,7 @@ export class PlatformHandler {
|
||||
typedsocket.findAllTargetConnectionsByTag('role', 'ops_dashboard')
|
||||
.then((connections: any[]) => {
|
||||
for (const conn of connections) {
|
||||
typedsocket.createTypedRequest<interfaces.requests.IReq_PushPlatformServiceLog>(
|
||||
typedsocket.createTypedRequest(
|
||||
'pushPlatformServiceLog',
|
||||
conn,
|
||||
).fire({ serviceType, entry }).catch(() => {});
|
||||
@@ -121,7 +121,7 @@ export class PlatformHandler {
|
||||
typedsocket.findAllTargetConnectionsByTag('role', 'ops_dashboard')
|
||||
.then((connections: any[]) => {
|
||||
for (const conn of connections) {
|
||||
typedsocket.createTypedRequest<interfaces.requests.IReq_PushServiceLog>(
|
||||
typedsocket.createTypedRequest(
|
||||
'pushServiceLog',
|
||||
conn,
|
||||
).fire({ serviceName, entry }).catch(() => {});
|
||||
@@ -136,7 +136,7 @@ export class PlatformHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetPlatformServices>(
|
||||
'getPlatformServices',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const platformServices = this.opsServerRef.oneboxRef.platformServices.getAllPlatformServices();
|
||||
const providers = this.opsServerRef.oneboxRef.platformServices.getAllProviders();
|
||||
|
||||
@@ -172,7 +172,7 @@ export class PlatformHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetPlatformService>(
|
||||
'getPlatformService',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const provider = this.opsServerRef.oneboxRef.platformServices.getProvider(dataArg.serviceType);
|
||||
if (!provider) {
|
||||
throw new plugins.typedrequest.TypedResponseError(`Unknown platform service type: ${dataArg.serviceType}`);
|
||||
@@ -208,7 +208,7 @@ export class PlatformHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_StartPlatformService>(
|
||||
'startPlatformService',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const provider = this.opsServerRef.oneboxRef.platformServices.getProvider(dataArg.serviceType);
|
||||
if (!provider) {
|
||||
throw new plugins.typedrequest.TypedResponseError(`Unknown platform service type: ${dataArg.serviceType}`);
|
||||
@@ -235,7 +235,7 @@ export class PlatformHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_StopPlatformService>(
|
||||
'stopPlatformService',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const provider = this.opsServerRef.oneboxRef.platformServices.getProvider(dataArg.serviceType);
|
||||
if (!provider) {
|
||||
throw new plugins.typedrequest.TypedResponseError(`Unknown platform service type: ${dataArg.serviceType}`);
|
||||
@@ -268,7 +268,7 @@ export class PlatformHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetPlatformServiceStats>(
|
||||
'getPlatformServiceStats',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const service = this.opsServerRef.oneboxRef.database.getPlatformServiceByType(dataArg.serviceType);
|
||||
if (!service || !service.containerId) {
|
||||
throw new plugins.typedrequest.TypedResponseError('Platform service has no container');
|
||||
@@ -289,7 +289,7 @@ export class PlatformHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetPlatformServiceLogs>(
|
||||
'getPlatformServiceLogs',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const service = this.opsServerRef.oneboxRef.database.getPlatformServiceByType(dataArg.serviceType);
|
||||
if (!service || !service.containerId) {
|
||||
throw new plugins.typedrequest.TypedResponseError('Platform service has no container');
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as plugins from '../../plugins.ts';
|
||||
import type { OpsServer } from '../classes.opsserver.ts';
|
||||
import * as interfaces from '../../../ts_interfaces/index.ts';
|
||||
import { requireValidIdentity } from '../helpers/guards.ts';
|
||||
import { requireAdminIdentity } from '../helpers/guards.ts';
|
||||
|
||||
export class RegistryHandler {
|
||||
public typedrouter = new plugins.typedrequest.TypedRouter();
|
||||
@@ -17,7 +17,7 @@ export class RegistryHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetRegistryTags>(
|
||||
'getRegistryTags',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const tags = await this.opsServerRef.oneboxRef.registry.getImageTags(dataArg.serviceName);
|
||||
return { tags };
|
||||
},
|
||||
@@ -29,7 +29,7 @@ export class RegistryHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetRegistryTokens>(
|
||||
'getRegistryTokens',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const rawTokens = this.opsServerRef.oneboxRef.database.getAllRegistryTokens();
|
||||
const now = Date.now();
|
||||
|
||||
@@ -68,7 +68,7 @@ export class RegistryHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_CreateRegistryToken>(
|
||||
'createRegistryToken',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const identity = await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const config = dataArg.tokenConfig;
|
||||
|
||||
// Calculate expiration
|
||||
@@ -95,7 +95,7 @@ export class RegistryHandler {
|
||||
expiresAt,
|
||||
createdAt: now,
|
||||
lastUsedAt: null,
|
||||
createdBy: dataArg.identity.username,
|
||||
createdBy: identity.username,
|
||||
});
|
||||
|
||||
let scopeDisplay: string;
|
||||
@@ -133,7 +133,7 @@ export class RegistryHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_DeleteRegistryToken>(
|
||||
'deleteRegistryToken',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const token = this.opsServerRef.oneboxRef.database.getRegistryTokenById(dataArg.tokenId);
|
||||
if (!token) {
|
||||
throw new plugins.typedrequest.TypedResponseError('Token not found');
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as plugins from '../../plugins.ts';
|
||||
import type { OpsServer } from '../classes.opsserver.ts';
|
||||
import * as interfaces from '../../../ts_interfaces/index.ts';
|
||||
import { requireValidIdentity } from '../helpers/guards.ts';
|
||||
import { requireAdminIdentity } from '../helpers/guards.ts';
|
||||
|
||||
export class SchedulesHandler {
|
||||
public typedrouter = new plugins.typedrequest.TypedRouter();
|
||||
@@ -16,7 +16,7 @@ export class SchedulesHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetBackupSchedules>(
|
||||
'getBackupSchedules',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const schedules = this.opsServerRef.oneboxRef.backupScheduler.getAllSchedules();
|
||||
return { schedules };
|
||||
},
|
||||
@@ -27,7 +27,7 @@ export class SchedulesHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_CreateBackupSchedule>(
|
||||
'createBackupSchedule',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const schedule = await this.opsServerRef.oneboxRef.backupScheduler.createSchedule(
|
||||
dataArg.scheduleConfig,
|
||||
);
|
||||
@@ -40,7 +40,7 @@ export class SchedulesHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetBackupSchedule>(
|
||||
'getBackupSchedule',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const schedule = this.opsServerRef.oneboxRef.backupScheduler.getScheduleById(dataArg.scheduleId);
|
||||
if (!schedule) {
|
||||
throw new plugins.typedrequest.TypedResponseError('Schedule not found');
|
||||
@@ -54,7 +54,7 @@ export class SchedulesHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_UpdateBackupSchedule>(
|
||||
'updateBackupSchedule',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const schedule = await this.opsServerRef.oneboxRef.backupScheduler.updateSchedule(
|
||||
dataArg.scheduleId,
|
||||
dataArg.updates,
|
||||
@@ -68,7 +68,7 @@ export class SchedulesHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_DeleteBackupSchedule>(
|
||||
'deleteBackupSchedule',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await this.opsServerRef.oneboxRef.backupScheduler.deleteSchedule(dataArg.scheduleId);
|
||||
return { ok: true };
|
||||
},
|
||||
@@ -79,7 +79,7 @@ export class SchedulesHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_TriggerBackupSchedule>(
|
||||
'triggerBackupSchedule',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await this.opsServerRef.oneboxRef.backupScheduler.triggerBackup(dataArg.scheduleId);
|
||||
// triggerBackup is void; the backup is created async by the scheduler
|
||||
// Return the most recent backup for the schedule
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as plugins from '../../plugins.ts';
|
||||
import { logger } from '../../logging.ts';
|
||||
import type { OpsServer } from '../classes.opsserver.ts';
|
||||
import * as interfaces from '../../../ts_interfaces/index.ts';
|
||||
import { requireValidIdentity } from '../helpers/guards.ts';
|
||||
import { requireAdminIdentity } from '../helpers/guards.ts';
|
||||
|
||||
export class ServicesHandler {
|
||||
public typedrouter = new plugins.typedrequest.TypedRouter();
|
||||
@@ -18,7 +18,7 @@ export class ServicesHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetServices>(
|
||||
'getServices',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const services = this.opsServerRef.oneboxRef.services.listServices();
|
||||
return { services };
|
||||
},
|
||||
@@ -30,7 +30,7 @@ export class ServicesHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetService>(
|
||||
'getService',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const service = this.opsServerRef.oneboxRef.services.getService(dataArg.serviceName);
|
||||
if (!service) {
|
||||
throw new plugins.typedrequest.TypedResponseError('Service not found');
|
||||
@@ -45,7 +45,7 @@ export class ServicesHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_CreateService>(
|
||||
'createService',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const service = await this.opsServerRef.oneboxRef.services.deployService(dataArg.serviceConfig);
|
||||
return { service };
|
||||
},
|
||||
@@ -57,7 +57,7 @@ export class ServicesHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_UpdateService>(
|
||||
'updateService',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const service = await this.opsServerRef.oneboxRef.services.updateService(
|
||||
dataArg.serviceName,
|
||||
dataArg.updates,
|
||||
@@ -72,7 +72,7 @@ export class ServicesHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_DeleteService>(
|
||||
'deleteService',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await this.opsServerRef.oneboxRef.services.removeService(dataArg.serviceName);
|
||||
return { ok: true };
|
||||
},
|
||||
@@ -84,7 +84,7 @@ export class ServicesHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_StartService>(
|
||||
'startService',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await this.opsServerRef.oneboxRef.services.startService(dataArg.serviceName);
|
||||
const service = this.opsServerRef.oneboxRef.services.getService(dataArg.serviceName);
|
||||
return { service: service! };
|
||||
@@ -97,7 +97,7 @@ export class ServicesHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_StopService>(
|
||||
'stopService',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await this.opsServerRef.oneboxRef.services.stopService(dataArg.serviceName);
|
||||
const service = this.opsServerRef.oneboxRef.services.getService(dataArg.serviceName);
|
||||
return { service: service! };
|
||||
@@ -110,7 +110,7 @@ export class ServicesHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_RestartService>(
|
||||
'restartService',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await this.opsServerRef.oneboxRef.services.restartService(dataArg.serviceName);
|
||||
const service = this.opsServerRef.oneboxRef.services.getService(dataArg.serviceName);
|
||||
return { service: service! };
|
||||
@@ -123,7 +123,7 @@ export class ServicesHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetServiceLogs>(
|
||||
'getServiceLogs',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const logs = await this.opsServerRef.oneboxRef.services.getServiceLogs(dataArg.serviceName);
|
||||
return { logs: String(logs) };
|
||||
},
|
||||
@@ -135,7 +135,7 @@ export class ServicesHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetServiceStats>(
|
||||
'getServiceStats',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const service = this.opsServerRef.oneboxRef.services.getService(dataArg.serviceName);
|
||||
if (!service || !service.containerID) {
|
||||
throw new plugins.typedrequest.TypedResponseError('Service has no container');
|
||||
@@ -154,7 +154,7 @@ export class ServicesHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetServiceMetrics>(
|
||||
'getServiceMetrics',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const service = this.opsServerRef.oneboxRef.services.getService(dataArg.serviceName);
|
||||
if (!service || !service.id) {
|
||||
throw new plugins.typedrequest.TypedResponseError('Service not found');
|
||||
@@ -170,7 +170,7 @@ export class ServicesHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetServicePlatformResources>(
|
||||
'getServicePlatformResources',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const rawResources = await this.opsServerRef.oneboxRef.services.getServicePlatformResources(
|
||||
dataArg.serviceName,
|
||||
);
|
||||
@@ -204,7 +204,7 @@ export class ServicesHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetServiceBackups>(
|
||||
'getServiceBackups',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const backups = this.opsServerRef.oneboxRef.backupManager.listBackups(dataArg.serviceName);
|
||||
return { backups };
|
||||
},
|
||||
@@ -216,7 +216,7 @@ export class ServicesHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_CreateServiceBackup>(
|
||||
'createServiceBackup',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const result = await this.opsServerRef.oneboxRef.backupManager.createBackup(dataArg.serviceName);
|
||||
return { backup: result.backup };
|
||||
},
|
||||
@@ -228,7 +228,7 @@ export class ServicesHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetServiceBackupSchedules>(
|
||||
'getServiceBackupSchedules',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const service = this.opsServerRef.oneboxRef.services.getService(dataArg.serviceName);
|
||||
if (!service) {
|
||||
throw new plugins.typedrequest.TypedResponseError('Service not found');
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as plugins from '../../plugins.ts';
|
||||
import type { OpsServer } from '../classes.opsserver.ts';
|
||||
import * as interfaces from '../../../ts_interfaces/index.ts';
|
||||
import { requireValidIdentity } from '../helpers/guards.ts';
|
||||
import { requireAdminIdentity } from '../helpers/guards.ts';
|
||||
|
||||
export class SettingsHandler {
|
||||
public typedrouter = new plugins.typedrequest.TypedRouter();
|
||||
@@ -16,7 +16,7 @@ export class SettingsHandler {
|
||||
const settingsMap = db.getAllSettings(); // Returns Record<string, string>
|
||||
|
||||
return {
|
||||
cloudflareToken: settingsMap['cloudflareToken'] || '',
|
||||
cloudflareToken: settingsMap['cloudflareToken'] || settingsMap['cloudflareAPIKey'] || '',
|
||||
cloudflareZoneId: settingsMap['cloudflareZoneId'] || '',
|
||||
autoRenewCerts: settingsMap['autoRenewCerts'] === 'true',
|
||||
renewalThreshold: parseInt(settingsMap['renewalThreshold'] || '30', 10),
|
||||
@@ -32,7 +32,7 @@ export class SettingsHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetSettings>(
|
||||
'getSettings',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const settings = this.getSettingsObject();
|
||||
return { settings };
|
||||
},
|
||||
@@ -43,14 +43,19 @@ export class SettingsHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_UpdateSettings>(
|
||||
'updateSettings',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const db = this.opsServerRef.oneboxRef.database;
|
||||
const updates = dataArg.settings;
|
||||
|
||||
// Store each setting as key-value pair
|
||||
for (const [key, value] of Object.entries(updates)) {
|
||||
if (value !== undefined) {
|
||||
db.setSetting(key, String(value));
|
||||
if (key === 'cloudflareToken') {
|
||||
db.setSetting('cloudflareToken', String(value));
|
||||
db.setSetting('cloudflareAPIKey', String(value));
|
||||
} else {
|
||||
db.setSetting(key, String(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +69,8 @@ export class SettingsHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_SetBackupPassword>(
|
||||
'setBackupPassword',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
this.opsServerRef.oneboxRef.database.setSetting('backup_encryption_password', dataArg.password);
|
||||
this.opsServerRef.oneboxRef.database.setSetting('backupPassword', dataArg.password);
|
||||
return { ok: true };
|
||||
},
|
||||
@@ -75,8 +81,9 @@ export class SettingsHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetBackupPasswordStatus>(
|
||||
'getBackupPasswordStatus',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const backupPassword = this.opsServerRef.oneboxRef.database.getSetting('backupPassword');
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const backupPassword = this.opsServerRef.oneboxRef.database.getSetting('backupPassword')
|
||||
|| this.opsServerRef.oneboxRef.database.getSetting('backup_encryption_password');
|
||||
const isConfigured = !!backupPassword;
|
||||
return { status: { isConfigured } };
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as plugins from '../../plugins.ts';
|
||||
import type { OpsServer } from '../classes.opsserver.ts';
|
||||
import * as interfaces from '../../../ts_interfaces/index.ts';
|
||||
import { requireValidIdentity } from '../helpers/guards.ts';
|
||||
import { requireAdminIdentity } from '../helpers/guards.ts';
|
||||
|
||||
export class SslHandler {
|
||||
public typedrouter = new plugins.typedrequest.TypedRouter();
|
||||
@@ -16,7 +16,7 @@ export class SslHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_ObtainCertificate>(
|
||||
'obtainCertificate',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await this.opsServerRef.oneboxRef.ssl.obtainCertificate(dataArg.domain, false);
|
||||
const certificate = this.opsServerRef.oneboxRef.ssl.getCertificate(dataArg.domain);
|
||||
return { certificate: certificate as unknown as interfaces.data.ICertificate };
|
||||
@@ -28,7 +28,7 @@ export class SslHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_ListCertificates>(
|
||||
'listCertificates',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const certificates = this.opsServerRef.oneboxRef.ssl.listCertificates();
|
||||
return { certificates: certificates as unknown as interfaces.data.ICertificate[] };
|
||||
},
|
||||
@@ -39,7 +39,7 @@ export class SslHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetCertificate>(
|
||||
'getCertificate',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const certificate = this.opsServerRef.oneboxRef.ssl.getCertificate(dataArg.domain);
|
||||
if (!certificate) {
|
||||
throw new plugins.typedrequest.TypedResponseError('Certificate not found');
|
||||
@@ -53,7 +53,7 @@ export class SslHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_RenewCertificate>(
|
||||
'renewCertificate',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await this.opsServerRef.oneboxRef.ssl.renewCertificate(dataArg.domain);
|
||||
const certificate = this.opsServerRef.oneboxRef.ssl.getCertificate(dataArg.domain);
|
||||
return { certificate: certificate as unknown as interfaces.data.ICertificate };
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as plugins from '../../plugins.ts';
|
||||
import type { OpsServer } from '../classes.opsserver.ts';
|
||||
import * as interfaces from '../../../ts_interfaces/index.ts';
|
||||
import { requireValidIdentity } from '../helpers/guards.ts';
|
||||
import { requireAdminIdentity } from '../helpers/guards.ts';
|
||||
|
||||
export class StatusHandler {
|
||||
public typedrouter = new plugins.typedrequest.TypedRouter();
|
||||
@@ -16,7 +16,7 @@ export class StatusHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetSystemStatus>(
|
||||
'getSystemStatus',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const status = await this.opsServerRef.oneboxRef.getSystemStatus();
|
||||
return { status: status as unknown as interfaces.data.ISystemStatus };
|
||||
},
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as plugins from '../../plugins.ts';
|
||||
import { logger } from '../../logging.ts';
|
||||
import type { OpsServer } from '../classes.opsserver.ts';
|
||||
import * as interfaces from '../../../ts_interfaces/index.ts';
|
||||
import { requireValidIdentity } from '../helpers/guards.ts';
|
||||
import { requireAdminIdentity } from '../helpers/guards.ts';
|
||||
import { getErrorMessage } from '../../utils/error.ts';
|
||||
|
||||
export class WorkspaceHandler {
|
||||
@@ -30,7 +30,7 @@ export class WorkspaceHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_WorkspaceReadFile>(
|
||||
'workspaceReadFile',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const containerId = await this.resolveContainerId(dataArg.serviceName);
|
||||
const result = await this.opsServerRef.oneboxRef.docker.execInContainer(
|
||||
containerId,
|
||||
@@ -49,7 +49,7 @@ export class WorkspaceHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_WorkspaceWriteFile>(
|
||||
'workspaceWriteFile',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const containerId = await this.resolveContainerId(dataArg.serviceName);
|
||||
// Use sh -c with printf to write content (handles special characters)
|
||||
const escaped = dataArg.content.replace(/'/g, "'\\''");
|
||||
@@ -70,7 +70,7 @@ export class WorkspaceHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_WorkspaceReadDir>(
|
||||
'workspaceReadDir',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const containerId = await this.resolveContainerId(dataArg.serviceName);
|
||||
// Use ls with -1 -F to get entries with type indicators (/ for dirs)
|
||||
const result = await this.opsServerRef.oneboxRef.docker.execInContainer(
|
||||
@@ -103,7 +103,7 @@ export class WorkspaceHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_WorkspaceMkdir>(
|
||||
'workspaceMkdir',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const containerId = await this.resolveContainerId(dataArg.serviceName);
|
||||
const result = await this.opsServerRef.oneboxRef.docker.execInContainer(
|
||||
containerId,
|
||||
@@ -122,7 +122,7 @@ export class WorkspaceHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_WorkspaceRm>(
|
||||
'workspaceRm',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const containerId = await this.resolveContainerId(dataArg.serviceName);
|
||||
const args = dataArg.recursive ? ['rm', '-rf', dataArg.path] : ['rm', '-f', dataArg.path];
|
||||
const result = await this.opsServerRef.oneboxRef.docker.execInContainer(
|
||||
@@ -142,7 +142,7 @@ export class WorkspaceHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_WorkspaceExists>(
|
||||
'workspaceExists',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const containerId = await this.resolveContainerId(dataArg.serviceName);
|
||||
const result = await this.opsServerRef.oneboxRef.docker.execInContainer(
|
||||
containerId,
|
||||
@@ -158,7 +158,7 @@ export class WorkspaceHandler {
|
||||
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_WorkspaceExec>(
|
||||
'workspaceExec',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const containerId = await this.resolveContainerId(dataArg.serviceName);
|
||||
const cmd = dataArg.args
|
||||
? [dataArg.command, ...dataArg.args]
|
||||
|
||||
@@ -5,25 +5,13 @@ import * as interfaces from '../../../ts_interfaces/index.ts';
|
||||
export async function requireValidIdentity<T extends { identity?: interfaces.data.IIdentity }>(
|
||||
adminHandler: AdminHandler,
|
||||
dataArg: T,
|
||||
): Promise<void> {
|
||||
if (!dataArg.identity) {
|
||||
throw new plugins.typedrequest.TypedResponseError('No identity provided');
|
||||
}
|
||||
const passed = await adminHandler.validIdentityGuard.exec({ identity: dataArg.identity });
|
||||
if (!passed) {
|
||||
throw new plugins.typedrequest.TypedResponseError('Valid identity required');
|
||||
}
|
||||
): Promise<interfaces.data.IIdentity> {
|
||||
return await adminHandler.getVerifiedIdentity(dataArg.identity);
|
||||
}
|
||||
|
||||
export async function requireAdminIdentity<T extends { identity?: interfaces.data.IIdentity }>(
|
||||
adminHandler: AdminHandler,
|
||||
dataArg: T,
|
||||
): Promise<void> {
|
||||
if (!dataArg.identity) {
|
||||
throw new plugins.typedrequest.TypedResponseError('No identity provided');
|
||||
}
|
||||
const passed = await adminHandler.adminIdentityGuard.exec({ identity: dataArg.identity });
|
||||
if (!passed) {
|
||||
throw new plugins.typedrequest.TypedResponseError('Admin access required');
|
||||
}
|
||||
): Promise<interfaces.data.IIdentity> {
|
||||
return await adminHandler.getVerifiedAdminIdentity(dataArg.identity);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user