mirror of
https://github.com/KuekHaoYang/KVideo.git
synced 2026-08-13 07:43:43 +08:00
Keep every post-59948b5 change inside verification/. The verifier owns its npm working directory and sanitized Docker context, so no release metadata or root Docker configuration is modified.
82 lines
2.7 KiB
TypeScript
82 lines
2.7 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import {
|
|
shouldUseSecureSessionCookie,
|
|
signSessionPayload,
|
|
verifySessionToken,
|
|
} from '../../../lib/server/auth-helpers';
|
|
import {
|
|
hasResolvedPermission,
|
|
hasRoleAtLeast,
|
|
resolvePermissions,
|
|
} from '../../../lib/auth/permissions';
|
|
|
|
// GH-ISSUE: 19,45,48,173,202,204,206; GH-PR: 157,216
|
|
|
|
const mutableEnv = process.env as Record<string, string | undefined>;
|
|
|
|
function withNodeEnv<T>(value: string | undefined, callback: () => T): T {
|
|
const previous = mutableEnv.NODE_ENV;
|
|
if (value === undefined) delete mutableEnv.NODE_ENV;
|
|
else mutableEnv.NODE_ENV = value;
|
|
|
|
try {
|
|
return callback();
|
|
} finally {
|
|
if (previous === undefined) delete mutableEnv.NODE_ENV;
|
|
else mutableEnv.NODE_ENV = previous;
|
|
}
|
|
}
|
|
|
|
function mockRequest(protocol: 'http:' | 'https:', forwardedProtocol?: string) {
|
|
return {
|
|
headers: new Headers(
|
|
forwardedProtocol ? { 'x-forwarded-proto': forwardedProtocol } : undefined,
|
|
),
|
|
nextUrl: { protocol },
|
|
};
|
|
}
|
|
|
|
test('signed sessions round-trip and reject tampering', async () => {
|
|
const token = await signSessionPayload({
|
|
accountId: 'account-1',
|
|
profileId: 'profile-1',
|
|
username: 'alice',
|
|
name: 'Alice',
|
|
role: 'super_admin',
|
|
customPermissions: ['iptv_access'],
|
|
mode: 'managed',
|
|
iat: Date.now(),
|
|
}, 'test-secret');
|
|
|
|
const decoded = await verifySessionToken(token, 'test-secret');
|
|
assert.equal(decoded?.username, 'alice');
|
|
assert.equal(decoded?.mode, 'managed');
|
|
|
|
const parts = token.split('.');
|
|
const tampered = `${parts[0]}.${parts[1]}-tampered.${parts[2]}`;
|
|
assert.equal(await verifySessionToken(tampered, 'test-secret'), null);
|
|
});
|
|
|
|
test('role permissions preserve IPTV management inheritance', () => {
|
|
const permissions = resolvePermissions('viewer', ['iptv_access']);
|
|
assert.ok(permissions.includes('iptv_access'));
|
|
assert.ok(permissions.includes('iptv_source_management'));
|
|
assert.equal(hasResolvedPermission('admin', 'player_settings'), true);
|
|
assert.equal(hasResolvedPermission('viewer', 'account_management'), false);
|
|
assert.equal(hasRoleAtLeast('super_admin', 'admin'), true);
|
|
});
|
|
|
|
test('session cookies are secure only for HTTPS production requests', () => {
|
|
withNodeEnv('production', () => {
|
|
assert.equal(shouldUseSecureSessionCookie(mockRequest('http:')), false);
|
|
assert.equal(shouldUseSecureSessionCookie(mockRequest('https:')), true);
|
|
assert.equal(shouldUseSecureSessionCookie(mockRequest('http:', 'https')), true);
|
|
assert.equal(shouldUseSecureSessionCookie(mockRequest('https:', 'http')), false);
|
|
});
|
|
|
|
withNodeEnv('development', () => {
|
|
assert.equal(shouldUseSecureSessionCookie(mockRequest('https:')), false);
|
|
});
|
|
});
|