광고 추가 보상 서버 시청 검증 · 사용자 퀘스트 승인 후 공개 · TIME ATTACK 모드 · 만보기 퀘스트 · 위치 퀘스트 지도 선택 · 운영 퀘스트 보상 재원

This commit is contained in:
Sn-Kinos
2026-10-05 22:48:09 +09:00
parent 4bb92c2ee7
commit fbf9a2c3d7
39 changed files with 1871 additions and 477 deletions
@@ -0,0 +1,27 @@
import { createSign, generateKeyPairSync } from 'node:crypto';
import { describe, expect, it } from 'vitest';
import { verifySsv } from '../src/quest/ad_ssv.js';
/** AdMob SSV 서명 검증(fn-ad-ssv) — 에뮬레이터 없이 도는 순수 검증. */
describe('AdMob SSV 서명 검증', () => {
const { privateKey, publicKey } = generateKeyPairSync('ec', { namedCurve: 'prime256v1' });
const keys = new Map([['42', publicKey.export({ type: 'spki', format: 'pem' }) as string]]);
const sign = (message: string) => createSign('sha256').update(message).sign(privateKey)
.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
const message = 'ad_network=5450213213286189855&ad_unit=1234&custom_data=tx1&reward_amount=1'
+ '&reward_item=Reward&timestamp=1507770365237823&transaction_id=abc&user_id=u1';
it('서명이 맞으면 파라미터를 돌려준다', () => {
const params = verifySsv(`${message}&signature=${sign(message)}&key_id=42`, keys);
expect(params?.get('user_id')).toBe('u1');
expect(params?.get('custom_data')).toBe('tx1');
});
it('값을 바꾸거나 모르는 키 · 서명 없음이면 거부한다', () => {
const sig = sign(message);
expect(verifySsv(`${message.replace('u1', 'u2')}&signature=${sig}&key_id=42`, keys)).toBeNull();
expect(verifySsv(`${message}&signature=${sig}&key_id=7`, keys)).toBeNull();
expect(verifySsv(message, keys)).toBeNull();
});
});