UNPKG

@tracetail/angular

Version:

Angular SDK for TraceTail browser fingerprinting - over 99.5% accuracy

179 lines 19.3 kB
import { Injectable, Inject } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; import TraceTail from '@tracetail/js'; import { TRACETAIL_CONFIG } from './tracetail.config'; import * as i0 from "@angular/core"; export class TraceTailService { config; client; fingerprintSubject = new BehaviorSubject(null); loadingSubject = new BehaviorSubject(true); errorSubject = new BehaviorSubject(null); fingerprint$ = this.fingerprintSubject.asObservable(); loading$ = this.loadingSubject.asObservable(); error$ = this.errorSubject.asObservable(); constructor(config) { this.config = config; this.initializeClient(); } initializeClient() { try { // Handle test mode if (this.config.config?.testMode && this.config.config.mockData) { this.fingerprintSubject.next({ visitorId: 'mock-visitor-123', confidence: 0.99, riskScore: 0.1, fraudulent: false, signals: {}, timestamp: new Date(), ...this.config.config.mockData }); this.loadingSubject.next(false); return; } // Initialize real client this.client = new TraceTail({ apiKey: this.config.apiKey, timeout: this.config.config?.timeout, debug: this.config.config?.debug || false }); // Get initial fingerprint this.loadFingerprint(); } catch (error) { this.handleError(error); } } async loadFingerprint() { try { this.loadingSubject.next(true); this.errorSubject.next(null); const result = await this.client.generateFingerprint(); const fingerprint = { visitorId: result.visitorId, confidence: result.confidence, riskScore: 0, fraudulent: false, signals: result.components || {}, timestamp: new Date() }; this.fingerprintSubject.next(fingerprint); this.loadingSubject.next(false); } catch (error) { this.handleError(error); } } handleError(error) { console.error('TraceTail error:', error); this.errorSubject.next(error); this.loadingSubject.next(false); } /** * Get current fingerprint as a promise */ async getFingerprint() { const current = this.fingerprintSubject.value; if (current) { return current; } // Wait for fingerprint to be loaded return new Promise((resolve, reject) => { const subscription = this.fingerprint$.subscribe({ next: (fingerprint) => { if (fingerprint) { subscription.unsubscribe(); resolve(fingerprint); } }, error: (error) => { subscription.unsubscribe(); reject(error); } }); }); } /** * Track an event */ async trackEvent(event, data) { try { // TraceTail doesn't have a track method - this is custom app functionality // For now, just return mock data with a generated event ID const eventId = `evt_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; return { success: true, fraudulent: false, riskScore: 0, eventId: eventId }; } catch (error) { console.error('Track event error:', error); throw error; } } /** * Check for fraud */ async checkFraud(data) { try { const fingerprint = await this.getFingerprint(); // Simple fraud detection logic based on risk score const block = fingerprint.riskScore > 0.8; const challenge = fingerprint.riskScore > 0.5 && fingerprint.riskScore <= 0.8; const allow = fingerprint.riskScore <= 0.5; const reasons = []; if (fingerprint.signals.vpn) reasons.push('VPN detected'); if (fingerprint.signals.tor) reasons.push('Tor browser detected'); if (fingerprint.signals.proxy) reasons.push('Proxy detected'); if (fingerprint.riskScore > 0.7) reasons.push('High risk score'); return { block, challenge, allow, riskScore: fingerprint.riskScore, reasons }; } catch (error) { console.error('Fraud check error:', error); throw error; } } /** * Retry fingerprinting */ retry() { this.loadFingerprint(); } /** * Force refresh fingerprint */ async refresh() { await this.loadFingerprint(); } /** * Get raw TraceTail client instance */ getClient() { return this.client; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TraceTailService, deps: [{ token: TRACETAIL_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TraceTailService, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TraceTailService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: undefined, decorators: [{ type: Inject, args: [TRACETAIL_CONFIG] }] }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhY2V0YWlsLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL3RyYWNldGFpbC5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ25ELE9BQU8sRUFBRSxlQUFlLEVBQXdCLE1BQU0sTUFBTSxDQUFDO0FBRTdELE9BQU8sU0FBUyxNQUFNLGVBQWUsQ0FBQztBQUN0QyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQzs7QUFXdEQsTUFBTSxPQUFPLGdCQUFnQjtJQVVtQjtJQVR0QyxNQUFNLENBQVk7SUFDbEIsa0JBQWtCLEdBQUcsSUFBSSxlQUFlLENBQXFCLElBQUksQ0FBQyxDQUFDO0lBQ25FLGNBQWMsR0FBRyxJQUFJLGVBQWUsQ0FBVSxJQUFJLENBQUMsQ0FBQztJQUNwRCxZQUFZLEdBQUcsSUFBSSxlQUFlLENBQWUsSUFBSSxDQUFDLENBQUM7SUFFL0QsWUFBWSxHQUFHLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUN0RCxRQUFRLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUM5QyxNQUFNLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUUxQyxZQUE4QyxNQUF1QjtRQUF2QixXQUFNLEdBQU4sTUFBTSxDQUFpQjtRQUNuRSxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztJQUMxQixDQUFDO0lBRU8sZ0JBQWdCO1FBQ3RCLElBQUk7WUFDRixtQkFBbUI7WUFDbkIsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRSxRQUFRLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFO2dCQUMvRCxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDO29C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dGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlLCBJbmplY3QgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCwgT2JzZXJ2YWJsZSwgZnJvbSwgb2YgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IGNhdGNoRXJyb3IsIHNoYXJlUmVwbGF5LCB0YXAgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgVHJhY2VUYWlsIGZyb20gJ0B0cmFjZXRhaWwvanMnO1xuaW1wb3J0IHsgVFJBQ0VUQUlMX0NPTkZJRyB9IGZyb20gJy4vdHJhY2V0YWlsLmNvbmZpZyc7XG5pbXBvcnQgeyBcbiAgVHJhY2VUYWlsQ29uZmlnLCBcbiAgRmluZ2VycHJpbnQsIFxuICBUcmFja2luZ1Jlc3VsdCwgXG4gIEZyYXVkUmVzdWx0IFxufSBmcm9tICcuL3RyYWNldGFpbC50eXBlcyc7XG5cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXG59KVxuZXhwb3J0IGNsYXNzIFRyYWNlVGFpbFNlcnZpY2Uge1xuICBwcml2YXRlIGNsaWVudDogVHJhY2VUYWlsO1xuICBwcml2YXRlIGZpbmdlcnByaW50U3ViamVjdCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8RmluZ2VycHJpbnQgfCBudWxsPihudWxsKTtcbiAgcHJpdmF0ZSBsb2FkaW5nU3ViamVjdCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4odHJ1ZSk7XG4gIHByaXZhdGUgZXJyb3JTdWJqZWN0ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxFcnJvciB8IG51bGw+KG51bGwpO1xuXG4gIGZpbmdlcnByaW50JCA9IHRoaXMuZmluZ2VycHJpbnRTdWJqZWN0LmFzT2JzZXJ2YWJsZSgpO1xuICBsb2FkaW5nJCA9IHRoaXMubG9hZGluZ1N1YmplY3QuYXNPYnNlcnZhYmxlKCk7XG4gIGVycm9yJCA9IHRoaXMuZXJyb3JTdWJqZWN0LmFzT2JzZXJ2YWJsZSgpO1xuXG4gIGNvbnN0cnVjdG9yKEBJbmplY3QoVFJBQ0VUQUlMX0NPTkZJRykgcHJpdmF0ZSBjb25maWc6IFRyYWNlVGFpbENvbmZpZykge1xuICAgIHRoaXMuaW5pdGlhbGl6ZUNsaWVudCgpO1xuICB9XG5cbiAgcHJpdmF0ZSBpbml0aWFsaXplQ2xpZW50KCk6IHZvaWQge1xuICAgIHRyeSB7XG4gICAgICAvLyBIYW5kbGUgdGVzdCBtb2RlXG4gICAgICBpZiAodGhpcy5jb25maWcuY29uZmlnPy50ZXN0TW9kZSAmJiB0aGlzLmNvbmZpZy5jb25maWcubW9ja0RhdGEpIHtcbiAgICAgICAgdGhpcy5maW5nZXJwcmludFN1YmplY3QubmV4dCh7XG4gICAgICAgICAgdmlzaXRvcklkOiAnbW9jay12aXNpdG9yLTEyMycsXG4gICAgICAgICAgY29uZmlkZW5jZTogMC45OSxcbiAgICAgICAgICByaXNrU2NvcmU6IDAuMSxcbiAgICAgICAgICBmcmF1ZHVsZW50OiBmYWxzZSxcbiAgICAgICAgICBzaWduYWxzOiB7fSBhcyBhbnksXG4gICAgICAgICAgdGltZXN0YW1wOiBuZXcgRGF0ZSgpLFxuICAgICAgICAgIC4uLnRoaXMuY29uZmlnLmNvbmZpZy5tb2NrRGF0YVxuICAgICAgICB9IGFzIEZpbmdlcnByaW50KTtcbiAgICAgICAgdGhpcy5sb2FkaW5nU3ViamVjdC5uZXh0KGZhbHNlKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICAvLyBJbml0aWFsaXplIHJlYWwgY2xpZW50XG4gICAgICB0aGlzLmNsaWVudCA9IG5ldyBUcmFjZVRhaWwoe1xuICAgICAgICBhcGlLZXk6IHRoaXMuY29uZmlnLmFwaUtleSxcbiAgICAgICAgdGltZW91dDogdGhpcy5jb25maWcuY29uZmlnPy50aW1lb3V0LFxuICAgICAgICBkZWJ1ZzogdGhpcy5jb25maWcuY29uZmlnPy5kZWJ1ZyB8fCBmYWxzZVxuICAgICAgfSk7XG5cbiAgICAgIC8vIEdldCBpbml0aWFsIGZpbmdlcnByaW50XG4gICAgICB0aGlzLmxvYWRGaW5nZXJwcmludCgpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aGlzLmhhbmRsZUVycm9yKGVycm9yIGFzIEVycm9yKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGxvYWRGaW5nZXJwcmludCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0cnkge1xuICAgICAgdGhpcy5sb2FkaW5nU3ViamVjdC5uZXh0KHRydWUpO1xuICAgICAgdGhpcy5lcnJvclN1YmplY3QubmV4dChudWxsKTtcblxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5jbGllbnQuZ2VuZXJhdGVGaW5nZXJwcmludCgpO1xuICAgICAgXG4gICAgICBjb25zdCBmaW5nZXJwcmludDogRmluZ2VycHJpbnQgPSB7XG4gICAgICAgIHZpc2l0b3JJZDogcmVzdWx0LnZpc2l0b3JJZCxcbiAgICAgICAgY29uZmlkZW5jZTogcmVzdWx0LmNvbmZpZGVuY2UsXG4gICAgICAgIHJpc2tTY29yZTogMCwgIC8vIERlZmF1bHQgdmFsdWUgLSBub3QgaW4gYmFzZSBTREtcbiAgICAgICAgZnJhdWR1bGVudDogZmFsc2UsICAvLyBEZWZhdWx0IHZhbHVlIC0gbm90IGluIGJhc2UgU0RLICBcbiAgICAgICAgc2lnbmFsczogcmVzdWx0LmNvbXBvbmVudHMgfHwge30gYXMgYW55LFxuICAgICAgICB0aW1lc3RhbXA6IG5ldyBEYXRlKClcbiAgICAgIH07XG5cbiAgICAgIHRoaXMuZmluZ2VycHJpbnRTdWJqZWN0Lm5leHQoZmluZ2VycHJpbnQpO1xuICAgICAgdGhpcy5sb2FkaW5nU3ViamVjdC5uZXh0KGZhbHNlKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhpcy5oYW5kbGVFcnJvcihlcnJvciBhcyBFcnJvcik7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBoYW5kbGVFcnJvcihlcnJvcjogRXJyb3IpOiB2b2lkIHtcbiAgICBjb25zb2xlLmVycm9yKCdUcmFjZVRhaWwgZXJyb3I6JywgZXJyb3IpO1xuICAgIHRoaXMuZXJyb3JTdWJqZWN0Lm5leHQoZXJyb3IpO1xuICAgIHRoaXMubG9hZGluZ1N1YmplY3QubmV4dChmYWxzZSk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGN1cnJlbnQgZmluZ2VycHJpbnQgYXMgYSBwcm9taXNlXG4gICAqL1xuICBhc3luYyBnZXRGaW5nZXJwcmludCgpOiBQcm9taXNlPEZpbmdlcnByaW50PiB7XG4gICAgY29uc3QgY3VycmVudCA9IHRoaXMuZmluZ2VycHJpbnRTdWJqZWN0LnZhbHVlO1xuICAgIGlmIChjdXJyZW50KSB7XG4gICAgICByZXR1cm4gY3VycmVudDtcbiAgICB9XG5cbiAgICAvLyBXYWl0IGZvciBmaW5nZXJwcmludCB0byBiZSBsb2FkZWRcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgY29uc3Qgc3Vic2NyaXB0aW9uID0gdGhpcy5maW5nZXJwcmludCQuc3Vic2NyaWJlKHtcbiAgICAgICAgbmV4dDogKGZpbmdlcnByaW50KSA9PiB7XG4gICAgICAgICAgaWYgKGZpbmdlcnByaW50KSB7XG4gICAgICAgICAgICBzdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgICAgICAgICAgIHJlc29sdmUoZmluZ2VycHJpbnQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgZXJyb3I6IChlcnJvcikgPT4ge1xuICAgICAgICAgIHN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuICAgICAgICAgIHJlamVjdChlcnJvcik7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFRyYWNrIGFuIGV2ZW50XG4gICAqL1xuICBhc3luYyB0cmFja0V2ZW50KGV2ZW50OiBzdHJpbmcsIGRhdGE/OiBhbnkpOiBQcm9taXNlPFRyYWNraW5nUmVzdWx0PiB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIFRyYWNlVGFpbCBkb2Vzbid0IGhhdmUgYSB0cmFjayBtZXRob2QgLSB0aGlzIGlzIGN1c3RvbSBhcHAgZnVuY3Rpb25hbGl0eVxuICAgICAgLy8gRm9yIG5vdywganVzdCByZXR1cm4gbW9jayBkYXRhIHdpdGggYSBnZW5lcmF0ZWQgZXZlbnQgSURcbiAgICAgIGNvbnN0IGV2ZW50SWQgPSBgZXZ0XyR7RGF0ZS5ub3coKX1fJHtNYXRoLnJhbmRvbSgpLnRvU3RyaW5nKDM2KS5zdWJzdHIoMiwgOSl9YDtcbiAgICAgIFxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgICAgZnJhdWR1bGVudDogZmFsc2UsXG4gICAgICAgIHJpc2tTY29yZTogMCxcbiAgICAgICAgZXZlbnRJZDogZXZlbnRJZFxuICAgICAgfTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcignVHJhY2sgZXZlbnQgZXJyb3I6JywgZXJyb3IpO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrIGZvciBmcmF1ZFxuICAgKi9cbiAgYXN5bmMgY2hlY2tGcmF1ZChkYXRhOiBhbnkpOiBQcm9taXNlPEZyYXVkUmVzdWx0PiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGZpbmdlcnByaW50ID0gYXdhaXQgdGhpcy5nZXRGaW5nZXJwcmludCgpO1xuICAgICAgXG4gICAgICAvLyBTaW1wbGUgZnJhdWQgZGV0ZWN0aW9uIGxvZ2ljIGJhc2VkIG9uIHJpc2sgc2NvcmVcbiAgICAgIGNvbnN0IGJsb2NrID0gZmluZ2VycHJpbnQucmlza1Njb3JlID4gMC44O1xuICAgICAgY29uc3QgY2hhbGxlbmdlID0gZmluZ2VycHJpbnQucmlza1Njb3JlID4gMC41ICYmIGZpbmdlcnByaW50LnJpc2tTY29yZSA8PSAwLjg7XG4gICAgICBjb25zdCBhbGxvdyA9IGZpbmdlcnByaW50LnJpc2tTY29yZSA8PSAwLjU7XG4gICAgICBcbiAgICAgIGNvbnN0IHJlYXNvbnM6IHN0cmluZ1tdID0gW107XG4gICAgICBpZiAoZmluZ2VycHJpbnQuc2lnbmFscy52cG4pIHJlYXNvbnMucHVzaCgnVlBOIGRldGVjdGVkJyk7XG4gICAgICBpZiAoZmluZ2VycHJpbnQuc2lnbmFscy50b3IpIHJlYXNvbnMucHVzaCgnVG9yIGJyb3dzZXIgZGV0ZWN0ZWQnKTtcbiAgICAgIGlmIChmaW5nZXJwcmludC5zaWduYWxzLnByb3h5KSByZWFzb25zLnB1c2goJ1Byb3h5IGRldGVjdGVkJyk7XG4gICAgICBpZiAoZmluZ2VycHJpbnQucmlza1Njb3JlID4gMC43KSByZWFzb25zLnB1c2goJ0hpZ2ggcmlzayBzY29yZScpO1xuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBibG9jayxcbiAgICAgICAgY2hhbGxlbmdlLFxuICAgICAgICBhbGxvdyxcbiAgICAgICAgcmlza1Njb3JlOiBmaW5nZXJwcmludC5yaXNrU2NvcmUsXG4gICAgICAgIHJlYXNvbnNcbiAgICAgIH07XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ0ZyYXVkIGNoZWNrIGVycm9yOicsIGVycm9yKTtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZXRyeSBmaW5nZXJwcmludGluZ1xuICAgKi9cbiAgcmV0cnkoKTogdm9pZCB7XG4gICAgdGhpcy5sb2FkRmluZ2VycHJpbnQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGb3JjZSByZWZyZXNoIGZpbmdlcnByaW50XG4gICAqL1xuICBhc3luYyByZWZyZXNoKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMubG9hZEZpbmdlcnByaW50KCk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHJhdyBUcmFjZVRhaWwgY2xpZW50IGluc3RhbmNlXG4gICAqL1xuICBnZXRDbGllbnQoKTogVHJhY2VUYWlsIHtcbiAgICByZXR1cm4gdGhpcy5jbGllbnQ7XG4gIH1cbn0iXX0=