@ipranker/sdk
Version:
Professional IP Intelligence and Device Fingerprinting SDK - Comprehensive fraud detection with single API call
3 lines (2 loc) • 20.1 kB
JavaScript
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).IPRanker={})}(this,function(e){"use strict";function t(e){let t=0;for(let n=0;n<e.length;n++)t=Math.imul(31,t)+e.charCodeAt(n)|0;return Math.abs(t).toString(36)}const n=["Arial","Arial Black","Arial Narrow","Calibri","Calibri Light","Cambria","Candara","Century Gothic","Comic Sans MS","Consolas","Constantia","Corbel","Courier New","Ebrima","Franklin Gothic Medium","Gabriola","Gadugi","Georgia","Impact","Ink Free","Javanese Text","Leelawadee UI","Lucida Console","Lucida Sans Unicode","Malgun Gothic","Marlett","Microsoft Himalaya","Microsoft JhengHei","Microsoft New Tai Lue","Microsoft PhagsPa","Microsoft Sans Serif","Microsoft Tai Le","Microsoft YaHei","Microsoft Yi Baiti","MingLiU-ExtB","Mongolian Baiti","MS Gothic","MS PGothic","MS UI Gothic","MV Boli","Myanmar Text","Nirmala UI","Palatino Linotype","Segoe MDL2 Assets","Segoe Print","Segoe Script","Segoe UI","Segoe UI Emoji","Segoe UI Historic","Segoe UI Light","Segoe UI Semibold","Segoe UI Symbol","SimSun","Sitka Banner","Sitka Display","Sitka Heading","Sitka Small","Sitka Subheading","Sitka Text","Sylfaen","Symbol","Tahoma","Times New Roman","Trebuchet MS","Verdana","Webdings","Wingdings","Yu Gothic","Yu Gothic UI","American Typewriter","Andale Mono","Apple Chancery","Apple Color Emoji","Apple SD Gothic Neo","AppleGothic","AppleMyungjo","Avenir","Avenir Next","Avenir Next Condensed","Baskerville","Big Caslon","Bodoni 72","Bodoni 72 Oldstyle","Bodoni 72 Smallcaps","Bradley Hand","Brush Script MT","Chalkboard","Chalkboard SE","Chalkduster","Charter","Cochin","Copperplate","Corsiva Hebrew","Courier","DIN Alternate","DIN Condensed","Didot","Euphemia UCAS","Futura","Geneva","Gill Sans","Helvetica","Helvetica Neue","Herculanum","Hiragino Kaku Gothic Pro","Hiragino Mincho Pro","Hoefler Text","Kailasa","Kannada Sangam MN","Khmer Sangam MN","Kohinoor Bangla","Kohinoor Devanagari","Kohinoor Telugu","Lao Sangam MN","Lucida Grande","Luminari","Malayalam Sangam MN","Marker Felt","Menlo","Monaco","Noteworthy","Optima","Oriya Sangam MN","Osaka","Palatino","Papyrus","Phosphate","PingFang HK","PingFang SC","PingFang TC","Plantagenet Cherokee","PT Mono","PT Sans","PT Sans Caption","PT Sans Narrow","PT Serif","PT Serif Caption","Rockwell","Savoye LET","SignPainter","Sinhala Sangam MN","Skia","Snell Roundhand","STIXGeneral","Superclarendon","Tamil Sangam MN","Telugu Sangam MN","Times","Trattatello","Zapfino","Ubuntu","Ubuntu Condensed","Ubuntu Light","Ubuntu Mono","DejaVu Sans","DejaVu Sans Mono","DejaVu Serif","Liberation Mono","Liberation Sans","Liberation Serif","Nimbus Mono L","Nimbus Roman No9 L","Nimbus Sans L","FreeMono","FreeSans","FreeSerif","Noto Sans","Noto Serif","Noto Mono","Droid Sans","Droid Sans Mono","Droid Serif","Open Sans","Roboto","Roboto Condensed","Roboto Mono","Roboto Slab","Lato","Montserrat","Source Sans Pro","Source Code Pro","Source Serif Pro","Oswald","Raleway","Merriweather","Nunito","Poppins","Playfair Display","Quicksand","Rubik","Work Sans","Fira Sans","Fira Mono","Fira Code","Barlow","Barlow Condensed","Inter","Manrope","DM Sans","DM Serif Display","IBM Plex Sans","IBM Plex Mono","JetBrains Mono","Inconsolata","Space Mono","Space Grotesk"],i=["monospace","sans-serif","serif"],o="mmmmmmmmmmlli",a="72px";class r{constructor(e="https://fingerprint.ipranker.com/fingerprint-visitor-id",t){this.fingerprintEndpoint=e,this.apiKey=t}async collect(){try{const e=await this.collectCompleteDeviceData(),t={"Content-Type":"application/json",Accept:"application/json"};this.apiKey&&(t["x-api-key"]=this.apiKey);const n=await fetch(this.fingerprintEndpoint,{method:"POST",headers:t,credentials:"omit",body:JSON.stringify({deviceData:e})});if(!n.ok)return await this.collectBasicFingerprint();const i=await n.json();return i.visitorId||i.fingerprints?.installationId?this.transformFingerprintResponse(i):await this.collectBasicFingerprint()}catch(e){return await this.collectBasicFingerprint()}}transformFingerprintResponse(e){const t={installationId:e.visitorId||e.fingerprints?.installationId||e.installationId||null,canvas:{text:e.fingerprints?.canvasText||e.canvas?.text||null,geometry:e.fingerprints?.canvasGeometry||e.canvas?.geometry||null,blending:e.fingerprints?.canvasBlending||e.canvas?.blending||null},webgl:e.fingerprints?.webgl||e.webgl?{vendor:e.fingerprints?.webgl?.vendor||e.webgl?.vendor||null,renderer:e.fingerprints?.webgl?.renderer||e.webgl?.renderer||null,extensions:e.fingerprints?.webgl?.extensions?.length||e.webgl?.extensions?.length||0}:{vendor:null,renderer:null,extensions:0},audio:e.fingerprints?.audio||e.audio||null,screen:{width:e.screen?.width||window.screen.width,height:e.screen?.height||window.screen.height,colorDepth:e.screen?.colorDepth||window.screen.colorDepth,pixelRatio:e.screen?.pixelRatio||window.devicePixelRatio,orientation:e.screen?.orientation||screen.orientation?.type||window.orientation||"unknown"},timezone:e.localization?.timeZone||e.timezone||Intl.DateTimeFormat().resolvedOptions().timeZone,language:e.localization?.languages?.[0]||e.language||navigator.language,platform:e.platform?.platform||e.platform||navigator.platform};return e.fonts&&(t.fonts=e.fonts),e.webrtc&&(t.webrtc=e.webrtc),e.sensors&&(t.sensors=e.sensors),e.advancedBrowser&&(t.advancedBrowser=e.advancedBrowser),e.hardware&&(t.hardware=e.hardware),e.permissions&&(t.permissions=e.permissions),t}async collectBasicFingerprint(){const[e,t]=await Promise.all([this.collectFontFingerprint(),this.collectWebRTCFingerprint()]),n=this.collectSensorFingerprint(),i=this.collectAdvancedBrowserFeatures(),o=this.collectHardwareData(),a=await this.collectPermissionsState(),r=this.getWebGLFingerprint();return{installationId:null,canvas:{text:this.getCanvasFingerprint(),geometry:this.getCanvasGeometryFingerprint(),blending:this.getCanvasBlendingFingerprint()},webgl:r?{vendor:r.vendor||null,renderer:r.renderer||null,extensions:r.extensions||0}:{vendor:null,renderer:null,extensions:0},audio:null,screen:{width:window.screen.width,height:window.screen.height,colorDepth:window.screen.colorDepth,pixelRatio:window.devicePixelRatio,orientation:screen.orientation?.type||window.orientation||"unknown"},timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,language:navigator.language,platform:navigator.platform,fonts:e,webrtc:t,sensors:n,advancedBrowser:i,hardware:o,permissions:a}}async collectCompleteDeviceData(){const e=navigator.userAgent,t=navigator.platform,[n,i]=await Promise.all([this.collectFontFingerprint(),this.collectWebRTCFingerprint()]),o=this.collectSensorFingerprint(),a=this.collectAdvancedBrowserFeatures(),r=this.collectHardwareData(),s=await this.collectPermissionsState(),l=this.getWebGLFingerprint();return{platform:{brands:navigator.userAgentData?.brands||[],platform:t,mobile:/Mobile|Android|iPhone|iPad|iPod/i.test(e),architecture:navigator.userAgentData?.architecture||"unknown",bitness:navigator.userAgentData?.bitness||"unknown",browserInfo:{userAgent:e,language:navigator.language,languages:navigator.languages||[navigator.language]}},screen:{width:window.screen.width,height:window.screen.height,colorDepth:window.screen.colorDepth,pixelDepth:window.screen.pixelDepth||window.screen.colorDepth,orientation:screen.orientation?.type||window.orientation||"portrait-primary",pixelRatio:window.devicePixelRatio||1},hardware:r,capabilities:{cookiesEnabled:navigator.cookieEnabled,doNotTrack:"1"===navigator.doNotTrack||"1"===window.doNotTrack,pdfViewerEnabled:navigator.pdfViewerEnabled??!0},localization:{languages:navigator.languages||[navigator.language],timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone},fingerprints:{canvasText:this.getCanvasFingerprint(),canvasBlending:this.getCanvasBlendingFingerprint(),canvasGeometry:this.getCanvasGeometryFingerprint(),webgl:l,timingResolution:"undefined"!=typeof performance&&"function"==typeof performance.now?"high":"low"},fonts:{fontCount:n.fontCount,fontFingerprint:n.fontFingerprint},webrtc:i,sensors:o,advancedBrowser:a,permissions:s}}async collectFontFingerprint(){try{return await async function(){const e=performance.now(),r=[];try{const s=document.createElement("canvas").getContext("2d");if(!s)return{installedFonts:[],fontCount:0,fontFingerprint:"unavailable",detectionTimeMs:performance.now()-e};const l={};for(const e of i)s.font=`${a} ${e}`,l[e]=s.measureText(o).width;for(const e of n){let t=!1;for(const n of i)if(s.font=`${a} "${e}", ${n}`,s.measureText(o).width!==l[n]){t=!0;break}t&&r.push(e)}return{installedFonts:r,fontCount:r.length,fontFingerprint:t(r.sort().join("|")),detectionTimeMs:performance.now()-e}}catch{return{installedFonts:[],fontCount:0,fontFingerprint:"error",detectionTimeMs:performance.now()-e}}}()}catch{return{installedFonts:[],fontCount:0,fontFingerprint:"error",detectionTimeMs:0}}}async collectWebRTCFingerprint(){const e={webrtcSupported:!!window.RTCPeerConnection,mediaDevicesCount:0,hasCamera:!1,hasMicrophone:!1,hasSpeaker:!1,webrtcFingerprint:""};try{if(navigator.mediaDevices?.enumerateDevices){const t=await navigator.mediaDevices.enumerateDevices();e.mediaDevicesCount=t.length,e.hasCamera=t.some(e=>"videoinput"===e.kind),e.hasMicrophone=t.some(e=>"audioinput"===e.kind),e.hasSpeaker=t.some(e=>"audiooutput"===e.kind)}}catch{}return e.webrtcFingerprint=t(JSON.stringify({supported:e.webrtcSupported,devices:e.mediaDevicesCount,camera:e.hasCamera,mic:e.hasMicrophone,speaker:e.hasSpeaker})),e}collectSensorFingerprint(){const e={accelerometerSupported:"Accelerometer"in window,gyroscopeSupported:"Gyroscope"in window,magnetometerSupported:"Magnetometer"in window,ambientLightSupported:"AmbientLightSensor"in window,sensorFingerprint:""};return e.sensorFingerprint=t(JSON.stringify({accel:e.accelerometerSupported,gyro:e.gyroscopeSupported,mag:e.magnetometerSupported,light:e.ambientLightSupported})),e}collectAdvancedBrowserFeatures(){const e={localStorageEnabled:this.isStorageAvailable("localStorage"),sessionStorageEnabled:this.isStorageAvailable("sessionStorage"),indexedDBEnabled:!!window.indexedDB,cacheAPIEnabled:"caches"in window,webGL2Supported:!!document.createElement("canvas").getContext("webgl2"),webAssemblySupported:"object"==typeof WebAssembly,serviceWorkerSupported:"serviceWorker"in navigator,doNotTrack:"1"===navigator.doNotTrack||"1"===window.doNotTrack,pdfViewerEnabled:navigator.pdfViewerEnabled??!0,browserFeaturesFingerprint:""};return e.browserFeaturesFingerprint=t(JSON.stringify({ls:e.localStorageEnabled,ss:e.sessionStorageEnabled,idb:e.indexedDBEnabled,cache:e.cacheAPIEnabled,webgl2:e.webGL2Supported,wasm:e.webAssemblySupported,sw:e.serviceWorkerSupported,dnt:e.doNotTrack,pdf:e.pdfViewerEnabled})),e}isStorageAvailable(e){try{const t=window[e],n="__t__";return t.setItem(n,n),t.removeItem(n),!0}catch{return!1}}collectHardwareData(){const e=this.getWebGLFingerprint();return{cores:navigator.hardwareConcurrency||4,memory:navigator.deviceMemory||null,maxTouchPoints:navigator.maxTouchPoints||0,gpuVendor:e?.vendor||null,gpuRenderer:e?.renderer||null}}async collectPermissionsState(){const e={geolocation:1,notifications:1,camera:1,microphone:1},t=e=>{switch(e){case"granted":return 2;case"prompt":default:return 1;case"denied":return 0}};try{if(navigator.permissions){const n=["geolocation","notifications","camera","microphone"];for(const i of n)try{const n=await navigator.permissions.query({name:i});e[i]=t(n.state)}catch{}}}catch{}return e}getCanvasFingerprint(){try{const e=document.createElement("canvas"),t=e.getContext("2d");return t?(e.width=240,e.height=60,t.textBaseline="alphabetic",t.fillStyle="#f60",t.fillRect(100,1,62,20),t.fillStyle="#069",t.font="11pt Arial",t.fillText("Cwm fjordbank glyphs vext quiz, 😃",2,15),t.fillStyle="rgba(102, 204, 0, 0.7)",t.font="18pt Arial",t.fillText("Cwm fjordbank glyphs vext quiz, 😃",4,45),e.toDataURL()):null}catch{return null}}getCanvasBlendingFingerprint(){try{const e=document.createElement("canvas"),t=e.getContext("2d");return t?(e.width=100,e.height=100,t.fillStyle="rgb(255,0,255)",t.beginPath(),t.arc(50,50,50,0,2*Math.PI,!0),t.closePath(),t.fill(),t.fillStyle="rgb(0,255,255)",t.globalCompositeOperation="multiply",t.beginPath(),t.arc(25,25,25,0,2*Math.PI,!0),t.closePath(),t.fill(),e.toDataURL()):null}catch{return null}}getCanvasGeometryFingerprint(){try{const e=document.createElement("canvas"),t=e.getContext("2d");if(!t)return null;e.width=122,e.height=110,t.globalCompositeOperation="multiply";for(let e=0;e<20;e++)t.fillStyle=`rgb(${Math.floor(255-10*e)}, ${Math.floor(10*e)}, ${Math.floor(5*e)})`,t.beginPath(),t.arc(5*e,5*e,e+10,0,2*Math.PI,!0),t.closePath(),t.fill();return e.toDataURL()}catch{return null}}getWebGLFingerprint(){try{const e=document.createElement("canvas"),t=e.getContext("webgl")||e.getContext("experimental-webgl");if(!t)return null;const n=t.getExtension("WEBGL_debug_renderer_info");return{vendor:n?t.getParameter(n.UNMASKED_VENDOR_WEBGL):t.getParameter(t.VENDOR),renderer:n?t.getParameter(n.UNMASKED_RENDERER_WEBGL):t.getParameter(t.RENDERER),version:t.getParameter(t.VERSION),shadingLanguageVersion:t.getParameter(t.SHADING_LANGUAGE_VERSION),extensions:t.getSupportedExtensions()?.length||0}}catch{return null}}}class s{constructor(){this.mouseMovements=[],this.scrollEvents=[],this.clickEvents=[],this.keypresses=0,this.startTime=Date.now(),this.isCollecting=!1,this.handleMouseMove=e=>{this.mouseMovements.push({x:e.clientX,y:e.clientY,timestamp:Date.now()}),this.mouseMovements.length>100&&this.mouseMovements.shift()},this.handleTouchMove=e=>{if(e.touches.length>0){const t=e.touches[0];this.mouseMovements.push({x:t.clientX,y:t.clientY,timestamp:Date.now()}),this.mouseMovements.length>100&&this.mouseMovements.shift()}},this.handleTouchStart=e=>{if(e.touches.length>0){const t=e.touches[0];this.clickEvents.push({x:t.clientX,y:t.clientY,timestamp:Date.now()}),this.clickEvents.length>50&&this.clickEvents.shift()}},this.handleScroll=()=>{this.scrollEvents.push({y:window.scrollY,timestamp:Date.now()}),this.scrollEvents.length>50&&this.scrollEvents.shift()},this.handleClick=e=>{this.clickEvents.push({x:e.clientX,y:e.clientY,timestamp:Date.now()}),this.clickEvents.length>50&&this.clickEvents.shift()},this.handleKeypress=()=>{this.keypresses++}}start(){this.isCollecting||(this.isCollecting=!0,document.addEventListener("mousemove",this.handleMouseMove,{passive:!0}),document.addEventListener("touchmove",this.handleTouchMove,{passive:!0}),document.addEventListener("touchstart",this.handleTouchStart,{passive:!0}),window.addEventListener("scroll",this.handleScroll,{passive:!0}),document.addEventListener("click",this.handleClick,{passive:!0}),document.addEventListener("keypress",this.handleKeypress,{passive:!0}))}stop(){this.isCollecting=!1,document.removeEventListener("mousemove",this.handleMouseMove),document.removeEventListener("touchmove",this.handleTouchMove),document.removeEventListener("touchstart",this.handleTouchStart),window.removeEventListener("scroll",this.handleScroll),document.removeEventListener("click",this.handleClick),document.removeEventListener("keypress",this.handleKeypress)}getData(){const e=Date.now()-this.startTime,t=this.keypresses/(e/6e4);return{mouseMovements:this.mouseMovements,scrollEvents:this.scrollEvents,clickEvents:this.clickEvents,sessionDuration:e,typingSpeed:t,keypresses:this.keypresses}}}class l{async collect(){return{userAgent:navigator.userAgent,platform:navigator.platform,language:navigator.language,screenWidth:window.screen.width,screenHeight:window.screen.height,colorDepth:window.screen.colorDepth,pixelRatio:window.devicePixelRatio,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,hardwareConcurrency:navigator.hardwareConcurrency||0,maxTouchPoints:navigator.maxTouchPoints||0,cookieEnabled:navigator.cookieEnabled}}}class c{constructor(e,t){this.baseURL=e,this.apiKey=t}async analyze(e){const t=Date.now();try{const n=await fetch(`${this.baseURL}/analyze`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.apiKey},body:JSON.stringify(e)});if(!n.ok){const e=await n.text();throw new Error(`API Error: ${n.status} ${n.statusText} - ${e}`)}const i=await n.json(),o=Date.now()-t;return{...i,responseTime:o}}catch(e){if(e instanceof Error)throw new Error(`IPRanker API request failed: ${e.message}`);throw e}}}class h{constructor(e,t={}){if(!e||"string"!=typeof e||e.length<10)throw new Error("Invalid API key. Please provide a valid IPRanker API key.");this.apiKey=e,this.options={baseURL:t.baseURL||"https://api.ipranker.com",collectBehavior:!1!==t.collectBehavior,behaviorTimeout:t.behaviorTimeout||5e3,autoRetry:!1!==t.autoRetry,maxRetries:t.maxRetries||3,cache:!1!==t.cache,cacheTimeout:t.cacheTimeout||3e5,debug:t.debug||!1},this.callbacks={onReady:t.onReady,onAnalyzing:t.onAnalyzing,onComplete:t.onComplete,onError:t.onError};const n=`${this.options.baseURL}/v1`;this.apiClient=new c(n,this.apiKey);const i=`${n}/fingerprint-visitor-id`;this.fingerprintCollector=new r(i,this.apiKey),this.behaviorCollector=new s,this.deviceCollector=new l,this._initialize()}_initialize(){try{this.options.collectBehavior&&this.behaviorCollector.start(),this._log("IPRanker SDK initialized"),this.callbacks.onReady?.()}catch(e){this._handleError(e)}}async analyze(e){try{this._log("Starting analysis..."),this.callbacks.onAnalyzing?.();const t=e?.ip||"auto";if(this.options.cache){const e=this._getCachedResult(t);if(e)return this._log("Returning cached result for IP:",t),this.callbacks.onComplete?.(e),e}this._log("Collecting fingerprint data...");const n=await this.fingerprintCollector.collect();this._log("Collecting behavioral data...");const i=this.options.collectBehavior?await this._collectBehaviorWithTimeout(e?.timeout||this.options.behaviorTimeout):null;this._log("Collecting device data...");const o={fingerprint:n,behavior:i,device:await this.deviceCollector.collect(),includeRawData:e?.includeRawData||!1};e?.ip&&(o.ip=e.ip),this._log("Sending analysis request to IPRanker API...",{ip:o.ip,hasIp:!!o.ip});const a=await this._sendWithRetry(o);return this.options.cache&&this._cacheResult(t,a),this._log("Analysis complete",a),this.callbacks.onComplete?.(a),a}catch(e){throw this._handleError(e),e}}async getFingerprint(){return await this.fingerprintCollector.collect()}getBehaviorData(){return this.behaviorCollector.getData()}async getDeviceData(){return await this.deviceCollector.collect()}clearCache(){this._clearCache(),this._log("Cache cleared")}destroy(){this.behaviorCollector.stop(),this._log("SDK destroyed")}async _collectBehaviorWithTimeout(e){return Promise.race([Promise.resolve(this.behaviorCollector.getData()),new Promise(t=>setTimeout(()=>t(null),e))])}async _sendWithRetry(e,t=0){try{return await this.apiClient.analyze(e)}catch(n){if(this.options.autoRetry&&t<this.options.maxRetries)return this._log(`Retry ${t+1}/${this.options.maxRetries} after error:`,n),await this._delay(1e3*(t+1)),this._sendWithRetry(e,t+1);throw n}}_getCachedResult(e){try{const t=localStorage.getItem("ipranker_cache");if(!t)return null;const n=JSON.parse(t);if(n.result&&n.timestamp)return this._log("Clearing old cache format"),localStorage.removeItem("ipranker_cache"),null;const i=n[e];if(!i||!i.result||!i.timestamp)return null;return Date.now()-i.timestamp<this.options.cacheTimeout?i.result:(delete n[e],localStorage.setItem("ipranker_cache",JSON.stringify(n)),null)}catch(e){return localStorage.removeItem("ipranker_cache"),null}}_cacheResult(e,t){try{let n={};const i=localStorage.getItem("ipranker_cache");i&&(n=JSON.parse(i)),n[e]={result:t,timestamp:Date.now()},localStorage.setItem("ipranker_cache",JSON.stringify(n))}catch(e){this._log("Cache failed:",e)}}_clearCache(){try{localStorage.removeItem("ipranker_cache")}catch(e){}}_handleError(e){this._log("Error:",e),this.callbacks.onError?.(e)}_log(...e){this.options.debug&&console.log("[IPRanker SDK]",...e)}_delay(e){return new Promise(t=>setTimeout(t,e))}}e.IPRanker=h,e.default=h,Object.defineProperty(e,"__esModule",{value:!0})});
//# sourceMappingURL=index.umd.js.map