fix(backend): harden runtime config and verification access
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { AppError } from '../lib/errors.js';
|
||||
import { isDatabaseConfigured, query, withTransaction } from './db.js';
|
||||
import { requireTenantContext } from './actor-context.js';
|
||||
import { loadActorContext, requireTenantContext } from './actor-context.js';
|
||||
import { invokeVertexMultimodalModel } from './llm.js';
|
||||
|
||||
export const VerificationStatus = Object.freeze({
|
||||
@@ -95,7 +95,11 @@ async function processVerificationJobInMemory(verificationId) {
|
||||
}
|
||||
|
||||
function accessMode() {
|
||||
return process.env.VERIFICATION_ACCESS_MODE || 'authenticated';
|
||||
const mode = `${process.env.VERIFICATION_ACCESS_MODE || 'tenant'}`.trim().toLowerCase();
|
||||
if (mode === 'owner' || mode === 'tenant' || mode === 'authenticated') {
|
||||
return mode;
|
||||
}
|
||||
return 'tenant';
|
||||
}
|
||||
|
||||
function providerTimeoutMs() {
|
||||
@@ -156,12 +160,27 @@ function toPublicJob(row) {
|
||||
};
|
||||
}
|
||||
|
||||
function assertAccess(row, actorUid) {
|
||||
if (accessMode() === 'authenticated') {
|
||||
async function assertAccess(row, actorUid) {
|
||||
if (row.owner_user_id === actorUid) {
|
||||
return;
|
||||
}
|
||||
if (row.owner_user_id !== actorUid) {
|
||||
throw new AppError('FORBIDDEN', 'Not allowed to access this verification', 403);
|
||||
|
||||
const mode = accessMode();
|
||||
if (mode === 'authenticated') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode === 'owner' || !row.tenant_id) {
|
||||
throw new AppError('FORBIDDEN', 'Not allowed to access this verification', 403, {
|
||||
verificationId: row.id,
|
||||
});
|
||||
}
|
||||
|
||||
const actorContext = await loadActorContext(actorUid);
|
||||
if (actorContext.tenant?.tenantId !== row.tenant_id) {
|
||||
throw new AppError('FORBIDDEN', 'Not allowed to access this verification', 403, {
|
||||
verificationId: row.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -614,19 +633,19 @@ export async function createVerificationJob({ actorUid, payload }) {
|
||||
export async function getVerificationJob(verificationId, actorUid) {
|
||||
if (useMemoryStore()) {
|
||||
const job = loadMemoryJob(verificationId);
|
||||
assertAccess(job, actorUid);
|
||||
await assertAccess(job, actorUid);
|
||||
return toPublicJob(job);
|
||||
}
|
||||
|
||||
const job = await loadJob(verificationId);
|
||||
assertAccess(job, actorUid);
|
||||
await assertAccess(job, actorUid);
|
||||
return toPublicJob(job);
|
||||
}
|
||||
|
||||
export async function reviewVerificationJob(verificationId, actorUid, review) {
|
||||
if (useMemoryStore()) {
|
||||
const job = loadMemoryJob(verificationId);
|
||||
assertAccess(job, actorUid);
|
||||
await assertAccess(job, actorUid);
|
||||
if (HUMAN_TERMINAL_STATUSES.has(job.status)) {
|
||||
throw new AppError('CONFLICT', 'Verification already finalized', 409, {
|
||||
verificationId,
|
||||
@@ -668,7 +687,7 @@ export async function reviewVerificationJob(verificationId, actorUid, review) {
|
||||
}
|
||||
|
||||
const job = result.rows[0];
|
||||
assertAccess(job, actorUid);
|
||||
await assertAccess(job, actorUid);
|
||||
if (HUMAN_TERMINAL_STATUSES.has(job.status)) {
|
||||
throw new AppError('CONFLICT', 'Verification already finalized', 409, {
|
||||
verificationId,
|
||||
@@ -735,7 +754,7 @@ export async function reviewVerificationJob(verificationId, actorUid, review) {
|
||||
export async function retryVerificationJob(verificationId, actorUid) {
|
||||
if (useMemoryStore()) {
|
||||
const job = loadMemoryJob(verificationId);
|
||||
assertAccess(job, actorUid);
|
||||
await assertAccess(job, actorUid);
|
||||
if (job.status === VerificationStatus.PROCESSING) {
|
||||
throw new AppError('CONFLICT', 'Cannot retry while verification is processing', 409, {
|
||||
verificationId,
|
||||
@@ -774,7 +793,7 @@ export async function retryVerificationJob(verificationId, actorUid) {
|
||||
}
|
||||
|
||||
const job = result.rows[0];
|
||||
assertAccess(job, actorUid);
|
||||
await assertAccess(job, actorUid);
|
||||
if (job.status === VerificationStatus.PROCESSING) {
|
||||
throw new AppError('CONFLICT', 'Cannot retry while verification is processing', 409, {
|
||||
verificationId,
|
||||
|
||||
Reference in New Issue
Block a user