49 lines
1.9 KiB
TypeScript
49 lines
1.9 KiB
TypeScript
import type Database from 'better-sqlite3';
|
|
import type { SessionMetadata } from '@multi-simadmin/contracts';
|
|
import { CredentialResolverError } from './instance-credential-resolver.js';
|
|
import { UpstreamSessionClient } from './upstream-session-client.js';
|
|
|
|
export interface CredentialResolver {
|
|
resolve(instanceId: string): Promise<string>;
|
|
}
|
|
export class InstanceLoginServiceError extends Error {
|
|
constructor(readonly code: 'NOT_FOUND' | 'CREDENTIAL_UNAVAILABLE') {
|
|
super(code);
|
|
}
|
|
}
|
|
export interface InstanceLoginServiceOptions {
|
|
readonly db: Database.Database;
|
|
readonly client: UpstreamSessionClient;
|
|
readonly resolver: CredentialResolver;
|
|
readonly now?: () => Date;
|
|
}
|
|
export class InstanceLoginService {
|
|
private readonly now: () => Date;
|
|
constructor(private readonly options: InstanceLoginServiceOptions) {
|
|
this.now = options.now ?? (() => new Date());
|
|
}
|
|
async login(instanceId: string, password?: string): Promise<SessionMetadata> {
|
|
const origin = this.origin(instanceId);
|
|
let resolved: string;
|
|
try {
|
|
resolved = password ?? (await this.options.resolver.resolve(instanceId));
|
|
} catch (error) {
|
|
if (error instanceof CredentialResolverError) throw new InstanceLoginServiceError(error.code);
|
|
throw error;
|
|
}
|
|
const result = await this.options.client.login(instanceId, origin, resolved);
|
|
return { instanceId, authenticated: result.authenticated, checkedAt: this.now().toISOString() };
|
|
}
|
|
async logout(instanceId: string): Promise<SessionMetadata> {
|
|
await this.options.client.logout(instanceId, this.origin(instanceId));
|
|
return { instanceId, authenticated: false, checkedAt: this.now().toISOString() };
|
|
}
|
|
private origin(instanceId: string): string {
|
|
const row = this.options.db
|
|
.prepare('SELECT base_url FROM instances WHERE id=?')
|
|
.get(instanceId) as { base_url: string } | undefined;
|
|
if (!row) throw new InstanceLoginServiceError('NOT_FOUND');
|
|
return row.base_url;
|
|
}
|
|
}
|