feat(opsserver,web): replace the Angular UI and REST management layer with a TypedRequest-based ops server and bundled web frontend

This commit is contained in:
2026-03-20 16:43:44 +00:00
parent 0fc74ff995
commit d4f758ce0f
159 changed files with 12465 additions and 14861 deletions

View File

@@ -3,12 +3,18 @@
* Orchestrates OAuth/OIDC and LDAP authentication flows
*/
import { User, Session, AuthProvider, ExternalIdentity, PlatformSettings } from '../models/index.ts';
import {
AuthProvider,
ExternalIdentity,
PlatformSettings,
Session,
User,
} from '../models/index.ts';
import { AuthService, type IAuthResult } from './auth.service.ts';
import { AuditService } from './audit.service.ts';
import { cryptoService } from './crypto.service.ts';
import { AuthStrategyFactory, type IOAuthCallbackData } from './auth/strategies/index.ts';
import type { IExternalUserInfo, IConnectionTestResult } from '../interfaces/auth.interfaces.ts';
import type { IConnectionTestResult, IExternalUserInfo } from '../interfaces/auth.interfaces.ts';
export interface IOAuthState {
providerId: string;
@@ -33,7 +39,7 @@ export class ExternalAuthService {
*/
public async initiateOAuth(
providerId: string,
returnUrl?: string
returnUrl?: string,
): Promise<{ authUrl: string; state: string }> {
const provider = await AuthProvider.findById(providerId);
if (!provider) {
@@ -67,7 +73,7 @@ export class ExternalAuthService {
*/
public async handleOAuthCallback(
data: IOAuthCallbackData,
options: { ipAddress?: string; userAgent?: string } = {}
options: { ipAddress?: string; userAgent?: string } = {},
): Promise<IAuthResult> {
// Validate state
const stateData = await this.validateState(data.state);
@@ -170,7 +176,7 @@ export class ExternalAuthService {
providerId: string,
username: string,
password: string,
options: { ipAddress?: string; userAgent?: string } = {}
options: { ipAddress?: string; userAgent?: string } = {},
): Promise<IAuthResult> {
const provider = await AuthProvider.findById(providerId);
if (!provider || provider.status !== 'active' || provider.type !== 'ldap') {
@@ -261,7 +267,7 @@ export class ExternalAuthService {
public async linkProvider(
userId: string,
providerId: string,
externalUser: IExternalUserInfo
externalUser: IExternalUserInfo,
): Promise<ExternalIdentity> {
// Check if this external ID is already linked to another user
const existing = await ExternalIdentity.findByExternalId(providerId, externalUser.externalId);
@@ -377,12 +383,12 @@ export class ExternalAuthService {
private async findOrCreateUser(
provider: AuthProvider,
externalUser: IExternalUserInfo,
options: { ipAddress?: string } = {}
options: { ipAddress?: string } = {},
): Promise<{ user: User; isNew: boolean }> {
// 1. Check if external identity already exists
const existingIdentity = await ExternalIdentity.findByExternalId(
provider.id,
externalUser.externalId
externalUser.externalId,
);
if (existingIdentity) {
@@ -544,12 +550,12 @@ export class ExternalAuthService {
encoder.encode(secret),
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign']
['sign'],
);
const signature = await crypto.subtle.sign('HMAC', key, encoder.encode(data));
const encodedSignature = this.base64UrlEncode(
String.fromCharCode(...new Uint8Array(signature))
String.fromCharCode(...new Uint8Array(signature)),
);
return `${data}.${encodedSignature}`;