fix: post-M4 validation improvements

- Session: verify server-side iat expiry (not just cookie maxAge)
- Validate ProjectMemberRole on member add (reject arbitrary strings)
- Scope coverage threshold to Repository/Service layers (per guidelines)
- Add session expiry/fresh-token unit tests
This commit is contained in:
Ken Yasue
2026-06-25 01:11:35 +02:00
parent abef2c58d9
commit 3dc0318011
5 changed files with 44 additions and 5 deletions

View File

@ -50,8 +50,15 @@ export function verifySessionToken(token: string): number | null {
try {
const payload = JSON.parse(
Buffer.from(encoded, 'base64url').toString('utf-8')
) as { uid?: unknown };
) as { uid?: unknown; iat?: unknown };
if (typeof payload.uid !== 'number') return null;
// サーバ側でも有効期限を検証する(クッキーのmaxAgeだけに依存しない)
if (
typeof payload.iat !== 'number' ||
Date.now() - payload.iat > SESSION_MAX_AGE_SECONDS * 1000
) {
return null;
}
return payload.uid;
} catch {
return null;

View File

@ -1,5 +1,5 @@
import { ValidationError } from '@/lib/errors';
import type { ProjectStatus } from '@/lib/types';
import type { ProjectMemberRole, ProjectStatus } from '@/lib/types';
const MAX_NAME_LENGTH = 200;
const MAX_DESCRIPTION_LENGTH = 2000;
@ -9,6 +9,7 @@ const VALID_STATUSES: ProjectStatus[] = [
'completed',
'archived',
];
const VALID_MEMBER_ROLES: ProjectMemberRole[] = ['admin', 'member', 'guest'];
export interface ProjectCreateInput {
name: string;
@ -64,3 +65,10 @@ export function validateProjectUpdate(input: ProjectUpdateInput): void {
throw new ValidationError('無効なステータスです', 'status');
}
}
export function validateProjectMemberRole(role: string): ProjectMemberRole {
if (!VALID_MEMBER_ROLES.includes(role as ProjectMemberRole)) {
throw new ValidationError('無効なメンバーロールです', 'role');
}
return role as ProjectMemberRole;
}