metis-desk/apps/server/src/infrastructure/http/relationship-read-access.ts

51 lines
1.7 KiB
TypeScript
Raw Normal View History

2026-10-20 11:20:22 +00:00
import type { IdentityContext } from "@metis/identity/module";
import type { RelationshipContext, RelationshipReadAccess } from "@metis/relationship-contracts";
import { RelationshipContextSchema, RelationshipReadError } from "@metis/relationship-contracts";
import { Result } from "@repo/rdx-utils";
/** Contextos emitidos desde sesión; copiar sus campos no produce una credencial válida. */
export class SessionRelationshipReadAccess implements RelationshipReadAccess {
private readonly sessions = new WeakMap<RelationshipContext, IdentityContext>();
constructor(
private readonly isAuthenticated: (session: IdentityContext) => Promise<boolean>,
private readonly companyExists: (companyId: string) => Promise<boolean>
) {}
async createContext(session: IdentityContext, companyId: string, requestId: string) {
const parsed = RelationshipContextSchema.safeParse({
operatorId: session.userId,
companyId,
requestId,
});
if (
!(
parsed.success &&
(await this.isAuthenticated(session)) &&
(await this.companyExists(parsed.data.companyId))
)
) {
return Result.fail(new RelationshipReadError("FORBIDDEN"));
}
this.sessions.set(parsed.data, Object.freeze({ ...session }));
return Result.ok(parsed.data);
}
async authorize(context: RelationshipContext): Promise<Result<true, RelationshipReadError>> {
const session = this.sessions.get(context);
if (
!session ||
session.userId !== context.operatorId ||
!(await this.isAuthenticated(session)) ||
!(await this.companyExists(context.companyId))
) {
return Result.fail(new RelationshipReadError("FORBIDDEN"));
}
return Result.ok(true);
}
}