UNPKG

@udene/react-native-sdk

Version:

Udene Fraud Detection SDK for React Native

271 lines (270 loc) 10.7 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.UdeneClient = void 0; const axios_1 = __importDefault(require("axios")); const react_native_1 = require("react-native"); const async_storage_1 = __importDefault(require("@react-native-async-storage/async-storage")); /** * Main client for Udene fraud detection services */ class UdeneClient { /** * Creates a new UdeneClient instance * * @param config - Configuration options or API key string */ constructor(configOrApiKey) { this.SDK_VERSION = '1.0.0'; this.STORAGE_KEY = '@udene/device-fingerprint'; // Handle string API key or config object const config = typeof configOrApiKey === 'string' ? { apiKey: configOrApiKey } : configOrApiKey; if (!config.apiKey) { throw new Error('API key is required'); } // Set configuration with defaults this.platform = config.platform || react_native_1.Platform.OS || 'react-native'; this.maxRetries = config.maxRetries || 3; this.disableLogging = config.disableLogging || false; this.logger = config.logger || ((message, error) => { if (!this.disableLogging) { console.warn(message, error); } }); // Create axios client with interceptors for retries and security this.client = axios_1.default.create({ baseURL: config.baseURL || 'https://api.udene.net/v1', headers: { 'Authorization': `Bearer ${config.apiKey}`, 'Content-Type': 'application/json', 'X-Udene-SDK': `react-native-sdk/${this.SDK_VERSION}`, 'X-Udene-Platform': this.platform } }); // Add request interceptor for logging this.client.interceptors.request.use((config) => { if (!this.disableLogging) { this.logger(`Request to ${config.url}`); } return config; }, (error) => { this.logger('Request error', error); return Promise.reject(error); }); // Add response interceptor for retries and logging this.client.interceptors.response.use((response) => { if (!this.disableLogging) { this.logger(`Response from ${response.config.url}: ${response.status}`); } return response; }, (error) => __awaiter(this, void 0, void 0, function* () { var _a; // Get the original request config const originalRequest = error.config; // If we haven't set a retry count yet, initialize it if (originalRequest && !originalRequest._retryCount) { originalRequest._retryCount = 0; } // Check if we should retry the request if (originalRequest && originalRequest._retryCount < this.maxRetries && (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) >= 500 || error.code === 'ECONNABORTED')) { originalRequest._retryCount++; // Exponential backoff delay const delay = Math.pow(2, originalRequest._retryCount) * 100; this.logger(`Retrying request (${originalRequest._retryCount}/${this.maxRetries}) after ${delay}ms`); return new Promise((resolve) => { setTimeout(() => resolve(this.client(originalRequest)), delay); }); } this.handleError(error); return Promise.reject(error); })); } /** * Sanitize data by removing sensitive fields and validating inputs * * @param data - Data to sanitize * @returns Sanitized data * @private */ sanitizeData(data) { // Create a deep copy to avoid modifying the original const sanitized = JSON.parse(JSON.stringify(data)); // Remove sensitive fields that should never be sent const sensitiveFields = ['password', 'ssn', 'creditCard', 'cvv']; const removeSensitive = (obj) => { if (!obj || typeof obj !== 'object') return; for (const key of Object.keys(obj)) { if (sensitiveFields.includes(key.toLowerCase())) { delete obj[key]; } else if (typeof obj[key] === 'object') { removeSensitive(obj[key]); } } }; removeSensitive(sanitized); return sanitized; } /** * Get fraud metrics * * @returns Promise with metrics data */ getMetrics() { return __awaiter(this, void 0, void 0, function* () { try { const response = yield this.client.get('/metrics'); return response.data; } catch (error) { this.handleError(error); throw error; } }); } /** * Analyze email for Business Email Compromise (BEC) threats * * @param emailData - Email data to analyze * @returns Promise with analysis results */ analyzeBEC(emailData) { return __awaiter(this, void 0, void 0, function* () { try { const sanitizedData = this.sanitizeData(emailData); const response = yield this.client.post('/analyze/bec', sanitizedData); return response.data; } catch (error) { this.handleError(error); throw error; } }); } /** * Track user interaction for fraud analysis * * @param data - Interaction data to track * @returns Promise with tracking results */ trackInteraction(data) { return __awaiter(this, void 0, void 0, function* () { try { const sanitizedData = this.sanitizeData(data); const response = yield this.client.post('/track', sanitizedData); return response.data; } catch (error) { this.handleError(error); throw error; } }); } /** * Get user activity data * * @returns Promise with activity data */ getActivity() { return __awaiter(this, void 0, void 0, function* () { try { const response = yield this.client.get('/activity'); return response.data; } catch (error) { this.handleError(error); throw error; } }); } /** * Analyze a transaction for fraud detection * * @param transactionData - Transaction data to analyze * @returns Promise with analysis results including recommendation */ analyzeTransaction(transactionData) { return __awaiter(this, void 0, void 0, function* () { try { const sanitizedData = this.sanitizeData(transactionData); const response = yield this.client.post('/analyze/transaction', sanitizedData); return response.data; } catch (error) { this.handleError(error); throw error; } }); } /** * Get device fingerprint information * * @returns Promise with device fingerprint data */ getDeviceFingerprint() { return __awaiter(this, void 0, void 0, function* () { try { // Try to get cached fingerprint first const cachedFingerprint = yield async_storage_1.default.getItem(this.STORAGE_KEY); if (cachedFingerprint) { const fingerprintData = JSON.parse(cachedFingerprint); const cacheAge = Date.now() - fingerprintData.timestamp; // Use cached fingerprint if it's less than 24 hours old if (cacheAge < 24 * 60 * 60 * 1000) { return fingerprintData.data; } } // Get fresh fingerprint from API const response = yield this.client.get('/device/fingerprint'); // Cache the fingerprint yield async_storage_1.default.setItem(this.STORAGE_KEY, JSON.stringify({ data: response.data, timestamp: Date.now() })); return response.data; } catch (error) { this.handleError(error); throw error; } }); } /** * Handle API errors * * @param error - Error object from API request * @private */ handleError(error) { var _a, _b, _c, _d, _e, _f, _g; if (axios_1.default.isAxiosError(error)) { // Create a sanitized error object that doesn't expose sensitive details const sanitizedError = { status: (_a = error.response) === null || _a === void 0 ? void 0 : _a.status, message: ((_d = (_c = (_b = error.response) === null || _b === void 0 ? void 0 : _b.data) === null || _c === void 0 ? void 0 : _c.error) === null || _d === void 0 ? void 0 : _d.message) || 'An error occurred', code: ((_g = (_f = (_e = error.response) === null || _e === void 0 ? void 0 : _e.data) === null || _f === void 0 ? void 0 : _f.error) === null || _g === void 0 ? void 0 : _g.code) || 'unknown_error' }; this.logger('API Error', sanitizedError); } else { this.logger('Non-API Error', { message: error.message }); } } } exports.UdeneClient = UdeneClient;