allowlist에 userId, path를 추가하고 u를 제거

This commit is contained in:
2026-08-04 10:45:17 +09:00
parent 8ced9ecf1c
commit 1222e9cb31
3 changed files with 16 additions and 9 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
const CLICK_QUERY_PARAM_ALLOWLIST = ['u'] as const; const CLICK_QUERY_PARAM_ALLOWLIST = ['userId', 'path'] as const;
type ClickQueryParamKey = typeof CLICK_QUERY_PARAM_ALLOWLIST[number]; type ClickQueryParamKey = typeof CLICK_QUERY_PARAM_ALLOWLIST[number];
+9 -4
View File
@@ -403,7 +403,7 @@ describe('recordInstallEvent', () => {
click_id: 'click-merge', click_id: 'click-merge',
link_id: 'link-merge', link_id: 'link-merge',
clicked_at: clickTime, clicked_at: clickTime,
click_query_params: { u: 'abc' }, click_query_params: { userId: 'study3144', path: '/invite', u: 'abc' },
attribution_window_hours: 24, attribution_window_hours: 24,
ip_address: '24.5.10.250', ip_address: '24.5.10.250',
user_agent: user_agent:
@@ -440,12 +440,17 @@ describe('recordInstallEvent', () => {
expect(result.match).not.toBeNull(); expect(result.match).not.toBeNull();
expect(result.deepLinkData.deepLinkParameters).toEqual({ expect(result.deepLinkData.deepLinkParameters).toEqual({
pid: 'recommend_user', pid: 'recommend_user',
u: 'abc', userId: 'study3144',
path: '/invite',
}); });
expect(result.deepLinkData.customParameters).toEqual({ expect(result.deepLinkData.customParameters).toEqual({
pid: 'recommend_user', pid: 'recommend_user',
u: 'abc', userId: 'study3144',
path: '/invite',
});
expect(result.deepLinkData.clickQueryParameters).toEqual({
userId: 'study3144',
path: '/invite',
}); });
expect(result.deepLinkData.clickQueryParameters).toEqual({ u: 'abc' });
}); });
}); });
+6 -4
View File
@@ -1,5 +1,6 @@
import crypto from 'crypto'; import crypto from 'crypto';
import { db } from './database.js'; import { db } from './database.js';
import { extractAllowedClickQueryParams } from './click-query-params.js';
/** /**
* Device fingerprint data structure * Device fingerprint data structure
@@ -263,13 +264,14 @@ function normalizeClickQueryParams(value: unknown): Record<string, string> {
if (typeof source !== 'object' || Array.isArray(source)) return {}; if (typeof source !== 'object' || Array.isArray(source)) return {};
const result: Record<string, string> = {}; const queryLike: Record<string, string | undefined> = {};
for (const [k, v] of Object.entries(source as Record<string, unknown>)) { for (const [k, v] of Object.entries(source as Record<string, unknown>)) {
if (typeof v === 'string') { if (typeof v === 'string' && v.length > 0) {
result[k] = v; queryLike[k] = v;
} }
} }
return result;
return extractAllowedClickQueryParams(queryLike);
} }
function scoreFingerprintMatch( function scoreFingerprintMatch(