PageSourceSearch

https://puridex.io/assets/worker-privacyWorker-vRsdR-6o.js

js puridex.io collected 2026-10-09 21:34:05 UTC 7,662 bytes, 2 lines download raw bytes

1function v(e){return e.replace(/[\s.\-]/g,"").toUpperCase()}function k(e){const t=v(e);if(!/^[0-9]+$/.test(t)||t.length<8)return!1;let n=0,s=!1;for(let o=t.length-1;o>=0;o--){let i=t.charCodeAt(o)-48;s&&(i*=2,i>9&&(i-=9)),n+=i,s=!s}return n%10===0}function u(e,t){for(const n of t)e.push(n);return e.length}const w=5*1024*1024,m=500,f=5e3,$=4,S=[{name:"email",pattern:/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g,category:"Contact Info",risk:"high",recommendation:"Consider masking email inputs or minimizing storage duration"},{name:"phone",pattern:/\b(?:\+?1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}\b/g,category:"Contact Info",risk:"medium",recommendation:"Store phone numbers securely and only if necessary"},{name:"ssn",pattern:/\b\d{3}[-]?\d{2}[-]?\d{4}\b/g,category:"Identity Info",risk:"high",recommendation:"Never store SSN in plaintext - use secure hashing or avoid collection"},{name:"creditCard",pattern:/\b(?:\d{4}[-\s]?){3}\d{4}\b/g,category:"Financial Info",risk:"high",recommendation:"Never store credit card numbers - use tokenization via payment processors",validator:k},{name:"ipAddress",pattern:/\b(?:\d{1,3}\.){3}\d{1,3}\b/g,category:"Technical Info",risk:"medium",recommendation:"Consider anonymizing IP addresses for analytics"},{name:"dateOfBirth",pattern:/\b(19|20)\d{2}[-/](0[1-9]|1[0-2])[-/](0[1-9]|[12]\d|3[01])\b/g,category:"Personal Info",risk:"high",recommendation:"Only store age or year if full DOB not required"},{name:"address",pattern:/\b\d+\s+[\w\s]{1,50}(?:street|st|avenue|ave|road|rd|boulevard|blvd|lane|ln|drive|dr)\b/gi,category:"Location Info",risk:"medium",recommendation:"Consider partial address storage or geocoding"},{name:"zipCode",pattern:/\b\d{5}(?:-\d{4})?\b/g,category:"Location Info",risk:"low",recommendation:"Zip codes alone are generally low risk"}],P=[{pattern:/localStorage\.(setItem|getItem)\s*\(\s*['"`][^'"`]*?(password|token|secret|key|ssn|credit|card)/gi,type:"Insecure Storage",severity:"high",description:"Sensitive data stored in localStorage",recommendation:"Use secure storage options like httpOnly cookies or server-side sessions"},{pattern:/console\.(log|info|debug)\s*\([^)]*?(password|token|email|ssn|credit|secret)/gi,type:"Console Logging",severity:"medium",description:"Sensitive data may be logged to console",recommendation:"Remove console.log statements with sensitive data in production"},{pattern:/type\s*=\s*['"`]text['"`][^>]*?(password|secret)/gi,type:"Unmasked Sensitive Field",severity:"critical",description:"Password field displayed as plain text",recommendation:"Use type='password' for password inputs"},{pattern:/(api[_-]?key|secret|password|token)\s*[:=]\s*['"`][A-Za-z0-9_\-]{10,}['"`]/gi,type:"Hardcoded Secret",severity:"critical",description:"Potential hardcoded secret or API key detected",recommendation:"Use environment variables for secrets"},{pattern:/fetch\s*\(\s*['"`]http:\/\//gi,type:"Insecure Connection",severity:"high",description:"HTTP used instead of HTTPS for API calls",recommendation:"Always use HTTPS for API endpoints"}],T=[{pattern:/(['"`]?)(firstName|first_name)(['"`]?)\s*[:=]/gi,name:"firstName",category:"Personal Info"},{pattern:/(['"`]?)(lastName|last_name)(['"`]?)\s*[:=]/gi,name:"lastName",category:"Personal Info"},{pattern:/(['"`]?)(fullName|full_name|name)(['"`]?)\s*[:=]/gi,name:"fullName",category:"Personal Info"},{pattern:/(['"`]?)(dateOfBirth|dob|birthDate)(['"`]?)\s*[:=]/gi,name:"dateOfBirth",category:"Personal Info"},{pattern:/(['"`]?)(gender|sex)(['"`]?)\s*[:=]/gi,name:"gender",category:"Personal Info"},{pattern:/(['"`]?)(password|passwd)(['"`]?)\s*[:=]/gi,name:"password",category:"Credentials"},{pattern:/(['"`]?)(bankAccount|accountNumber|iban)(['"`]?)\s*[:=]/gi,name:"bankAccount",category:"Financial Info"}];function h(e,t,n=m,s){const o=[];e.lastIndex=0;let i,c=0;try{for(;(i=e.exec(t))!==null&&c<f&&(o.push(i),c++,!(o.length>=n));)i.index===e.lastIndex&&e.lastIndex++}catch{}return s&&(o.length>=n?s.notices.push(`${s.label}: match cap reached (${n}); counts are a floor, not a total.`):c>=f&&s.notices.push(`${s.label}: iteration cap reached (${f}); the rest of this pattern was not scanned.`)),o}function A(e){const t=[0];for(let n=0;n<e.length;n++)e[n]===`
2`&&t.push(n+1);return t}function y(e,t){let n=0,s=e.length-1;for(;n<s;){const o=Math.ceil((n+s)/2);e[o]<=t?n=o:s=o-1}return n+1}function N(e,t,n,s,o=[]){const i=[];let c=s;const l=new Set;for(const r of S){const d=h(r.pattern,t,m,{label:`${e} · ${r.name}`,notices:o});
2for(const a of d){if(r.validator&&!r.validator(a[0]))continue;const g=y(n,a.index),p=`${r.name}:${g}:${a[0].slice(0,20)}`;l.has(p)||(l.add(p),i.push({id:`pii-${e}-${c++}`,fieldName:r.name,category:r.category,location:e,risk:r.risk,recommendation:r.recommendation,sampleValue:a[0].slice(0,20)+(a[0].length>20?"...":""),lineNumber:g}))}}for(const{pattern:r,name:d,category:a}of T){const g=h(r,t,m,{label:`${e} · ${d}`,notices:o});for(const p of g){const I=y(n,p.index),b=`field:${d}:${I}`;l.has(b)||(l.add(b),i.push({id:`pii-${e}-${c++}`,fieldName:d,category:a,location:e,risk:a==="Credentials"||a==="Financial Info"?"high":"medium",recommendation:`Review usage of ${d} field and ensure proper data protection`,lineNumber:I}))}}return i}function C(e,t,n,s,o=[]){const i=[];let c=s;const l=new Set;for(const r of P){const d=h(r.pattern,t,m,{label:`${e} · ${r.type}`,notices:o});for(const a of d){const g=y(n,a.index),p=`${r.type}:${g}`;l.has(p)||(l.add(p),i.push({id:`sec-${e}-${c++}`,type:r.type,description:r.description,severity:r.severity,location:e,recommendation:r.recommendation,lineNumber:g}))}}return i}function F(e){const t=[];try{const n=e.content.length>w?e.content.slice(0,w):e.content;if(n.length<e.content.length){const c=Math.round(n.length/e.content.length*100);t.push(`${e.name}: only the first ${n.length.toLocaleString()} of ${e.content.length.toLocaleString()} characters were scanned (${c}%). Findings beyond that point are unknown — this file is NOT confirmed clean.`)}const s=A(n),o=N(e.name,n,s,0,t),i=C(e.name,n,s,0,t);return{pii:o,security:i,notices:t}}catch(n){return{pii:[],security:[],notices:[...t,`${e.name}: scan failed before completion — results for this file are incomplete.`],error:n instanceof Error?n.message:"Unknown error"}}}async function R(e){const t=[],n=[],s=e.files.length,o=[],i=[];for(let c=0;c<s;c+=$){const l=Math.min(c+$,s),r=e.files.slice(c,l);postMessage({type:"progress",value:c/s*90,stage:`Scanning files ${c+1}-${l} of ${s}...`,totalRows:s,processedRows:c});const d=r.map(F);for(const a of d)u(t,a.pii),u(n,a.security),u(i,a.notices),a.error&&o.push(a.error);l<s&&await new Promise(a=>setTimeout(a,0))}return postMessage({type:"progress",value:95,stage:"Finalizing results...",totalRows:s,processedRows:s}),{piiFields:t,securityIssues:n,truncationNotices:i}}self.onmessage=async e=>{try{postMessage({type:"progress",value:0,stage:"Starting privacy scan...",totalRows:0,processedRows:0});const t=await R(e.data);postMessage({type:"progress",value:100,stage:"Complete!",totalRows:e.data.files.length,processedRows:e.data.files.length}),await new Promise(n=>setTimeout(n,50));try{postMessage({type:"complete",results:t})}catch{postMessage({type:"complete",results:{piiFields:t.piiFields.slice(0,5e3),securityIssues:t.securityIssues.slice(0,1e3),truncationNotices:[...t.truncationNotices,`Result set truncated for transfer: showing ${Math.min(t.piiFields.length,5e3)} of ${t.piiFields.length} PII findings and ${Math.min(t.securityIssues.length,1e3)} of ${t.securityIssues.length} security findings.`]}})}}catch(t){postMessage({type:"error",message:t instanceof Error?t.message:"Unknown error during privacy scan"})}};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.