feat(context): verify product session scope
This commit is contained in:
@@ -53,6 +53,9 @@ export class SessionMetadataStore {
|
||||
this.filePath(sessionId),
|
||||
);
|
||||
if (existing) {
|
||||
if (!matchesContext(existing, input)) {
|
||||
throw new SessionContextMismatchError();
|
||||
}
|
||||
return { created: false, record: existing };
|
||||
}
|
||||
|
||||
@@ -80,9 +83,10 @@ export class SessionMetadataStore {
|
||||
if (!normalizedSessionId) {
|
||||
return null;
|
||||
}
|
||||
return await readJsonFile<SessionRecord>(
|
||||
const record = await readJsonFile<SessionRecord>(
|
||||
this.filePath(normalizedSessionId),
|
||||
);
|
||||
return record && matchesContext(record, context) ? record : null;
|
||||
}
|
||||
|
||||
async touch(
|
||||
@@ -132,6 +136,18 @@ const normalizeSessionId = (value?: string) => {
|
||||
return normalized ? normalized.slice(0, 128) : undefined;
|
||||
};
|
||||
|
||||
export class SessionContextMismatchError extends Error {
|
||||
constructor() {
|
||||
super("session not found");
|
||||
}
|
||||
}
|
||||
|
||||
const matchesContext = (record: SessionRecord, context: SessionMetadataContext) =>
|
||||
record.actorKey === context.actorKey &&
|
||||
record.projectKey === context.projectKey &&
|
||||
(context.userId === undefined || record.ownerUserId === context.userId) &&
|
||||
(context.projectId === undefined || record.projectId === context.projectId);
|
||||
|
||||
const normalizeSessionUpdates = (
|
||||
updates: Partial<Pick<SessionRecord, "title" | "status">>,
|
||||
) => {
|
||||
|
||||
Reference in New Issue
Block a user