@adstage/web-sdk 2.4.11 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs.js +126 -460
- package/dist/index.d.ts +3 -27
- package/dist/index.esm.js +126 -460
- package/dist/index.standalone.js +126 -460
- package/package.json +1 -1
- package/src/managers/ads/advertisement-event-tracker.ts +27 -36
- package/src/managers/ads/viewability-tracker.ts +16 -140
- package/src/managers/ads/viewable-event-tracker.ts +10 -82
- package/src/modules/ads/AdRenderer.ts +1 -1
- package/src/modules/ads/AdsModule.ts +45 -93
- package/src/utils/version.ts +23 -0
- package/src/managers/ads/basic-fraud-detector.ts +0 -191
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AdStage SDK - 버전 정보 유틸리티
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// package.json에서 버전 정보 가져오기 (빌드 시 자동으로 교체됨)
|
|
6
|
+
export const SDK_VERSION = '__SDK_VERSION__';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* SDK 버전 정보 반환
|
|
10
|
+
*/
|
|
11
|
+
export function getSDKVersion(): string {
|
|
12
|
+
return SDK_VERSION;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 버전 정보가 포함된 User-Agent 문자열 생성
|
|
17
|
+
*/
|
|
18
|
+
export function getSDKUserAgent(): string {
|
|
19
|
+
if (typeof navigator !== 'undefined') {
|
|
20
|
+
return `${navigator.userAgent} AdStageSDK/${SDK_VERSION}`;
|
|
21
|
+
}
|
|
22
|
+
return `AdStageSDK/${SDK_VERSION}`;
|
|
23
|
+
}
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* BasicFraudDetector - 현실적 구현 버전
|
|
3
|
-
* 기본적인 봇 탐지 및 간단한 행동 패턴 분석
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export interface FraudScore {
|
|
7
|
-
score: number; // 0-100
|
|
8
|
-
riskLevel: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
|
|
9
|
-
reasons: string[];
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface BasicBrowserInfo {
|
|
13
|
-
userAgent: string;
|
|
14
|
-
language: string;
|
|
15
|
-
platform: string;
|
|
16
|
-
cookieEnabled: boolean;
|
|
17
|
-
doNotTrack: string | null;
|
|
18
|
-
timezone: string;
|
|
19
|
-
screenResolution: string;
|
|
20
|
-
viewportSize: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export class BasicFraudDetector {
|
|
24
|
-
private startTime: number;
|
|
25
|
-
private mouseEvents: number = 0;
|
|
26
|
-
private keyboardEvents: number = 0;
|
|
27
|
-
private scrollEvents: number = 0;
|
|
28
|
-
|
|
29
|
-
constructor() {
|
|
30
|
-
this.startTime = Date.now();
|
|
31
|
-
this.initBasicTracking();
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
private initBasicTracking(): void {
|
|
35
|
-
// 기본적인 사용자 상호작용 추적
|
|
36
|
-
document.addEventListener('mousemove', () => this.mouseEvents++, { passive: true });
|
|
37
|
-
document.addEventListener('keydown', () => this.keyboardEvents++, { passive: true });
|
|
38
|
-
document.addEventListener('scroll', () => this.scrollEvents++, { passive: true });
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
public calculateFraudScore(): FraudScore {
|
|
42
|
-
let score = 0;
|
|
43
|
-
const reasons: string[] = [];
|
|
44
|
-
|
|
45
|
-
// 1. 웹드라이버 탐지 (기본)
|
|
46
|
-
if (this.detectWebDriver()) {
|
|
47
|
-
score += 50;
|
|
48
|
-
reasons.push('WebDriver detected');
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// 2. 헤드리스 브라우저 기본 탐지
|
|
52
|
-
if (this.detectBasicHeadless()) {
|
|
53
|
-
score += 40;
|
|
54
|
-
reasons.push('Headless browser signatures');
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// 3. 사용자 상호작용 부족
|
|
58
|
-
const sessionTime = Date.now() - this.startTime;
|
|
59
|
-
if (sessionTime > 5000) { // 5초 이상 경과
|
|
60
|
-
if (this.mouseEvents === 0) {
|
|
61
|
-
score += 20;
|
|
62
|
-
reasons.push('No mouse interaction');
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (this.scrollEvents === 0 && sessionTime > 10000) {
|
|
66
|
-
score += 15;
|
|
67
|
-
reasons.push('No scroll activity');
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// 4. 브라우저 환경 이상 징후
|
|
72
|
-
const browserCheck = this.checkBrowserEnvironment();
|
|
73
|
-
score += browserCheck.score;
|
|
74
|
-
reasons.push(...browserCheck.reasons);
|
|
75
|
-
|
|
76
|
-
// 5. 시간 패턴 이상 (너무 빠른 페이지 로드 후 즉시 클릭)
|
|
77
|
-
if (sessionTime < 1000) {
|
|
78
|
-
score += 25;
|
|
79
|
-
reasons.push('Suspiciously fast interaction');
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const finalScore = Math.min(score, 100);
|
|
83
|
-
|
|
84
|
-
return {
|
|
85
|
-
score: finalScore,
|
|
86
|
-
riskLevel: this.getRiskLevel(finalScore),
|
|
87
|
-
reasons: reasons
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
private detectWebDriver(): boolean {
|
|
92
|
-
// 기본적인 웹드라이버 탐지
|
|
93
|
-
return !!(
|
|
94
|
-
(window as any).webdriver ||
|
|
95
|
-
(navigator as any).webdriver ||
|
|
96
|
-
(window as any).__webdriver_evaluate ||
|
|
97
|
-
(window as any).__selenium_evaluate ||
|
|
98
|
-
(window as any).__webdriver_script_function ||
|
|
99
|
-
(window as any).__webdriver_script_func ||
|
|
100
|
-
(window as any).__webdriver_script_fn ||
|
|
101
|
-
(window as any).__fxdriver_evaluate ||
|
|
102
|
-
(window as any).__driver_unwrapped ||
|
|
103
|
-
(window as any).__webdriver_unwrapped ||
|
|
104
|
-
(window as any).__driver_evaluate ||
|
|
105
|
-
(window as any).__selenium_unwrapped ||
|
|
106
|
-
(window as any).__fxdriver_unwrapped
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
private detectBasicHeadless(): boolean {
|
|
111
|
-
const signatures: string[] = [];
|
|
112
|
-
|
|
113
|
-
// PhantomJS 탐지
|
|
114
|
-
if ((window as any)._phantom || (window as any).phantom) {
|
|
115
|
-
signatures.push('PhantomJS');
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Chrome headless 기본 탐지
|
|
119
|
-
if (navigator.userAgent.includes('HeadlessChrome')) {
|
|
120
|
-
signatures.push('Chrome Headless');
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// 플러그인 없음 (일반적이지 않음)
|
|
124
|
-
if (navigator.plugins.length === 0) {
|
|
125
|
-
signatures.push('No plugins');
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return signatures.length > 0;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
private checkBrowserEnvironment(): { score: number; reasons: string[] } {
|
|
132
|
-
let score = 0;
|
|
133
|
-
const reasons: string[] = [];
|
|
134
|
-
|
|
135
|
-
// 언어 설정 이상
|
|
136
|
-
if (!navigator.language || navigator.language === 'C') {
|
|
137
|
-
score += 10;
|
|
138
|
-
reasons.push('Unusual language setting');
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// 쿠키 비활성화
|
|
142
|
-
if (!navigator.cookieEnabled) {
|
|
143
|
-
score += 15;
|
|
144
|
-
reasons.push('Cookies disabled');
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// 화면 해상도 이상
|
|
148
|
-
if (screen.width === 0 || screen.height === 0) {
|
|
149
|
-
score += 20;
|
|
150
|
-
reasons.push('Invalid screen resolution');
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// 시간대 정보 없음
|
|
154
|
-
try {
|
|
155
|
-
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
156
|
-
if (!timezone || timezone === 'UTC') {
|
|
157
|
-
score += 5;
|
|
158
|
-
reasons.push('No timezone info');
|
|
159
|
-
}
|
|
160
|
-
} catch (e) {
|
|
161
|
-
score += 10;
|
|
162
|
-
reasons.push('Timezone detection failed');
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return { score, reasons };
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
private getRiskLevel(score: number): 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL' {
|
|
169
|
-
if (score >= 70) return 'CRITICAL';
|
|
170
|
-
if (score >= 50) return 'HIGH';
|
|
171
|
-
if (score >= 30) return 'MEDIUM';
|
|
172
|
-
return 'LOW';
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
public getBrowserInfo(): BasicBrowserInfo {
|
|
176
|
-
return {
|
|
177
|
-
userAgent: navigator.userAgent,
|
|
178
|
-
language: navigator.language,
|
|
179
|
-
platform: navigator.platform,
|
|
180
|
-
cookieEnabled: navigator.cookieEnabled,
|
|
181
|
-
doNotTrack: navigator.doNotTrack,
|
|
182
|
-
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
183
|
-
screenResolution: `${screen.width}x${screen.height}`,
|
|
184
|
-
viewportSize: `${window.innerWidth}x${window.innerHeight}`
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
public destroy(): void {
|
|
189
|
-
// 이벤트 리스너 정리는 생략 (메모리 누수 방지를 위해 필요시 구현)
|
|
190
|
-
}
|
|
191
|
-
}
|