@nice2dev/ui-security 1.0.10
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/CHANGELOG.md +56 -0
- package/README.md +26 -0
- package/dist/compliance-utilities.d.ts +201 -0
- package/dist/components/NiceDeviceTrust.d.ts +18 -0
- package/dist/components/NiceFaceRecognition.d.ts +25 -0
- package/dist/components/NiceFingerprintScanner.d.ts +34 -0
- package/dist/components/NiceIrisScanner.d.ts +22 -0
- package/dist/components/NiceMfaSelector.d.ts +24 -0
- package/dist/components/NicePassphraseInput.d.ts +22 -0
- package/dist/components/NicePatternLock.d.ts +19 -0
- package/dist/components/NicePinKeypad.d.ts +20 -0
- package/dist/components/NiceSecurityAuditLog.d.ts +16 -0
- package/dist/components/NiceSessionManager.d.ts +24 -0
- package/dist/components/NiceWebAuthnButton.d.ts +22 -0
- package/dist/content-safety.d.ts +212 -0
- package/dist/core/biometricEngine.d.ts +111 -0
- package/dist/core/i18n.d.ts +11 -0
- package/dist/core/types.d.ts +244 -0
- package/dist/index.cjs +292 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.mjs +3997 -0
- package/dist/security-automation.d.ts +121 -0
- package/dist/security-utilities.d.ts +192 -0
- package/package.json +82 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("react/jsx-runtime"),h=require("react"),He={low:.7,medium:.8,high:.85,critical:.95},Ue={matchThreshold:.85,timeout:3e4,maxRetries:3,livenessDetection:!0,verifyEndpoint:"",authToken:"",showFeedback:!0,hapticFeedback:!0,locale:"en",securityLevel:"high",antiSpoofing:!0};function ie(e){const t={...Ue,...e};return e!=null&&e.matchThreshold||(t.matchThreshold=He[t.securityLevel]),t}async function ae(e){const t=new TextEncoder().encode(e),r=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(r)).map(n=>n.toString(16).padStart(2,"0")).join("")}function le(e=8){const t=new Uint8Array(e);return crypto.getRandomValues(t),Array.from(t).map(r=>r.toString(36).padStart(2,"0")).join("").slice(0,e)}function Oe(e){const t=new Uint32Array(1);return crypto.getRandomValues(t),t[0]%e}function qe(e,t){return Math.sqrt((e.x-t.x)**2+(e.y-t.y)**2)}async function oe(e="user"){return navigator.mediaDevices.getUserMedia({video:{facingMode:e,width:{ideal:1280},height:{ideal:720}},audio:!1})}function te(e,t,r){const n=t??e.videoWidth,i=r??e.videoHeight,a=document.createElement("canvas");a.width=n,a.height=i;const o=a.getContext("2d");o.drawImage(e,0,0,n,i);const c=o.getImageData(0,0,n,i);return{canvas:a,ctx:o,imageData:c}}function re(e){const t=new Uint8Array(e.width*e.height),r=e.data;for(let n=0;n<t.length;n++){const i=n*4;t[n]=Math.round(.299*r[i]+.587*r[i+1]+.114*r[i+2])}return t}function Se(e,t,r){const n=new Uint8Array(t*r),i=[1,2,1,2,4,2,1,2,1],a=16;for(let o=1;o<r-1;o++)for(let c=1;c<t-1;c++){let m=0,x=0;for(let y=-1;y<=1;y++)for(let v=-1;v<=1;v++)m+=e[(o+y)*t+(c+v)]*i[x++];n[o*t+c]=Math.round(m/a)}return n}function Ke(e,t,r){const n=new Uint8Array(t*r);for(let i=1;i<r-1;i++)for(let a=1;a<t-1;a++){const o=-e[(i-1)*t+(a-1)]+e[(i-1)*t+(a+1)]+-2*e[i*t+(a-1)]+2*e[i*t+(a+1)]+-e[(i+1)*t+(a-1)]+e[(i+1)*t+(a+1)],c=-e[(i-1)*t+(a-1)]-2*e[(i-1)*t+a]-e[(i-1)*t+(a+1)]+e[(i+1)*t+(a-1)]+2*e[(i+1)*t+a]+e[(i+1)*t+(a+1)];n[i*t+a]=Math.min(255,Math.round(Math.sqrt(o*o+c*c)))}return n}function Ge(e){const t=new Array(256).fill(0);for(const x of e)t[x]++;const r=e.length;let n=0;for(let x=0;x<256;x++)n+=x*t[x];let i=0,a=0,o=0,c=0;for(let x=0;x<256;x++){if(a+=t[x],a===0)continue;const y=r-a;if(y===0)break;i+=x*t[x];const v=i/a,A=(n-i)/y,g=a*y*(v-A)**2;g>o&&(o=g,c=x)}const m=new Uint8Array(e.length);for(let x=0;x<e.length;x++)m[x]=e[x]>c?255:0;return{threshold:c,binary:m}}function ke(e,t=.3){var p;const r=e.width,n=e.height,i=re(e),a=Se(i,r,n),o=Ke(a,r,n),{binary:c}=Ge(o),m=[],x=[],y=[];for(let k=2;k<n-2;k++)for(let u=2;u<r-2;u++){if(c[k*r+u]===0)continue;const w=[c[(k-1)*r+u],c[(k-1)*r+(u+1)],c[k*r+(u+1)],c[(k+1)*r+(u+1)],c[(k+1)*r+u],c[(k+1)*r+(u-1)],c[k*r+(u-1)],c[(k-1)*r+(u-1)]];let l=0;for(let B=0;B<8;B++){const H=w[B]>0?1:0,G=w[(B+1)%8]>0?1:0;l+=Math.abs(H-G)}l/=2;let f=0,z=0;for(let B=-2;B<=2;B++)for(let H=-2;H<=2;H++)f+=o[(k+B)*r+(u+H)],z++;const O=f/z/255;if(O<t)continue;const J=Math.atan2(i[(k+1)*r+u]-i[(k-1)*r+u],i[k*r+(u+1)]-i[k*r+(u-1)]);l===1?m.push({x:u/r,y:k/n,angle:J,type:"ending",quality:O}):l===3&&m.push({x:u/r,y:k/n,angle:J,type:"bifurcation",quality:O})}m.sort((k,u)=>u.quality-k.quality);const v=m.slice(0,120);if(v.length>5){const k=v.reduce((w,l)=>w+l.x,0)/v.length,u=v.reduce((w,l)=>w+l.y,0)/v.length;x.push({x:k,y:u})}const A=v.length,g=v.filter(k=>k.type==="ending").length,D=v.filter(k=>k.type==="bifurcation").length/(g+1);let b="loop-right";D>1.5?b="whorl":D<.5?b="arch":((p=x[0])==null?void 0:p.x)<.45&&(b="loop-left");const T=v.length>20?v.reduce((k,u)=>k+u.quality,0)/v.length:0;return{minutiae:v,corePoints:x,deltaPoints:y,ridgeCount:A,patternType:b,quality:T}}function Ae(e,t){if(e.minutiae.length<5||t.minutiae.length<5)return 0;let r=0;const n=.05,i=.5,a=new Set;for(const c of e.minutiae){let m=1/0,x=-1;for(let y=0;y<t.minutiae.length;y++){if(a.has(y))continue;const v=t.minutiae[y];if(c.type!==v.type)continue;const A=qe(c,v),g=Math.abs(c.angle-v.angle);A<n&&g<i&&A<m&&(m=A,x=y)}x>=0&&(r++,a.add(x))}const o=Math.min(e.minutiae.length,t.minutiae.length);return o>0?r/o:0}async function je(e,t){const r=JSON.stringify(e),n=await ae(r);return{id:`fp_${Date.now()}_${le()}`,method:"fingerprint",templateData:btoa(r),enrolled:Date.now(),label:t,hash:n}}function Te(e){return JSON.parse(atob(e.templateData))}function Ce(e,t="left"){const r=e.width,n=e.height,i=re(e),a=Se(i,r,n);let o={cx:r/2,cy:n/2,r:Math.min(r,n)*.08,score:1/0};for(let I=Math.round(n*.3);I<Math.round(n*.7);I+=2)for(let D=Math.round(r*.3);D<Math.round(r*.7);D+=2)for(let b=Math.round(Math.min(r,n)*.04);b<Math.round(Math.min(r,n)*.15);b+=2){let T=0,p=0;for(let l=0;l<Math.PI*2;l+=.3){const f=Math.round(D+b*Math.cos(l)),z=Math.round(I+b*Math.sin(l));f>=0&&f<r&&z>=0&&z<n&&(T+=a[z*r+f],p++)}const k=p>0?T/p:255,u=a[I*r+D],w=k*.5+u*.5;w<o.score&&(o={cx:D,cy:I,r:b,score:w})}const c=o.r*3,m={cx:o.cx,cy:o.cy,r:Math.min(c,Math.min(r,n)*.4)},x=256,y=[];for(let I=0;I<x;I++){const D=I/x*Math.PI*2,b=o.r+(m.r-o.r)*.5,T=Math.round(o.cx+b*Math.cos(D)),p=Math.round(o.cy+b*Math.sin(D));if(T>=0&&T<r&&p>=0&&p<n){const k=Math.round(o.cx+b*Math.cos(D+.1)),u=Math.round(o.cy+b*Math.sin(D+.1)),w=a[p*r+T],l=k>=0&&k<r&&u>=0&&u<n?a[u*r+k]:w;y.push(w>l?1:0)}else y.push(0)}const v=y.join(""),A=Math.PI*o.r**2,g=Math.min(1,Math.max(0,A/(r*n)*100));return{irisCode:v,pupil:o,iris:m,quality:g,eye:t}}function Ie(e,t){if(!e.irisCode||!t.irisCode)return 0;const r=Math.min(e.irisCode.length,t.irisCode.length);if(r===0)return 0;let n=0,i=r;for(let o=-8;o<=8;o++){let c=0;for(let m=0;m<r;m++){const x=(m+o+r)%r;e.irisCode[m]!==t.irisCode[x]&&c++}c<i&&(i=c)}n=i;const a=n/r;return Math.max(0,1-a*2.5)}async function Re(e,t){const r=JSON.stringify(e),n=await ae(r);return{id:`iris_${Date.now()}_${le()}`,method:"iris",templateData:btoa(r),enrolled:Date.now(),label:t,hash:n}}function De(e){return JSON.parse(atob(e.templateData))}function ne(e){const t=e.width,r=e.height,n=e.data,i=new Uint8Array(t*r);for(let u=0;u<t*r;u++){const w=u*4,l=n[w],f=n[w+1],z=n[w+2],O=.299*l+.587*f+.114*z,J=128-.169*l-.331*f+.5*z,B=128+.5*l-.419*f-.081*z;J>=77&&J<=127&&B>=133&&B<=173&&O>80&&(i[u]=1)}let a=t,o=r,c=0,m=0,x=0;for(let u=0;u<r;u++)for(let w=0;w<t;w++)i[u*t+w]&&(x++,w<a&&(a=w),w>c&&(c=w),u<o&&(o=u),u>m&&(m=u));const y=c-a,v=m-o;if(y<t*.1||v<r*.1)return null;const A={x:a,y:o,width:y,height:v},g=[],I=re(e),D=Math.max(1,Math.floor(y/8)),b=Math.max(1,Math.floor(v/16));for(let u=0;u<16;u++)for(let w=0;w<8;w++){const l=a+w*D+Math.floor(D/2),f=o+u*b+Math.floor(b/2);l<t&&f<r?g.push(I[f*t+l]/255):g.push(0)}const T=[],p={x:a+y/2,y:o+v/2};for(let u=0;u<68;u++){const w=u/68*Math.PI*2,l=y*.4*Math.cos(w),f=v*.45*Math.sin(w);T.push({x:(p.x+l)/t,y:(p.y+f)/r})}const k=Math.min(1,x/(y*v)*2);return{embedding:g,boundingBox:A,landmarks:T,headPose:{yaw:0,pitch:0,roll:0},quality:k}}function ue(e,t){if(e.embedding.length!==t.embedding.length)return 0;let r=0,n=0,i=0;for(let o=0;o<e.embedding.length;o++)r+=e.embedding[o]*t.embedding[o],n+=e.embedding[o]**2,i+=t.embedding[o]**2;const a=Math.sqrt(n)*Math.sqrt(i);return a>0?(r/a+1)/2:0}function Me(e,t){const r=ne(e),n=ne(t);return!r||!n?{similarity:0,cameraFeatures:r,refFeatures:n}:{similarity:ue(r,n),cameraFeatures:r,refFeatures:n}}async function Pe(e,t){const r=JSON.stringify(e),n=await ae(r);return{id:`face_${Date.now()}_${le()}`,method:"face",templateData:btoa(r),enrolled:Date.now(),label:t,hash:n}}function Ee(e){return JSON.parse(atob(e.templateData))}function Je(){const e=["blink","smile","turn-left","turn-right","nod","raise-eyebrows"],t=e[Oe(e.length)];return{type:t,instruction:{blink:"Please blink your eyes",smile:"Please smile","turn-left":"Please turn your head left","turn-right":"Please turn your head right",nod:"Please nod your head","raise-eyebrows":"Please raise your eyebrows"}[t],completed:!1,confidence:0}}function de(e,t=.02){if(e.length<2)return{isLive:!1,confidence:0,motionScore:0};let r=0;for(let o=1;o<e.length;o++){const c=re(e[o-1]),m=re(e[o]);let x=0;for(let y=0;y<c.length;y++)x+=Math.abs(c[y]-m[y]);r+=x/(c.length*255)}const n=r/(e.length-1),i=n>t,a=Math.min(1,n/(t*3));return{isLive:i,confidence:a,motionScore:n}}function he(){return{userAgent:navigator.userAgent,platform:navigator.platform,language:navigator.language,screenResolution:[screen.width,screen.height],timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,touchSupport:"ontouchstart"in window||navigator.maxTouchPoints>0,hardwareConcurrency:navigator.hardwareConcurrency??0}}async function se(){const e=he(),t=JSON.stringify(e);return ae(t)}function fe(){return typeof window<"u"&&!!window.PublicKeyCredential}async function Fe(){if(!fe())return!1;try{return await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()}catch{return!1}}async function Ne(e){const t={rp:{name:e.rpName,id:e.rpId},user:{id:new TextEncoder().encode(e.userId),name:e.userName,displayName:e.userDisplayName},challenge:e.challenge,pubKeyCredParams:[{alg:-7,type:"public-key"},{alg:-257,type:"public-key"}],authenticatorSelection:{authenticatorAttachment:"platform",userVerification:"required",residentKey:"preferred"},timeout:e.timeout??6e4,attestation:"none"};return await navigator.credentials.create({publicKey:t})}async function ze(e){const t={rpId:e.rpId,challenge:e.challenge,allowCredentials:e.allowCredentials,userVerification:"required",timeout:e.timeout??6e4};return await navigator.credentials.get({publicKey:t})}async function ce(e,t,r){const n={"Content-Type":"application/json"};r&&(n.Authorization=`Bearer ${r}`);const i=await fetch(e,{method:"POST",headers:n,body:JSON.stringify(t)});return i.ok?i.json():{verified:!1,message:`Server error: ${i.status}`}}const Ye=(e,t)=>t,Le=h.createContext(Ye),Ze=({t:e,children:t})=>s.jsx(Le.Provider,{value:e,children:t});function X(){return{t:h.useContext(Le)}}const Xe={sm:200,md:280,lg:380},Qe=e=>{const{mode:t,enrolledTemplates:r=[],fingerPosition:n="right-index",onEnroll:i,onVerify:a,onStatusChange:o,onError:c,className:m,size:x="md",label:y,showQuality:v=!0,showMinutiae:A=!1,instructionText:g,cameraFacing:I="environment",...D}=e,{t:b}=X(),T=ie(D),p=Xe[x],k=h.useRef(null),u=h.useRef(null),w=h.useRef(null),[l,f]=h.useState("idle"),[z,O]=h.useState(0),[J,B]=h.useState(null),[H,G]=h.useState(0),[W,L]=h.useState(""),$=h.useCallback(P=>{f(P),o==null||o(P)},[o]),E=h.useCallback(async()=>{try{const P=await oe(I);w.current=P,k.current&&(k.current.srcObject=P,await k.current.play()),$("idle"),L(b("security.fingerprint.placeFingerPrompt","Place your finger on the scanner"))}catch(P){c==null||c(P instanceof Error?P:new Error(String(P))),L(b("security.fingerprint.cameraError","Camera access denied")),$("error")}},[I,b,$,c]),q=h.useCallback(()=>{var P;(P=w.current)==null||P.getTracks().forEach(C=>C.stop()),w.current=null},[]);h.useEffect(()=>(E(),q),[E,q]);const _=h.useCallback(async()=>{if(!(!k.current||l==="processing"||l==="success")){$("scanning"),L(b("security.fingerprint.scanning","Scanning…"));try{const{imageData:P}=te(k.current);$("processing"),L(b("security.fingerprint.processing","Processing fingerprint…"));const C=ke(P);if(B(C),O(C.quality),C.quality<.2){L(b("security.fingerprint.lowQuality","Low quality — try again")),$("idle");return}if(t==="enroll"){const F=await je(C,y??n);i==null||i(F,C),L(b("security.fingerprint.enrolled","Fingerprint enrolled successfully")),$("success")}else{let F=0;for(const d of r){const j=Te(d),N=Ae(C,j);N>F&&(F=N)}const R=F>=T.matchThreshold,S={success:R,confidence:F,method:"fingerprint",timestamp:Date.now(),duration:0,payload:btoa(JSON.stringify(C))};if(R&&T.verifyEndpoint){const d=await se(),j=await ce(T.verifyEndpoint,{method:"fingerprint",templateData:S.payload,matchScore:F,deviceFingerprint:d},T.authToken);S.success=j.verified}S.success?(L(b("security.fingerprint.verified","Fingerprint verified")),$("success")):(G(d=>d+1),H+1>=T.maxRetries?(L(b("security.fingerprint.maxAttempts","Maximum attempts reached")),$("failure")):(L(b("security.fingerprint.noMatch","No match — try again")),$("idle"))),a==null||a(S)}}catch(P){c==null||c(P instanceof Error?P:new Error(String(P))),L(b("security.fingerprint.error","Scan error — try again")),$("error")}}},[l,t,r,T,b,$,i,a,c,y,n,H]);h.useEffect(()=>{if(!A||!J||!u.current)return;const P=u.current.getContext("2d");P&&(P.clearRect(0,0,p,p),J.minutiae.forEach(C=>{P.beginPath(),P.arc(C.x*p,C.y*p,2,0,Math.PI*2),P.fillStyle=C.type==="ending"?"#10b981":"#f59e0b",P.fill(),P.beginPath(),P.moveTo(C.x*p,C.y*p),P.lineTo(C.x*p+Math.cos(C.angle)*8,C.y*p+Math.sin(C.angle)*8),P.strokeStyle=P.fillStyle,P.lineWidth=1,P.stroke()}))},[J,A,p]);const Y=l==="success"?"var(--security-success)":l==="failure"||l==="error"?"var(--security-error)":l==="scanning"||l==="processing"?"var(--security-biometric)":"var(--security-border)";return s.jsxs("div",{className:m,style:{display:"inline-flex",flexDirection:"column",alignItems:"center",gap:12},children:[y&&s.jsx("div",{style:{fontSize:14,fontWeight:600,color:"var(--security-text)"},children:y}),s.jsxs("div",{style:{width:p,height:p,position:"relative",borderRadius:"var(--security-radius-lg)",overflow:"hidden",border:`3px solid ${Y}`,boxShadow:l==="scanning"?`0 0 20px ${Y}`:"var(--security-shadow)",transition:"border-color 0.3s, box-shadow 0.3s"},children:[s.jsx("video",{ref:k,style:{width:"100%",height:"100%",objectFit:"cover"},playsInline:!0,muted:!0}),A&&s.jsx("canvas",{ref:u,width:p,height:p,style:{position:"absolute",inset:0,pointerEvents:"none"}}),s.jsxs("svg",{viewBox:"0 0 100 100",style:{position:"absolute",inset:0,width:"100%",height:"100%",pointerEvents:"none",opacity:.3},children:[s.jsx("ellipse",{cx:"50",cy:"50",rx:"28",ry:"38",fill:"none",stroke:"white",strokeWidth:"1",strokeDasharray:"4 3"}),s.jsx("ellipse",{cx:"50",cy:"50",rx:"20",ry:"28",fill:"none",stroke:"white",strokeWidth:"0.5",strokeDasharray:"2 3"})]}),(l==="scanning"||l==="processing")&&s.jsx("div",{style:{position:"absolute",inset:0,display:"flex",alignItems:"center",justifyContent:"center",background:"rgba(0,0,0,0.3)"},children:s.jsx("div",{style:{width:60,height:60,borderRadius:"50%",border:"3px solid transparent",borderTopColor:Y,animation:"spin 0.8s linear infinite"}})})]}),v&&z>0&&s.jsx("div",{style:{width:p,height:4,background:"var(--security-bg-panel)",borderRadius:2,overflow:"hidden"},children:s.jsx("div",{style:{width:`${z*100}%`,height:"100%",background:z>.6?"var(--security-success)":z>.3?"var(--security-warning)":"var(--security-error)",transition:"width 0.3s"}})}),s.jsx("div",{style:{fontSize:13,color:"var(--security-text-secondary)",textAlign:"center",minHeight:20},children:g??W}),l!=="success"&&l!=="failure"&&s.jsx("button",{onClick:_,disabled:l==="scanning"||l==="processing",style:{padding:"10px 24px",fontSize:14,fontWeight:600,background:"var(--security-biometric)",color:"#fff",border:"none",borderRadius:"var(--security-radius)",cursor:"pointer",opacity:l==="scanning"||l==="processing"?.6:1},children:t==="enroll"?b("security.fingerprint.captureBtn","🖐️ Capture Fingerprint"):b("security.fingerprint.verifyBtn","🖐️ Verify Fingerprint")}),(l==="failure"||l==="error")&&s.jsx("button",{onClick:()=>{G(0),$("idle"),L("")},style:{padding:"8px 20px",fontSize:13,background:"var(--security-bg-panel)",color:"var(--security-text)",border:"1px solid var(--security-border)",borderRadius:"var(--security-radius)",cursor:"pointer"},children:b("security.common.retry","Try Again")}),s.jsx("style",{children:"@keyframes spin { to { transform: rotate(360deg); } }"})]})},Ve={sm:220,md:300,lg:400},et=e=>{const{mode:t,enrolledTemplates:r=[],eye:n="right",onEnroll:i,onVerify:a,onStatusChange:o,onError:c,className:m,size:x="md",label:y,showQuality:v=!0,showSegmentation:A=!0,showGuide:g=!0,instructionText:I,...D}=e,{t:b}=X(),T=ie(D),p=Ve[x],k=h.useRef(null),u=h.useRef(null),w=h.useRef(null),l=h.useRef([]),[f,z]=h.useState("idle"),[O,J]=h.useState(0),[B,H]=h.useState(null),[G,W]=h.useState(0),[L,$]=h.useState(""),E=h.useCallback(C=>{z(C),o==null||o(C)},[o]),q=h.useCallback(async()=>{try{const C=await oe("user");w.current=C,k.current&&(k.current.srcObject=C,await k.current.play()),E("idle"),$(b("security.iris.alignEyePrompt","Align your eye with the circle"))}catch(C){c==null||c(C instanceof Error?C:new Error(String(C))),$(b("security.iris.cameraError","Camera access denied")),E("error")}},[b,E,c]),_=h.useCallback(()=>{var C;(C=w.current)==null||C.getTracks().forEach(F=>F.stop()),w.current=null},[]);h.useEffect(()=>(q(),_),[q,_]);const Y=h.useCallback(async()=>{if(!(!k.current||f==="processing"||f==="success")){E("scanning"),$(b("security.iris.scanning","Scanning iris…"));try{const C=[];for(let S=0;S<5;S++){const{imageData:d}=te(k.current);C.push(d),await new Promise(j=>setTimeout(j,200))}if(l.current=C,T.livenessDetection&&!de(C).isLive){$(b("security.iris.notLive","Liveness check failed — please blink or move slightly")),E("idle");return}E("processing"),$(b("security.iris.processing","Processing iris pattern…"));const F=C[C.length-1],R=Ce(F,n==="both"?"left":n);if(!R){$(b("security.iris.noIrisDetected","No iris detected — adjust position")),E("idle");return}if(H(R),J(R.quality),R.quality<.1){$(b("security.iris.lowQuality","Low quality — move closer")),E("idle");return}if(A&&u.current){const S=u.current.getContext("2d");if(S){S.clearRect(0,0,p,p);const d=p/F.width,j=p/F.height;S.beginPath(),S.arc(R.pupil.cx*d,R.pupil.cy*j,R.pupil.r*d,0,Math.PI*2),S.strokeStyle="#ef4444",S.lineWidth=2,S.stroke(),S.beginPath(),S.arc(R.iris.cx*d,R.iris.cy*j,R.iris.r*d,0,Math.PI*2),S.strokeStyle="#3b82f6",S.lineWidth=2,S.stroke()}}if(t==="enroll"){const S=await Re(R,y??`${n} eye`);i==null||i(S,R),$(b("security.iris.enrolled","Iris enrolled successfully")),E("success")}else{let S=0;for(const N of r){const M=De(N),U=Ie(R,M);U>S&&(S=U)}const d=S>=T.matchThreshold,j={success:d,confidence:S,method:"iris",timestamp:Date.now(),duration:0,livenessPassed:T.livenessDetection?!0:void 0,payload:btoa(JSON.stringify(R))};if(d&&T.verifyEndpoint){const N=await se(),M=await ce(T.verifyEndpoint,{method:"iris",templateData:j.payload,matchScore:S,deviceFingerprint:N},T.authToken);j.success=M.verified}j.success?($(b("security.iris.verified","Iris verified")),E("success")):(W(N=>N+1),G+1>=T.maxRetries?($(b("security.iris.maxAttempts","Maximum attempts reached")),E("failure")):($(b("security.iris.noMatch","No match — try again")),E("idle"))),a==null||a(j)}}catch(C){c==null||c(C instanceof Error?C:new Error(String(C))),$(b("security.iris.error","Scan error")),E("error")}}},[f,t,r,T,b,E,i,a,c,y,n,G,A,p]),P=f==="success"?"var(--security-success)":f==="failure"||f==="error"?"var(--security-error)":f==="scanning"||f==="processing"?"var(--security-biometric)":"var(--security-border)";return s.jsxs("div",{className:m,style:{display:"inline-flex",flexDirection:"column",alignItems:"center",gap:12},children:[y&&s.jsx("div",{style:{fontSize:14,fontWeight:600,color:"var(--security-text)"},children:y}),s.jsxs("div",{style:{width:p,height:p,position:"relative",borderRadius:"50%",overflow:"hidden",border:`3px solid ${P}`,boxShadow:f==="scanning"?`0 0 30px ${P}`:"var(--security-shadow)",transition:"border-color 0.3s, box-shadow 0.3s"},children:[s.jsx("video",{ref:k,style:{width:"100%",height:"100%",objectFit:"cover"},playsInline:!0,muted:!0}),A&&s.jsx("canvas",{ref:u,width:p,height:p,style:{position:"absolute",inset:0,pointerEvents:"none"}}),g&&f==="idle"&&s.jsxs("svg",{viewBox:"0 0 100 100",style:{position:"absolute",inset:0,width:"100%",height:"100%",pointerEvents:"none",opacity:.4},children:[s.jsx("circle",{cx:"50",cy:"50",r:"35",fill:"none",stroke:"white",strokeWidth:"1",strokeDasharray:"5 3"}),s.jsx("circle",{cx:"50",cy:"50",r:"15",fill:"none",stroke:"white",strokeWidth:"0.5",strokeDasharray:"3 3"}),s.jsx("line",{x1:"50",y1:"10",x2:"50",y2:"25",stroke:"white",strokeWidth:"0.5",opacity:"0.5"}),s.jsx("line",{x1:"50",y1:"75",x2:"50",y2:"90",stroke:"white",strokeWidth:"0.5",opacity:"0.5"}),s.jsx("line",{x1:"10",y1:"50",x2:"25",y2:"50",stroke:"white",strokeWidth:"0.5",opacity:"0.5"}),s.jsx("line",{x1:"75",y1:"50",x2:"90",y2:"50",stroke:"white",strokeWidth:"0.5",opacity:"0.5"})]}),(f==="scanning"||f==="processing")&&s.jsx("div",{style:{position:"absolute",inset:0,display:"flex",alignItems:"center",justifyContent:"center",background:"rgba(0,0,0,0.2)"},children:s.jsx("div",{style:{width:p*.7,height:3,background:P,animation:"irisLineAnim 1.5s ease-in-out infinite",position:"absolute",opacity:.7}})})]}),s.jsx("div",{style:{fontSize:11,color:"var(--security-text-muted)",textTransform:"uppercase",letterSpacing:1},children:n==="both"?b("security.iris.bothEyes","Both eyes"):n==="left"?b("security.iris.leftEye","Left eye"):b("security.iris.rightEye","Right eye")}),v&&O>0&&s.jsx("div",{style:{width:p*.6,height:4,background:"var(--security-bg-panel)",borderRadius:2,overflow:"hidden"},children:s.jsx("div",{style:{width:`${Math.min(100,O*300)}%`,height:"100%",background:O>.3?"var(--security-success)":O>.1?"var(--security-warning)":"var(--security-error)",transition:"width 0.3s"}})}),s.jsx("div",{style:{fontSize:13,color:"var(--security-text-secondary)",textAlign:"center",minHeight:20},children:I??L}),f!=="success"&&f!=="failure"&&s.jsx("button",{onClick:Y,disabled:f==="scanning"||f==="processing",style:{padding:"10px 24px",fontSize:14,fontWeight:600,background:"var(--security-biometric)",color:"#fff",border:"none",borderRadius:"var(--security-radius)",cursor:"pointer",opacity:f==="scanning"||f==="processing"?.6:1},children:t==="enroll"?b("security.iris.captureBtn","👁️ Capture Iris"):b("security.iris.verifyBtn","👁️ Verify Iris")}),(f==="failure"||f==="error")&&s.jsx("button",{onClick:()=>{W(0),E("idle"),$("")},style:{padding:"8px 20px",fontSize:13,background:"var(--security-bg-panel)",color:"var(--security-text)",border:"1px solid var(--security-border)",borderRadius:"var(--security-radius)",cursor:"pointer"},children:b("security.common.retry","Try Again")}),s.jsx("style",{children:`
|
|
2
|
+
@keyframes irisLineAnim {
|
|
3
|
+
0%, 100% { transform: translateY(-${p*.3}px); opacity: 0.3; }
|
|
4
|
+
50% { transform: translateY(${p*.3}px); opacity: 0.8; }
|
|
5
|
+
}
|
|
6
|
+
`})]})},tt={sm:240,md:320,lg:440},rt=e=>{const{mode:t,enrolledTemplates:r=[],referencePhoto:n,onEnroll:i,onVerify:a,onStatusChange:o,onError:c,className:m,size:x="md",label:y,showQuality:v=!0,showBoundingBox:A=!0,livenessSteps:g=1,showReference:I=!0,instructionText:D,...b}=e,{t:T}=X(),p=ie(b),k=tt[x],u=h.useRef(null),w=h.useRef(null),l=h.useRef(null),[f,z]=h.useState("idle"),[O,J]=h.useState(0),[B,H]=h.useState(0),[G,W]=h.useState(""),[L,$]=h.useState(null),[E,q]=h.useState(0),_=h.useCallback(S=>{z(S),o==null||o(S)},[o]),Y=h.useCallback(async()=>{try{const S=await oe("user");l.current=S,u.current&&(u.current.srcObject=S,await u.current.play()),_("idle"),W(T("security.face.lookAtCamera","Look at the camera"))}catch(S){c==null||c(S instanceof Error?S:new Error(String(S))),W(T("security.face.cameraError","Camera access denied")),_("error")}},[T,_,c]),P=h.useCallback(()=>{var S;(S=l.current)==null||S.getTracks().forEach(d=>d.stop()),l.current=null},[]);h.useEffect(()=>(Y(),P),[Y,P]);const C=h.useCallback(S=>{var ge,me,ve;const d=(ge=w.current)==null?void 0:ge.getContext("2d");if(!d)return;const j=w.current.width,N=w.current.height;if(d.clearRect(0,0,j,N),!S||!A)return;const M=S.boundingBox,U=j/(((me=u.current)==null?void 0:me.videoWidth)??j),K=N/(((ve=u.current)==null?void 0:ve.videoHeight)??N);d.strokeStyle=f==="success"?"#10b981":"#3b82f6",d.lineWidth=2,d.setLineDash([6,4]),d.strokeRect(M.x*U,M.y*K,M.width*U,M.height*K),d.setLineDash([]);const Z=[[M.x*U,M.y*K],[(M.x+M.width)*U,M.y*K],[M.x*U,(M.y+M.height)*K],[(M.x+M.width)*U,(M.y+M.height)*K]],Q=12;d.lineWidth=3;for(const[V,ee]of Z)d.beginPath(),d.moveTo(V===M.x*U?V:V-Q,ee),d.lineTo(V,ee),d.lineTo(V,ee===M.y*K?ee+Q:ee-Q),d.stroke()},[A,f]),F=h.useCallback(async()=>{if(!(!u.current||f==="processing"||f==="success")){_("scanning"),W(T("security.face.scanning","Scanning face…"));try{if(p.livenessDetection){const j=[];for(let M=0;M<8;M++)j.push(te(u.current).imageData),await new Promise(U=>setTimeout(U,200));if(!de(j).isLive){W(T("security.face.notLive","Liveness check failed — move naturally")),_("idle");return}}_("processing"),W(T("security.face.processing","Analysing face…"));const{imageData:S}=te(u.current);if(t==="compare"&&n){const j=typeof n=="string"?await st(n):nt(n),{similarity:N,cameraFeatures:M,refFeatures:U}=Me(S,j);q(N),J((M==null?void 0:M.quality)??0),C(M);const Z={success:N>=p.matchThreshold,confidence:N,method:"face",timestamp:Date.now(),duration:0,livenessPassed:p.livenessDetection};Z.success?(W(T("security.face.matchFound",`Match: ${(N*100).toFixed(0)}%`)),_("success")):(H(Q=>Q+1),B+1>=p.maxRetries?(W(T("security.face.maxAttempts","Maximum attempts reached")),_("failure")):(W(T("security.face.noMatch","No match — try again")),_("idle"))),a==null||a(Z);return}const d=ne(S);if(!d){W(T("security.face.noFaceDetected","No face detected")),_("idle");return}if(J(d.quality),C(d),t==="enroll"){const j=await Pe(d,y??"face");i==null||i(j,d),W(T("security.face.enrolled","Face enrolled successfully")),_("success")}else{let j=0;for(const U of r){const K=Ee(U),Z=ue(d,K);Z>j&&(j=Z)}q(j);const N=j>=p.matchThreshold,M={success:N,confidence:j,method:"face",timestamp:Date.now(),duration:0,livenessPassed:p.livenessDetection};if(N&&p.verifyEndpoint){const U=await se(),K=await ce(p.verifyEndpoint,{method:"face",templateData:btoa(JSON.stringify(d)),matchScore:j,deviceFingerprint:U},p.authToken);M.success=K.verified}M.success?(W(T("security.face.verified","Face verified")),_("success")):(H(U=>U+1),B+1>=p.maxRetries?(W(T("security.face.maxAttempts","Maximum attempts reached")),_("failure")):(W(T("security.face.noMatch","No match — try again")),_("idle"))),a==null||a(M)}}catch(S){c==null||c(S instanceof Error?S:new Error(String(S))),W(T("security.face.error","Error — try again")),_("error")}}},[f,t,r,n,p,T,_,i,a,c,y,B,C]),R=f==="success"?"var(--security-success)":f==="failure"||f==="error"?"var(--security-error)":f==="scanning"||f==="processing"?"var(--security-biometric)":"var(--security-border)";return s.jsxs("div",{className:m,style:{display:"inline-flex",flexDirection:"column",alignItems:"center",gap:12},children:[y&&s.jsx("div",{style:{fontSize:14,fontWeight:600,color:"var(--security-text)"},children:y}),s.jsxs("div",{style:{display:"flex",gap:16,alignItems:"center"},children:[s.jsxs("div",{style:{width:k,height:k*.75,position:"relative",borderRadius:"var(--security-radius-lg)",overflow:"hidden",border:`3px solid ${R}`,boxShadow:f==="scanning"?`0 0 20px ${R}`:"var(--security-shadow)",transition:"border-color 0.3s, box-shadow 0.3s"},children:[s.jsx("video",{ref:u,style:{width:"100%",height:"100%",objectFit:"cover",transform:"scaleX(-1)"},playsInline:!0,muted:!0}),s.jsx("canvas",{ref:w,width:k,height:k*.75,style:{position:"absolute",inset:0,pointerEvents:"none",transform:"scaleX(-1)"}}),s.jsx("svg",{viewBox:"0 0 100 75",style:{position:"absolute",inset:0,width:"100%",height:"100%",pointerEvents:"none",opacity:.3},children:s.jsx("ellipse",{cx:"50",cy:"37",rx:"22",ry:"30",fill:"none",stroke:"white",strokeWidth:"0.8",strokeDasharray:"4 3"})}),(f==="scanning"||f==="processing")&&s.jsx("div",{style:{position:"absolute",inset:0,background:"rgba(0,0,0,0.15)",display:"flex",alignItems:"center",justifyContent:"center"},children:s.jsx("div",{style:{width:50,height:50,borderRadius:"50%",border:"3px solid transparent",borderTopColor:R,animation:"spin 0.8s linear infinite"}})})]}),t==="compare"&&I&&n&&s.jsxs("div",{style:{width:k*.4,height:k*.5,borderRadius:"var(--security-radius)",overflow:"hidden",border:"2px solid var(--security-border)"},children:[s.jsx("img",{src:typeof n=="string"?n:void 0,alt:"Reference",style:{width:"100%",height:"100%",objectFit:"cover"}}),s.jsx("div",{style:{textAlign:"center",fontSize:10,padding:4,color:"var(--security-text-muted)",background:"var(--security-bg-panel)"},children:T("security.face.reference","Reference")})]})]}),E>0&&s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,fontSize:13},children:[s.jsxs("span",{style:{color:"var(--security-text-secondary)"},children:[T("security.face.confidence","Confidence"),":"]}),s.jsx("div",{style:{width:100,height:6,background:"var(--security-bg-panel)",borderRadius:3,overflow:"hidden"},children:s.jsx("div",{style:{width:`${E*100}%`,height:"100%",background:E>=p.matchThreshold?"var(--security-success)":"var(--security-warning)"}})}),s.jsxs("span",{style:{fontWeight:600,color:E>=p.matchThreshold?"var(--security-success)":"var(--security-warning)"},children:[(E*100).toFixed(0),"%"]})]}),s.jsx("div",{style:{fontSize:13,color:"var(--security-text-secondary)",textAlign:"center",minHeight:20},children:D??G}),f!=="success"&&f!=="failure"&&s.jsx("button",{onClick:F,disabled:f==="scanning"||f==="processing",style:{padding:"10px 24px",fontSize:14,fontWeight:600,background:"var(--security-biometric)",color:"#fff",border:"none",borderRadius:"var(--security-radius)",cursor:"pointer",opacity:f==="scanning"||f==="processing"?.6:1},children:t==="enroll"?T("security.face.captureBtn","📸 Capture Face"):t==="compare"?T("security.face.compareBtn","📸 Compare"):T("security.face.verifyBtn","📸 Verify Face")}),(f==="failure"||f==="error")&&s.jsx("button",{onClick:()=>{H(0),q(0),_("idle"),W("")},style:{padding:"8px 20px",fontSize:13,background:"var(--security-bg-panel)",color:"var(--security-text)",border:"1px solid var(--security-border)",borderRadius:"var(--security-radius)",cursor:"pointer"},children:T("security.common.retry","Try Again")}),s.jsx("style",{children:"@keyframes spin { to { transform: rotate(360deg); } }"})]})};async function st(e){return new Promise((t,r)=>{const n=new Image;n.crossOrigin="anonymous",n.onload=()=>{const i=document.createElement("canvas");i.width=n.naturalWidth,i.height=n.naturalHeight;const a=i.getContext("2d");a.drawImage(n,0,0),t(a.getImageData(0,0,i.width,i.height))},n.onerror=()=>r(new Error("Failed to load reference image")),n.src=e})}function nt(e){const t=document.createElement("canvas");t.width=e.naturalWidth||e.width,t.height=e.naturalHeight||e.height;const r=t.getContext("2d");return r.drawImage(e,0,0),r.getImageData(0,0,t.width,t.height)}const it=4,at=5,ot=3e4,ct=e=>{const{length:t=it,scramble:r=!1,showDigits:n=!1,maxAttempts:i=at,lockoutDuration:a=ot,keySize:o=64,haptic:c=!0,keyLabels:m,expectedHash:x,expectedPin:y,mode:v="verify",onComplete:A,onVerify:g,onStatusChange:I,onError:D,showBiometricFallback:b=!1,onBiometricFallback:T,label:p,className:k}=e,{t:u}=X(),[w,l]=h.useState([]),[f,z]=h.useState("idle"),[O,J]=h.useState(0),[B,H]=h.useState(0),[G,W]=h.useState(null),L=h.useRef(),$=h.useMemo(()=>{const F=["1","2","3","4","5","6","7","8","9","","0","back"];if(!r)return F;const R=["0","1","2","3","4","5","6","7","8","9"];for(let S=R.length-1;S>0;S--){const d=new Uint32Array(1);crypto.getRandomValues(d);const j=d[0]%(S+1);[R[S],R[j]]=[R[j],R[S]]}return[R[0],R[1],R[2],R[3],R[4],R[5],R[6],R[7],R[8],"",R[9],"back"]},[r,f]),E=h.useCallback(F=>{z(F),I==null||I(F)},[I]);h.useEffect(()=>{if(!(B<=Date.now()))return L.current=setInterval(()=>{Date.now()>=B&&(clearInterval(L.current),E("idle"),J(0),l([]))},500),()=>clearInterval(L.current)},[B,E]);const q=B>Date.now(),_=h.useCallback(()=>{c&&navigator.vibrate&&navigator.vibrate(20)},[c]),Y=h.useCallback(async F=>{if(q||f==="success")return;if(_(),F==="back"){l(j=>j.slice(0,-1));return}if(F==="")return;const R=[...w,F];if(l(R),R.length<t)return;const S=R.join("");if(E("processing"),v==="set"){if(G===null){W(S),l([]),E("idle");return}if(G!==S){W(null),l([]),E("failure"),setTimeout(()=>E("idle"),1200);return}A==null||A(S),E("success");return}let d=!1;if(x){const j=new TextEncoder,N=await crypto.subtle.digest("SHA-256",j.encode(S));d=Array.from(new Uint8Array(N)).map(U=>U.toString(16).padStart(2,"0")).join("")===x}else if(y)d=S===y;else{A==null||A(S),E("success");return}if(d)E("success"),g==null||g({success:!0,confidence:1,method:"pin",timestamp:Date.now(),duration:0}),A==null||A(S);else{const j=O+1;if(J(j),j>=i){const N=Date.now()+a;H(N),E("failure"),D==null||D(new Error("Too many failed PIN attempts"))}else E("failure"),setTimeout(()=>{E("idle"),l([])},800);g==null||g({success:!1,confidence:0,method:"pin",timestamp:Date.now(),duration:0})}},[w,t,q,f,v,G,x,y,O,i,a,_,E,A,g,D]),P=Math.max(0,Math.ceil((B-Date.now())/1e3)),C=f==="success"?"var(--security-success)":f==="failure"?"var(--security-error)":"var(--security-border)";return s.jsxs("div",{className:k,style:{display:"inline-flex",flexDirection:"column",alignItems:"center",gap:16,fontFamily:"var(--security-font)",color:"var(--security-text)"},children:[p&&s.jsx("div",{style:{fontSize:14,fontWeight:600},children:p}),s.jsx("div",{style:{fontSize:13,color:"var(--security-text-secondary)",minHeight:18,textAlign:"center"},children:q?u("security.pin.locked",`Locked — try again in ${P}s`):v==="set"&&G!==null?u("security.pin.confirm","Confirm your PIN"):v==="set"?u("security.pin.setNew","Enter a new PIN"):u("security.pin.enter","Enter your PIN")}),s.jsx("div",{style:{display:"flex",gap:12},children:Array.from({length:t},(F,R)=>s.jsx("div",{style:{width:16,height:16,borderRadius:"50%",border:`2px solid ${C}`,background:R<w.length?C:"transparent",transition:"background 0.15s, border-color 0.15s"}},R))}),s.jsx("div",{style:{display:"grid",gridTemplateColumns:`repeat(3, ${o}px)`,gap:10,opacity:q?.4:1,pointerEvents:q?"none":"auto"},children:$.map((F,R)=>{if(F==="")return s.jsx("div",{},R);const S=F==="back";return s.jsx("button",{onClick:()=>Y(F),disabled:q||f==="success","aria-label":S?"Backspace":F,style:{width:o,height:o,borderRadius:"var(--security-key-border-radius, 50%)",border:"1px solid var(--security-key-border, var(--security-border))",background:"var(--security-key-bg, var(--security-bg-panel))",color:"var(--security-key-text, var(--security-text))",fontSize:S?20:22,fontWeight:600,cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",transition:"background 0.1s, transform 0.1s",userSelect:"none"},onMouseDown:d=>{d.currentTarget.style.transform="scale(0.92)"},onMouseUp:d=>{d.currentTarget.style.transform=""},onMouseLeave:d=>{d.currentTarget.style.transform=""},children:S?"⌫":(m==null?void 0:m[F])??F},R)})}),w.length>0&&f!=="success"&&s.jsx("button",{onClick:()=>l([]),style:{fontSize:12,background:"none",border:"none",color:"var(--security-text-secondary)",cursor:"pointer",textDecoration:"underline"},children:u("security.pin.clear","Clear")}),b&&s.jsxs("button",{onClick:T,style:{fontSize:13,padding:"8px 16px",background:"none",border:"1px solid var(--security-border)",borderRadius:"var(--security-radius)",color:"var(--security-biometric)",cursor:"pointer"},children:["🔐 ",u("security.pin.biometricFallback","Use biometrics instead")]}),O>0&&f!=="success"&&!q&&s.jsx("div",{style:{fontSize:11,color:"var(--security-warning)"},children:u("security.pin.attempts",`${O}/${i} attempts`)})]})},lt=3,ut=4,dt=5,ht=14,ft=e=>{const{gridSize:t=lt,minLength:r=ut,showTrail:n=!0,showError:i=!0,maxAttempts:a=dt,dotSize:o=ht,trailColor:c,mode:m="verify",expectedHash:x,expectedPattern:y,onComplete:v,onVerify:A,onStatusChange:g,onError:I,label:D,className:b,canvasSize:T}=e,{t:p}=X(),k=h.useRef(null),[u,w]=h.useState([]),[l,f]=h.useState(!1),[z,O]=h.useState("idle"),[J,B]=h.useState(0),[H,G]=h.useState(null),[W,L]=h.useState(null),$=T??t*80,E=$/t,q=h.useCallback(d=>{O(d),g==null||g(d)},[g]),_=h.useCallback(()=>{const d=[];for(let j=0;j<t;j++)for(let N=0;N<t;N++)d.push({x:N*E+E/2,y:j*E+E/2});return d},[t,E]),Y=h.useCallback(d=>{const j=k.current.getBoundingClientRect(),N="touches"in d?d.touches[0].clientX:d.clientX,M="touches"in d?d.touches[0].clientY:d.clientY;return{x:N-j.left,y:M-j.top}},[]),P=h.useCallback((d,j)=>{const N=_(),M=E*.38;for(let U=0;U<N.length;U++){const K=N[U].x-d,Z=N[U].y-j;if(K*K+Z*Z<M*M)return U}return-1},[_,E]),C=h.useCallback(()=>{var U;const d=(U=k.current)==null?void 0:U.getContext("2d");if(!d)return;d.clearRect(0,0,$,$);const j=_(),M=z==="failure"&&i?"var(--security-error)":c??"var(--security-biometric)";for(let K=0;K<j.length;K++){const Z=u.includes(K);d.beginPath(),d.arc(j[K].x,j[K].y,Z?o*.75:o*.5,0,Math.PI*2),d.fillStyle=Z?M:"var(--security-border)",d.fill(),Z&&(d.beginPath(),d.arc(j[K].x,j[K].y,o*1.2,0,Math.PI*2),d.strokeStyle=M,d.lineWidth=1.5,d.globalAlpha=.3,d.stroke(),d.globalAlpha=1)}if(n&&u.length>1){d.beginPath(),d.moveTo(j[u[0]].x,j[u[0]].y);for(let K=1;K<u.length;K++)d.lineTo(j[u[K]].x,j[u[K]].y);l&&W&&d.lineTo(W.x,W.y),d.strokeStyle=M,d.lineWidth=3,d.lineCap="round",d.lineJoin="round",d.globalAlpha=.5,d.stroke(),d.globalAlpha=1}else n&&u.length===1&&l&&W&&(d.beginPath(),d.moveTo(j[u[0]].x,j[u[0]].y),d.lineTo(W.x,W.y),d.strokeStyle=c??"var(--security-biometric)",d.lineWidth=3,d.globalAlpha=.4,d.stroke(),d.globalAlpha=1)},[$,_,o,u,l,W,z,n,i,c]);h.useEffect(()=>{C()},[C]);const F=h.useCallback(d=>{if(z==="success"||z==="failure")return;d.preventDefault();const{x:j,y:N}=Y(d),M=P(j,N);M>=0&&(f(!0),w([M]),L({x:j,y:N}))},[z,Y,P]),R=h.useCallback(d=>{if(!l)return;d.preventDefault();const{x:j,y:N}=Y(d);L({x:j,y:N});const M=P(j,N);M>=0&&!u.includes(M)&&w(U=>[...U,M])},[l,Y,P,u]),S=h.useCallback(async()=>{if(!l)return;if(f(!1),L(null),u.length<r){w([]);return}const d=u.join(",");if(m==="set"){if(H===null){G([...u]),w([]);return}if(H.join(",")!==d){G(null),q("failure"),setTimeout(()=>{q("idle"),w([])},800);return}v==null||v([...u]),q("success");return}q("processing");let j=!1;if(x){const N=new TextEncoder,M=await crypto.subtle.digest("SHA-256",N.encode(d));j=Array.from(new Uint8Array(M)).map(K=>K.toString(16).padStart(2,"0")).join("")===x}else if(y)j=d===y;else{v==null||v([...u]),q("success");return}if(j)q("success"),A==null||A({success:!0,confidence:1,method:"pattern",timestamp:Date.now(),duration:0}),v==null||v([...u]);else{const N=J+1;B(N),q("failure"),N>=a&&(I==null||I(new Error("Too many failed pattern attempts"))),setTimeout(()=>{q("idle"),w([])},900),A==null||A({success:!1,confidence:0,method:"pattern",timestamp:Date.now(),duration:0})}},[l,u,r,m,H,x,y,J,a,q,v,A,I]);return s.jsxs("div",{className:b,style:{display:"inline-flex",flexDirection:"column",alignItems:"center",gap:12,fontFamily:"var(--security-font)",color:"var(--security-text)"},children:[D&&s.jsx("div",{style:{fontSize:14,fontWeight:600},children:D}),s.jsx("div",{style:{fontSize:13,color:"var(--security-text-secondary)",minHeight:18,textAlign:"center"},children:z==="success"?p("security.pattern.success","Pattern accepted"):z==="failure"?p("security.pattern.wrong","Wrong pattern"):m==="set"&&H!==null?p("security.pattern.confirm","Draw pattern again to confirm"):m==="set"?p("security.pattern.setNew","Draw a new pattern"):p("security.pattern.draw","Draw your pattern")}),s.jsx("canvas",{ref:k,width:$,height:$,style:{touchAction:"none",borderRadius:"var(--security-radius-lg)",background:"var(--security-bg-panel)",border:`1px solid ${z==="failure"?"var(--security-error)":"var(--security-border)"}`,cursor:"pointer",transition:"border-color 0.3s"},onMouseDown:F,onMouseMove:R,onMouseUp:S,onMouseLeave:S,onTouchStart:F,onTouchMove:R,onTouchEnd:S}),(z==="failure"||z==="success")&&s.jsx("button",{onClick:()=>{w([]),B(0),G(null),q("idle")},style:{fontSize:13,padding:"6px 16px",background:"var(--security-bg-panel)",border:"1px solid var(--security-border)",borderRadius:"var(--security-radius)",color:"var(--security-text)",cursor:"pointer"},children:p("security.common.retry","Try Again")}),J>0&&z!=="success"&&s.jsx("div",{style:{fontSize:11,color:"var(--security-warning)"},children:p("security.pattern.attempts",`${J}/${a} attempts`)})]})},yt={sm:"8px 16px",md:"12px 24px",lg:"14px 32px"},pt={sm:13,md:14,lg:16},gt=e=>{const{mode:t,credentialIds:r=[],challenge:n,rpName:i=window.location.hostname,rpId:a=window.location.hostname,user:o,attestation:c="none",authenticatorAttachment:m,residentKey:x="preferred",userVerification:y="preferred",onRegister:v,onAuthenticate:A,onVerify:g,onStatusChange:I,onError:D,label:b,className:T,variant:p="primary",size:k="md",fullWidth:u=!1,icon:w}=e,{t:l}=X(),[f,z]=h.useState("idle"),[O,J]=h.useState(!0),[B,H]=h.useState(!1),G=h.useCallback(C=>{z(C),I==null||I(C)},[I]);h.useEffect(()=>{J(fe()),Fe().then(H)},[]);const W=h.useCallback(()=>{if(n){const C=atob(n.replace(/-/g,"+").replace(/_/g,"/")),F=new Uint8Array(C.length);for(let R=0;R<C.length;R++)F[R]=C.charCodeAt(R);return F.buffer}return crypto.getRandomValues(new Uint8Array(32)).buffer},[n]),L=h.useCallback(async()=>{if(!O){D==null||D(new Error("WebAuthn not available"));return}G("processing");try{if(t==="register"){const C=(o==null?void 0:o.id)??crypto.getRandomValues(new Uint8Array(16)),F=(o==null?void 0:o.name)??"user",R=(o==null?void 0:o.displayName)??F,S=W(),d=await Ne({rpName:i,rpId:a,userId:typeof C=="string"?C:Array.from(C).join(""),userName:F,userDisplayName:R,challenge:S});G("success"),d&&(v==null||v(d)),g==null||g({success:!0,confidence:1,method:"webauthn",timestamp:Date.now(),duration:0})}else{const C=await ze({rpId:a,challenge:W(),allowCredentials:r==null?void 0:r.map(F=>({id:new TextEncoder().encode(F),type:"public-key"}))});G("success"),C&&(A==null||A(C)),g==null||g({success:!0,confidence:1,method:"webauthn",timestamp:Date.now(),duration:0})}}catch(C){const F=C instanceof Error?C:new Error(String(C));F.name==="NotAllowedError"?G("idle"):(G("error"),D==null||D(F),g==null||g({success:!1,confidence:0,method:"webauthn",timestamp:Date.now(),duration:0}))}},[O,t,r,o,i,a,c,m,x,y,W,G,v,A,g,D]),$=t==="register"?B?l("security.webauthn.registerPasskey","🔑 Register Passkey"):l("security.webauthn.register","🔐 Register Security Key"):B?l("security.webauthn.signInPasskey","🔑 Sign in with Passkey"):l("security.webauthn.signIn","🔐 Sign in with Security Key"),E=b??$,q={primary:"var(--security-biometric)",outline:"transparent",ghost:"transparent"},_={primary:"none",outline:"2px solid var(--security-biometric)",ghost:"none"},Y={primary:"#fff",outline:"var(--security-biometric)",ghost:"var(--security-biometric)"},P=!O||f==="processing"||f==="success";return s.jsxs("div",{className:T,style:{display:u?"block":"inline-block",textAlign:"center"},children:[s.jsxs("button",{onClick:L,disabled:P,style:{width:u?"100%":"auto",padding:yt[k],fontSize:pt[k],fontWeight:600,fontFamily:"var(--security-font)",background:q[p],color:Y[p],border:_[p],borderRadius:"var(--security-radius)",cursor:P?"not-allowed":"pointer",opacity:P?.6:1,display:"inline-flex",alignItems:"center",justifyContent:"center",gap:8,transition:"opacity 0.2s, transform 0.1s"},children:[f==="processing"&&s.jsx("span",{style:{display:"inline-block",width:16,height:16,borderRadius:"50%",border:"2px solid transparent",borderTopColor:"currentColor",animation:"spin 0.6s linear infinite"}}),f==="success"&&s.jsx("span",{children:"✓"}),w&&f!=="processing"&&f!=="success"&&w,E]}),!O&&s.jsx("div",{style:{fontSize:11,marginTop:6,color:"var(--security-warning)"},children:l("security.webauthn.notAvailable","WebAuthn is not supported in this browser")}),f==="error"&&s.jsx("div",{style:{fontSize:11,marginTop:6,color:"var(--security-error)"},children:l("security.webauthn.error","Authentication failed — try again")}),s.jsx("style",{children:"@keyframes spin { to { transform: rotate(360deg); } }"})]})},mt={success:"✅",failure:"❌",error:"⚠️",idle:"⏸️",scanning:"🔍",processing:"⏳",timeout:"⏰"},vt=e=>e>=80?"var(--security-error)":e>=50?"var(--security-warning)":"var(--security-success)",xt=({entries:e,pageSize:t=20,showExport:r=!0,filterMethods:n,onEntryClick:i,className:a,label:o})=>{const{t:c}=X(),[m,x]=h.useState("all"),[y,v]=h.useState("all"),[A,g]=h.useState(0),I=h.useMemo(()=>{let l=[...e];return m!=="all"&&(l=l.filter(f=>f.method===m)),y!=="all"&&(l=l.filter(f=>f.status===y)),l.sort((f,z)=>z.timestamp-f.timestamp),l},[e,m,y]),D=Math.max(1,Math.ceil(I.length/t)),b=I.slice(A*t,(A+1)*t),T=h.useMemo(()=>n||Array.from(new Set(e.map(l=>l.method))),[e,n]),p=h.useMemo(()=>Array.from(new Set(e.map(l=>l.status))),[e]),k=h.useCallback(()=>{const l=new Blob([JSON.stringify(I,null,2)],{type:"application/json"}),f=URL.createObjectURL(l),z=document.createElement("a");z.href=f,z.download=`security-audit-${new Date().toISOString().slice(0,10)}.json`,z.click(),URL.revokeObjectURL(f)},[I]),u=l=>new Date(l).toLocaleString(),w={padding:"8px 12px",borderBottom:"1px solid var(--security-border)",fontSize:13,whiteSpace:"nowrap"};return s.jsxs("div",{className:a,style:{fontFamily:"var(--security-font)",color:"var(--security-text)",background:"var(--security-bg)",borderRadius:"var(--security-radius-lg)",border:"1px solid var(--security-border)",overflow:"hidden"},children:[s.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"12px 16px",background:"var(--security-bg-panel)",borderBottom:"1px solid var(--security-border)"},children:[s.jsx("div",{style:{fontWeight:600,fontSize:15},children:o??c("security.audit.title","🔒 Security Audit Log")}),s.jsxs("div",{style:{display:"flex",gap:8,alignItems:"center"},children:[s.jsxs("select",{value:m,onChange:l=>{x(l.target.value),g(0)},style:xe,children:[s.jsx("option",{value:"all",children:c("security.audit.allMethods","All methods")}),T.map(l=>s.jsx("option",{value:l,children:l},l))]}),s.jsxs("select",{value:y,onChange:l=>{v(l.target.value),g(0)},style:xe,children:[s.jsx("option",{value:"all",children:c("security.audit.allStatuses","All statuses")}),p.map(l=>s.jsx("option",{value:l,children:l},l))]}),r&&s.jsx("button",{onClick:k,style:bt,title:"Export JSON",children:"📥"})]})]}),s.jsx("div",{style:{overflowX:"auto"},children:s.jsxs("table",{style:{width:"100%",borderCollapse:"collapse"},children:[s.jsx("thead",{children:s.jsxs("tr",{style:{background:"var(--security-bg-panel)",fontSize:12,color:"var(--security-text-secondary)",textTransform:"uppercase",letterSpacing:.5},children:[s.jsx("th",{style:{...w,textAlign:"left"},children:c("security.audit.time","Time")}),s.jsx("th",{style:{...w,textAlign:"left"},children:c("security.audit.action","Action")}),s.jsx("th",{style:{...w,textAlign:"center"},children:c("security.audit.method","Method")}),s.jsx("th",{style:{...w,textAlign:"center"},children:c("security.audit.status","Status")}),s.jsx("th",{style:{...w,textAlign:"center"},children:c("security.audit.risk","Risk")}),s.jsx("th",{style:{...w,textAlign:"left"},children:c("security.audit.device","Device")})]})}),s.jsxs("tbody",{children:[b.length===0&&s.jsx("tr",{children:s.jsx("td",{colSpan:6,style:{...w,textAlign:"center",color:"var(--security-text-muted)",padding:24},children:c("security.audit.noEntries","No entries to show")})}),b.map(l=>s.jsxs("tr",{onClick:()=>i==null?void 0:i(l),style:{cursor:i?"pointer":"default"},onMouseEnter:f=>{f.currentTarget.style.background="var(--security-bg-panel)"},onMouseLeave:f=>{f.currentTarget.style.background=""},children:[s.jsx("td",{style:w,children:u(l.timestamp)}),s.jsx("td",{style:w,children:l.action}),s.jsx("td",{style:{...w,textAlign:"center"},children:s.jsx("span",{style:{padding:"2px 8px",borderRadius:12,fontSize:11,fontWeight:600,background:"var(--security-bg-panel)",border:"1px solid var(--security-border)"},children:l.method})}),s.jsxs("td",{style:{...w,textAlign:"center"},children:[mt[l.status]??"•"," ",l.status]}),s.jsx("td",{style:{...w,textAlign:"center"},children:l.riskScore!=null&&s.jsx("span",{style:{color:vt(l.riskScore),fontWeight:600},children:l.riskScore})}),s.jsx("td",{style:{...w,maxWidth:200,overflow:"hidden",textOverflow:"ellipsis"},children:l.device??"—"})]},l.id))]})]})}),D>1&&s.jsxs("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",gap:12,padding:"10px 16px",fontSize:13,color:"var(--security-text-secondary)",borderTop:"1px solid var(--security-border)"},children:[s.jsxs("button",{disabled:A===0,onClick:()=>g(A-1),style:be,children:["← ",c("security.audit.prev","Prev")]}),s.jsxs("span",{children:[A+1," / ",D]}),s.jsxs("button",{disabled:A>=D-1,onClick:()=>g(A+1),style:be,children:[c("security.audit.next","Next")," →"]})]}),s.jsx("div",{style:{padding:"6px 16px",fontSize:11,color:"var(--security-text-muted)",textAlign:"right"},children:c("security.audit.total",`${I.length} entries`)})]})},xe={fontSize:12,padding:"4px 8px",background:"var(--security-bg)",color:"var(--security-text)",border:"1px solid var(--security-border)",borderRadius:"var(--security-radius)"},bt={background:"none",border:"1px solid var(--security-border)",borderRadius:"var(--security-radius)",padding:"4px 8px",cursor:"pointer",fontSize:16},be={background:"none",border:"none",cursor:"pointer",color:"var(--security-biometric)",fontWeight:600,fontSize:13},wt={fingerprint:"👆",iris:"👁️",face:"🧑",voice:"🎙️",webauthn:"🔑",pattern:"✦",pin:"🔢",passphrase:"🔤"},St=({options:e,requiredCount:t=1,onSelect:r,onComplete:n,className:i,label:a,layout:o="grid"})=>{const{t:c}=X(),m=e.filter(y=>y.verified).length,x=m>=t;return s.jsxs("div",{className:i,style:{fontFamily:"var(--security-font)",color:"var(--security-text)",display:"flex",flexDirection:"column",gap:16},children:[a&&s.jsx("div",{style:{fontSize:15,fontWeight:600},children:a}),t>1&&s.jsx("div",{style:{fontSize:13,color:"var(--security-text-secondary)"},children:c("security.mfa.progress",`Verified ${m} of ${t} required`)}),s.jsx("div",{style:{display:o==="grid"?"grid":"flex",gridTemplateColumns:o==="grid"?"repeat(auto-fill, minmax(140px, 1fr))":void 0,flexDirection:o==="list"?"column":void 0,gap:12},children:e.map(y=>{const v=y.verified??!1,A=y.disabled||x;return s.jsxs("button",{onClick:()=>!A&&!v&&(r==null?void 0:r(y.method)),disabled:A||v,style:{display:"flex",flexDirection:o==="grid"?"column":"row",alignItems:"center",gap:o==="grid"?8:12,padding:o==="grid"?"20px 16px":"12px 16px",background:v?"rgba(16,185,129,0.08)":"var(--security-bg-panel)",border:`2px solid ${v?"var(--security-success)":"var(--security-border)"}`,borderRadius:"var(--security-radius-lg)",cursor:A||v?"default":"pointer",opacity:A&&!v?.5:1,transition:"border-color 0.2s, background 0.2s",textAlign:o==="grid"?"center":"left"},children:[s.jsx("span",{style:{fontSize:28},children:v?"✅":y.icon??wt[y.method]??"🔐"}),s.jsxs("div",{children:[s.jsx("div",{style:{fontSize:14,fontWeight:600,color:"var(--security-text)"},children:y.label??y.method}),y.description&&s.jsx("div",{style:{fontSize:11,color:"var(--security-text-muted)",marginTop:2},children:y.description})]})]},y.method)})}),x&&s.jsxs("div",{style:{textAlign:"center",fontSize:14,fontWeight:600,color:"var(--security-success)",padding:8},children:["✅ ",c("security.mfa.complete","All factors verified")]})]})},kt=({sessions:e,onRevoke:t,onRevokeAll:r,onTrust:n,className:i,label:a,showRevokeAll:o=!0})=>{const{t:c}=X(),[m,x]=h.useState(new Set),y=h.useMemo(()=>[...e].sort((g,I)=>(I.current?1:0)-(g.current?1:0)||I.lastActive-g.lastActive),[e]),v=g=>{const I=new Date(g),b=Date.now()-g;return b<6e4?c("security.session.justNow","Just now"):b<36e5?`${Math.floor(b/6e4)}m ago`:b<864e5?`${Math.floor(b/36e5)}h ago`:I.toLocaleDateString()},A=g=>{x(I=>new Set(I).add(g)),t==null||t(g)};return s.jsxs("div",{className:i,style:{fontFamily:"var(--security-font)",color:"var(--security-text)",background:"var(--security-bg)",borderRadius:"var(--security-radius-lg)",border:"1px solid var(--security-border)",overflow:"hidden"},children:[s.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"12px 16px",background:"var(--security-bg-panel)",borderBottom:"1px solid var(--security-border)"},children:[s.jsx("div",{style:{fontSize:15,fontWeight:600},children:a??c("security.session.title","🖥️ Active Sessions")}),o&&e.length>1&&s.jsx("button",{onClick:r,style:{fontSize:12,padding:"4px 12px",background:"none",border:"1px solid var(--security-error)",borderRadius:"var(--security-radius)",color:"var(--security-error)",cursor:"pointer"},children:c("security.session.revokeAll","Revoke all others")})]}),s.jsxs("div",{children:[y.map(g=>s.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"12px 16px",borderBottom:"1px solid var(--security-border)",opacity:m.has(g.id)?.5:1,background:g.current?"rgba(59,130,246,0.04)":void 0},children:[s.jsxs("div",{style:{display:"flex",gap:12,alignItems:"center"},children:[s.jsx("span",{style:{fontSize:24},children:g.device.toLowerCase().includes("mobile")?"📱":"💻"}),s.jsxs("div",{children:[s.jsxs("div",{style:{fontSize:14,fontWeight:500},children:[g.device,g.current&&s.jsx("span",{style:{marginLeft:8,fontSize:10,padding:"1px 6px",background:"var(--security-biometric)",color:"#fff",borderRadius:8},children:c("security.session.current","Current")}),g.trusted&&s.jsx("span",{style:{marginLeft:6,fontSize:10,padding:"1px 6px",background:"var(--security-success)",color:"#fff",borderRadius:8},children:c("security.session.trusted","Trusted")})]}),s.jsx("div",{style:{fontSize:12,color:"var(--security-text-muted)",marginTop:2},children:[g.browser,g.os,g.location].filter(Boolean).join(" · ")}),s.jsxs("div",{style:{fontSize:11,color:"var(--security-text-muted)",marginTop:1},children:[c("security.session.lastActive","Last active"),":"," ",v(g.lastActive)]})]})]}),s.jsxs("div",{style:{display:"flex",gap:6},children:[n&&!g.current&&s.jsx("button",{onClick:()=>n(g.id,!g.trusted),style:{fontSize:11,padding:"4px 8px",background:"none",border:"1px solid var(--security-border)",borderRadius:"var(--security-radius)",cursor:"pointer",color:"var(--security-text-secondary)"},children:g.trusted?"🚫":"✅"}),!g.current&&s.jsx("button",{onClick:()=>A(g.id),disabled:m.has(g.id),style:{fontSize:11,padding:"4px 10px",background:"none",border:"1px solid var(--security-error)",borderRadius:"var(--security-radius)",cursor:"pointer",color:"var(--security-error)"},children:c("security.session.revoke","Revoke")})]})]},g.id)),e.length===0&&s.jsx("div",{style:{padding:24,textAlign:"center",color:"var(--security-text-muted)",fontSize:13},children:c("security.session.noSessions","No active sessions")})]})]})},At=({trustScore:e,onScoreComputed:t,trustThreshold:r=60,showFactors:n=!0,showFingerprint:i=!1,className:a,label:o})=>{const{t:c}=X(),[m,x]=h.useState(e??null),[y,v]=h.useState(!e),A=h.useCallback(async()=>{var I;v(!0);try{const D=he(),b=await se(),T=[];let p=50;D.platform&&!D.platform.includes("Linux")&&(T.push({name:"Known platform",score:5,description:"Running on a recognized platform",weight:.05}),p+=5),navigator.cookieEnabled&&(T.push({name:"Cookies enabled",score:5,description:"Browser cookies are enabled",weight:.05}),p+=5),D.screenResolution[0]>=360&&D.screenResolution[1]>=640&&(T.push({name:"Standard resolution",score:5,description:"Screen resolution within normal range",weight:.05}),p+=5),typeof window<"u"&&window.isSecureContext&&(T.push({name:"Secure context",score:10,description:"Running in HTTPS secure context",weight:.1}),p+=10),((I=navigator.languages)==null?void 0:I.length)>0&&(T.push({name:"Language configured",score:5,description:"Browser language is set",weight:.05}),p+=5),D.touchSupport&&(T.push({name:"Touch device",score:5,description:"Touch input is supported",weight:.05}),p+=5);try{const l=document.createElement("canvas").getContext("webgl");l&&l.getExtension("WEBGL_debug_renderer_info")&&(T.push({name:"Hardware GPU",score:10,description:"Hardware GPU detected",weight:.1}),p+=10)}catch{}navigator.credentials&&(T.push({name:"Credential API",score:5,description:"Credential Management API available",weight:.05}),p+=5),p=Math.min(100,Math.max(0,p));const k=Date.now(),u={score:p,factors:T,trusted:p>=r,firstSeen:k,lastSeen:k,fingerprint:b};x(u),t==null||t(u)}finally{v(!1)}},[r,t]);h.useEffect(()=>{e||A()},[e,A]),h.useEffect(()=>{e&&x(e)},[e]);const g=m?m.score>=80?"var(--security-success)":m.score>=50?"var(--security-warning)":"var(--security-error)":"var(--security-text-muted)";return s.jsxs("div",{className:a,style:{fontFamily:"var(--security-font)",color:"var(--security-text)",background:"var(--security-bg-panel)",borderRadius:"var(--security-radius-lg)",border:"1px solid var(--security-border)",padding:20,display:"flex",flexDirection:"column",gap:14,alignItems:"center"},children:[s.jsx("div",{style:{fontSize:15,fontWeight:600},children:o??c("security.trust.title","🛡️ Device Trust")}),y?s.jsx("div",{style:{fontSize:13,color:"var(--security-text-muted)"},children:c("security.trust.computing","Analysing device…")}):m?s.jsxs(s.Fragment,{children:[s.jsxs("div",{style:{position:"relative",width:100,height:100},children:[s.jsxs("svg",{viewBox:"0 0 36 36",style:{width:"100%",height:"100%",transform:"rotate(-90deg)"},children:[s.jsx("circle",{cx:"18",cy:"18",r:"15.9",fill:"none",stroke:"var(--security-border)",strokeWidth:"2.5"}),s.jsx("circle",{cx:"18",cy:"18",r:"15.9",fill:"none",stroke:g,strokeWidth:"2.5",strokeDasharray:`${m.score}, 100`,strokeLinecap:"round"})]}),s.jsxs("div",{style:{position:"absolute",inset:0,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center"},children:[s.jsx("span",{style:{fontSize:24,fontWeight:700,color:g},children:m.score}),s.jsx("span",{style:{fontSize:10,color:"var(--security-text-muted)"},children:"/100"})]})]}),s.jsx("div",{style:{fontSize:14,fontWeight:600,color:m.trusted?"var(--security-success)":"var(--security-warning)"},children:m.trusted?c("security.trust.trusted","✅ Device Trusted"):c("security.trust.untrusted","⚠️ Low Trust Score")}),n&&m.factors.length>0&&s.jsxs("div",{style:{width:"100%",fontSize:12},children:[s.jsxs("div",{style:{fontWeight:600,marginBottom:6,color:"var(--security-text-secondary)"},children:[c("security.trust.factors","Contributing factors"),":"]}),s.jsx("ul",{style:{margin:0,paddingLeft:18,color:"var(--security-text-muted)"},children:m.factors.map((I,D)=>s.jsx("li",{style:{marginBottom:2},children:I.name},D))})]}),i&&m.fingerprint&&s.jsx("div",{style:{fontSize:10,color:"var(--security-text-muted)",wordBreak:"break-all",textAlign:"center",maxWidth:280,fontFamily:"monospace"},children:m.fingerprint})]}):null]})};function jt(e){if(!e)return 0;let t=0;return e.length>=8&&t++,e.length>=12&&t++,/[a-z]/.test(e)&&/[A-Z]/.test(e)&&t++,/\d/.test(e)&&t++,/[^a-zA-Z0-9]/.test(e)&&t++,/(.)\1{3,}/.test(e)&&t--,Math.max(0,Math.min(4,t))}const Tt=["Very weak","Weak","Fair","Strong","Very strong"],we=["#ef4444","#f97316","#eab308","#22c55e","#10b981"],Ct=({mode:e="verify",expectedHash:t,minStrength:r=2,minLength:n=8,onComplete:i,onVerify:a,onStatusChange:o,onError:c,label:m,placeholder:x,className:y,showStrength:v=!0,maxAttempts:A=5})=>{const{t:g}=X(),[I,D]=h.useState(""),[b,T]=h.useState(""),[p,k]=h.useState(!1),[u,w]=h.useState("idle"),[l,f]=h.useState(0),[z,O]=h.useState(""),J=h.useRef(null),B=jt(I),H=h.useCallback(L=>{w(L),o==null||o(L)},[o]),G=h.useCallback(async()=>{if(O(""),H("processing"),e==="set"){if(I.length<n){O(g("security.passphrase.tooShort",`Minimum ${n} characters`)),H("idle");return}if(B<r){O(g("security.passphrase.tooWeak","Passphrase is too weak")),H("idle");return}if(I!==b){O(g("security.passphrase.noMatch","Passphrases do not match")),H("failure"),setTimeout(()=>H("idle"),1e3);return}i==null||i(I),H("success");return}if(t){const L=new TextEncoder,$=await crypto.subtle.digest("SHA-256",L.encode(I));if(Array.from(new Uint8Array($)).map(_=>_.toString(16).padStart(2,"0")).join("")===t)H("success"),a==null||a({success:!0,confidence:1,method:"passphrase",timestamp:Date.now(),duration:0}),i==null||i(I);else{const _=l+1;f(_),_>=A?(H("failure"),c==null||c(new Error("Too many failed attempts"))):(O(g("security.passphrase.incorrect","Incorrect passphrase")),H("idle")),a==null||a({success:!1,confidence:0,method:"passphrase",timestamp:Date.now(),duration:0})}}else i==null||i(I),H("success")},[I,b,e,t,B,r,n,l,A,g,H,i,a,c]),W={width:"100%",padding:"10px 14px",fontSize:14,background:"var(--security-bg)",color:"var(--security-text)",border:`1px solid ${u==="failure"?"var(--security-error)":"var(--security-border)"}`,borderRadius:"var(--security-radius)",boxSizing:"border-box",fontFamily:"var(--security-font)"};return s.jsxs("div",{className:y,style:{display:"flex",flexDirection:"column",gap:10,maxWidth:340,fontFamily:"var(--security-font)",color:"var(--security-text)"},children:[m&&s.jsx("label",{style:{fontSize:14,fontWeight:600},children:m}),s.jsxs("div",{style:{position:"relative"},children:[s.jsx("input",{ref:J,type:p?"text":"password",value:I,onChange:L=>D(L.target.value),placeholder:x??g("security.passphrase.placeholder","Enter passphrase"),style:W,disabled:u==="success",onKeyDown:L=>L.key==="Enter"&&G()}),s.jsx("button",{type:"button",onClick:()=>k(!p),style:{position:"absolute",right:8,top:"50%",transform:"translateY(-50%)",background:"none",border:"none",cursor:"pointer",fontSize:16,color:"var(--security-text-muted)"},tabIndex:-1,children:p?"🙈":"👁️"})]}),e==="set"&&v&&I.length>0&&s.jsxs("div",{children:[s.jsx("div",{style:{display:"flex",gap:3,height:4},children:[0,1,2,3].map(L=>s.jsx("div",{style:{flex:1,borderRadius:2,background:L<B?we[B]:"var(--security-border)",transition:"background 0.2s"}},L))}),s.jsx("div",{style:{fontSize:11,marginTop:4,color:we[B]},children:g(`security.passphrase.strength${B}`,Tt[B])})]}),e==="set"&&s.jsx("input",{type:p?"text":"password",value:b,onChange:L=>T(L.target.value),placeholder:g("security.passphrase.confirmPlaceholder","Confirm passphrase"),style:W,disabled:u==="success",onKeyDown:L=>L.key==="Enter"&&G(),onPaste:L=>L.preventDefault()}),z&&s.jsx("div",{style:{fontSize:12,color:"var(--security-error)"},children:z}),s.jsx("button",{onClick:G,disabled:!I||u==="processing"||u==="success",style:{padding:"10px 20px",fontSize:14,fontWeight:600,background:u==="success"?"var(--security-success)":"var(--security-biometric)",color:"#fff",border:"none",borderRadius:"var(--security-radius)",cursor:u==="success"?"default":"pointer",opacity:!I||u==="processing"?.6:1},children:u==="success"?"✓ "+g("security.passphrase.accepted","Accepted"):e==="set"?g("security.passphrase.setBtn","Set Passphrase"):g("security.passphrase.verifyBtn","Verify")}),l>0&&u!=="success"&&s.jsx("div",{style:{fontSize:11,color:"var(--security-warning)"},children:g("security.passphrase.attempts",`${l}/${A} attempts`)})]})};function It(e){const t=[],r={defaultSrc:"default-src",scriptSrc:"script-src",styleSrc:"style-src",imgSrc:"img-src",fontSrc:"font-src",connectSrc:"connect-src",frameSrc:"frame-src",objectSrc:"object-src",mediaSrc:"media-src",workerSrc:"worker-src",childSrc:"child-src",formAction:"form-action",frameAncestors:"frame-ancestors",baseUri:"base-uri",reportUri:"report-uri",reportTo:"report-to",upgradeInsecureRequests:"upgrade-insecure-requests",blockAllMixedContent:"block-all-mixed-content"};return Object.entries(e.directives).forEach(([n,i])=>{const a=r[n];if(a){if(typeof i=="boolean")i&&t.push(a);else if(typeof i=="string")t.push(`${a} ${i}`);else if(Array.isArray(i)){let o=i;e.nonce&&(n==="scriptSrc"||n==="styleSrc")&&(o=[...o,`'nonce-${e.nonce}'`]),t.push(`${a} ${o.join(" ")}`)}}}),t.join("; ")}function Rt(e){const t="'self'";return{defaultSrc:[t],scriptSrc:[t],styleSrc:[t,"'unsafe-inline'"],imgSrc:[t,"data:","blob:",e==null?void 0:e.cdnDomain].filter(Boolean),fontSrc:[t,"data:",e==null?void 0:e.cdnDomain].filter(Boolean),connectSrc:[t,e==null?void 0:e.apiDomain,"wss:"].filter(Boolean),frameSrc:["'none'"],objectSrc:["'none'"],baseUri:[t],formAction:[t],frameAncestors:["'none'"],upgradeInsecureRequests:!0,reportUri:e==null?void 0:e.reportUri}}function Dt(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID().replace(/-/g,""):Math.random().toString(36).substring(2)+Date.now().toString(36)}const Mt={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="};function $e(e){return e.replace(/[&<>"'`=/]/g,t=>Mt[t]||t)}function Pt(e,t){let r=$e(e);return t!=null&&t.maxLength&&r.length>t.maxLength&&(r=r.substring(0,t.maxLength)),r}function Et(e){if(!e)return null;try{const t=new URL(e);return!["http:","https:","mailto:","tel:"].includes(t.protocol)||e.toLowerCase().includes("javascript:")?null:t.toString()}catch{return null}}function Ft(e){const t=["script","iframe","object","embed","form"];let r=e;t.forEach(a=>{const o=new RegExp(`<${a}[^>]*>.*?</${a}>`,"gi");r=r.replace(o,"");const c=new RegExp(`<${a}[^>]*/>`,"gi");r=r.replace(c,"")});const n=/\s+on\w+\s*=/gi;r=r.replace(n," data-removed=");const i=/javascript:/gi;return r=r.replace(i,""),r}function Nt(e,t){let r=e;if(t!=null&&t.allowedTags){const n=/<\/?([a-z][a-z0-9]*)[^>]*>/gi;r=r.replace(n,(i,a)=>t.allowedTags.includes(a.toLowerCase())?i:"")}return r=r.replace(/\s+on\w+\s*=/gi," data-removed="),r=r.replace(/javascript:/gi,""),{__html:r}}const ye={headerName:"X-CSRF-Token",cookieName:"XSRF-TOKEN",fieldName:"_csrf"};function zt(){if(typeof crypto<"u"){const e=new Uint8Array(32);return crypto.getRandomValues(e),Array.from(e,t=>t.toString(16).padStart(2,"0")).join("")}return Math.random().toString(36).substring(2)+Date.now().toString(36)}function pe(e=ye.cookieName){if(typeof document>"u")return null;const t=document.cookie.match(new RegExp(`(^| )${e}=([^;]+)`));return t?decodeURIComponent(t[2]):null}function Lt(e=ye){return async function(r,n={}){const i=pe(e.cookieName);i||console.warn("CSRF token not found");const a=new Headers(n.headers);return i&&e.headerName&&a.set(e.headerName,i),fetch(r,{...n,headers:a})}}function $t(e=ye){const t=pe(e.cookieName);return{token:t,inputProps:{type:"hidden",name:e.fieldName,value:t||""},headerName:e.headerName}}function Be(e){const t=new Map,r=e.keyGenerator||(a=>a.url);function n(a){const o=r(a),c=Date.now();let m=t.get(o);(!m||c>m.resetAt)&&(m={count:0,resetAt:c+e.windowMs}),m.count++,t.set(o,m);const x=m.count<=e.maxRequests,y=Math.max(0,e.maxRequests-m.count);return{allowed:x,remaining:y,resetAt:m.resetAt}}function i(a){a?t.delete(a):t.clear()}return{checkLimit:n,reset:i}}function Bt(e){const t=Be(e);return{checkAndFetch:async(n,i)=>{const a=t.checkLimit({url:n,method:i==null?void 0:i.method});if(!a.allowed){const o=Math.ceil((a.resetAt-Date.now())/1e3);throw new Error(`Rate limit exceeded. Retry after ${o} seconds.`)}return fetch(n,i)},checkLimit:t.checkLimit,reset:t.reset}}function We(e,t){const r=[];if(t.allowedTypes&&t.allowedTypes.length>0&&(t.allowedTypes.includes(e.type)||r.push(`File type '${e.type}' is not allowed. Allowed types: ${t.allowedTypes.join(", ")}`)),t.maxSize&&e.size>t.maxSize){const a=(t.maxSize/1048576).toFixed(2),o=(e.size/(1024*1024)).toFixed(2);r.push(`File size (${o}MB) exceeds maximum allowed size (${a}MB)`)}const n=[".exe",".bat",".cmd",".sh",".ps1",".vbs",".js",".jar"],i=e.name.toLowerCase();for(const a of n)if(i.includes(a+".")||i.endsWith(a)){r.push(`File extension '${a}' is not allowed`);break}return{valid:r.length===0,errors:r,file:r.length===0?e:void 0}}function Wt(e,t){const r=[],n=[],i=[];t.maxFiles&&e.length>t.maxFiles&&r.push(`Too many files. Maximum allowed: ${t.maxFiles}`);const a=e.reduce((o,c)=>o+c.size,0);if(t.maxTotalSize&&a>t.maxTotalSize){const o=(t.maxTotalSize/1048576).toFixed(2),c=(a/(1024*1024)).toFixed(2);r.push(`Total file size (${c}MB) exceeds maximum (${o}MB)`)}return e.forEach(o=>{const c=We(o,t);c.valid?n.push(o):i.push({file:o,errors:c.errors})}),{valid:r.length===0&&i.length===0,errors:[...r,...i.flatMap(o=>o.errors)],validFiles:n,invalidFiles:i}}async function _t(e,t){const r=new FormData;r.append("file",e);try{const n=await fetch(t,{method:"POST",body:r});if(!n.ok)throw new Error("Virus scan failed");return await n.json()}catch(n){return console.error("Virus scan error:",n),{clean:!1,threat:"Scan failed"}}}function _e(){if(typeof localStorage>"u")return null;const e=localStorage.getItem("nice2dev_consent");if(!e)return null;try{return JSON.parse(e)}catch{return null}}function Ht(e){typeof localStorage>"u"||localStorage.setItem("nice2dev_consent",JSON.stringify({...e,necessary:!0,timestamp:new Date().toISOString()}))}function Ut(e){const t=_e();return t?t[e]===!0:!1}function Ot(e){if(typeof document>"u")return;document.cookie.split(";").forEach(r=>{const[n]=r.trim().split("=");e.includes(n)||(document.cookie=`${n}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`)})}async function qt(e,t,r=fetch){const n={exportDate:new Date().toISOString(),userId:e};return await Promise.all(Object.entries(t).map(async([i,a])=>{try{const o=await r(a);o.ok&&(n[i]=await o.json())}catch(o){console.error(`Failed to fetch ${i} data:`,o),n[i]={error:"Failed to retrieve data"}}})),n}async function Kt(e,t,r=fetch){try{const n=await r(t,{method:"DELETE",headers:{"Content-Type":"application/json"},body:JSON.stringify({userId:e,timestamp:new Date().toISOString()})});return n.ok?{success:!0,confirmationId:(await n.json()).confirmationId}:{success:!1,error:"Deletion request failed"}}catch(n){return{success:!1,error:String(n)}}}function Gt(e,t){var n;const r={...e,id:((n=crypto.randomUUID)==null?void 0:n.call(crypto))||Math.random().toString(36),timestamp:new Date};return t&&fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)}).catch(console.error),process.env.NODE_ENV==="development"&&console.warn("[HIPAA] PHI Access:",r),r}function Jt(e){let t=null,r=null,n=Date.now();const i=e.timeoutMinutes*60*1e3,a=e.warningBeforeMs||6e4;function o(){n=Date.now(),t&&clearTimeout(t),r&&clearTimeout(r),e.onWarning&&(r=setTimeout(()=>{var y;const x=i-(Date.now()-n);(y=e.onWarning)==null||y.call(e,x)},i-a)),t=setTimeout(e.onTimeout,i)}function c(){t&&clearTimeout(t),r&&clearTimeout(r)}function m(){return Math.max(0,i-(Date.now()-n))}return o(),typeof window<"u"&&["mousedown","keypress","touchstart","scroll"].forEach(y=>{window.addEventListener(y,o,{passive:!0})}),{resetTimer:o,destroy:c,getTimeRemaining:m}}function Yt(e,t){const r=o=>{const c=o.replace("#",""),m=parseInt(c.substr(0,2),16)/255,x=parseInt(c.substr(2,2),16)/255,y=parseInt(c.substr(4,2),16)/255,v=A=>A<=.03928?A/12.92:Math.pow((A+.055)/1.055,2.4);return .2126*v(m)+.7152*v(x)+.0722*v(y)},n=r(e),i=r(t),a=(Math.max(n,i)+.05)/(Math.min(n,i)+.05);return{ratio:Math.round(a*100)/100,passesAA:a>=4.5,passesAAA:a>=7,passesAALarge:a>=3,passesAAALarge:a>=4.5}}function Zt(e){var r,n,i;if(e.getAttribute("aria-label"))return!0;const t=e.getAttribute("aria-labelledby");if(t){const a=document.getElementById(t);if((r=a==null?void 0:a.textContent)!=null&&r.trim())return!0}if(e.id){const a=document.querySelector(`label[for="${e.id}"]`);if((n=a==null?void 0:a.textContent)!=null&&n.trim())return!0}return!!((i=e.textContent)!=null&&i.trim()||e.getAttribute("title")||e.placeholder)}function Xt(e){const r=(e||document.body).querySelectorAll("h1, h2, h3, h4, h5, h6"),n=[];let i=0,a=!1;return r.forEach(o=>{const c=parseInt(o.tagName[1]);c===1&&(a&&n.push({level:c,element:o,issue:"Multiple H1 elements found"}),a=!0),c>i+1&&i!==0&&n.push({level:c,element:o,issue:`Skipped heading level: H${i} to H${c}`}),i=c}),!a&&r.length>0&&n.push({level:0,element:r[0],issue:"Missing H1 element"}),{valid:n.length===0,issues:n}}function Qt(e){const t=[];let r=null;const n=e.batchSize||10,i=e.flushInterval||5e3;async function a(){if(t.length===0)return;const x=t.splice(0,n);try{await fetch(e.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({entries:x})})}catch(y){console.error("Failed to send audit logs:",y),t.unshift(...x)}}function o(){r||(r=setTimeout(()=>{r=null,a()},i))}function c(x){var v;const y={...x,id:((v=crypto.randomUUID)==null?void 0:v.call(crypto))||Math.random().toString(36),timestamp:new Date,userAgent:e.includeUserAgent&&typeof navigator<"u"?navigator.userAgent:void 0};t.push(y),t.length>=n?a():o()}function m(){r&&clearTimeout(r),a()}return{log:c,flush:a,destroy:m}}function Vt(){return[{controlId:"CC6.1",name:"Logical and Physical Access Controls",category:"security",status:"in_progress",lastAssessed:new Date},{controlId:"CC6.2",name:"User Registration and Authorization",category:"security",status:"in_progress",lastAssessed:new Date},{controlId:"CC6.3",name:"Access Control Removal",category:"security",status:"in_progress",lastAssessed:new Date},{controlId:"A1.1",name:"System Capacity",category:"availability",status:"in_progress",lastAssessed:new Date},{controlId:"A1.2",name:"Backup and Recovery",category:"availability",status:"in_progress",lastAssessed:new Date},{controlId:"C1.1",name:"Confidential Information Classification",category:"confidentiality",status:"in_progress",lastAssessed:new Date},{controlId:"C1.2",name:"Confidential Information Disposal",category:"confidentiality",status:"in_progress",lastAssessed:new Date},{controlId:"P1.1",name:"Privacy Notice",category:"privacy",status:"in_progress",lastAssessed:new Date},{controlId:"P2.1",name:"Consent",category:"privacy",status:"in_progress",lastAssessed:new Date},{controlId:"P3.1",name:"Collection",category:"privacy",status:"in_progress",lastAssessed:new Date}]}const er={hardcodedSecrets:[{pattern:/password\s*[:=]\s*["'][^"']+["']/gi,name:"Hardcoded password"},{pattern:/api[_-]?key\s*[:=]\s*["'][^"']+["']/gi,name:"Hardcoded API key"},{pattern:/secret\s*[:=]\s*["'][^"']+["']/gi,name:"Hardcoded secret"},{pattern:/token\s*[:=]\s*["'][^"']+["']/gi,name:"Hardcoded token"}],sqlInjection:[{pattern:/execute\s*\(\s*["'`].*\$\{/gi,name:"Potential SQL injection (template literal)"},{pattern:/query\s*\(\s*["'`].*\+/gi,name:"Potential SQL injection (string concatenation)"}],xss:[{pattern:/dangerouslySetInnerHTML/g,name:"dangerouslySetInnerHTML usage"},{pattern:/innerHTML\s*=/g,name:"innerHTML assignment"},{pattern:/document\.write\s*\(/g,name:"document.write usage"},{pattern:/eval\s*\(/g,name:"eval usage"}],insecureFunctions:[{pattern:/Math\.random\s*\(\)/g,name:"Insecure random (use crypto)"},{pattern:/new Function\s*\(/g,name:"Function constructor (code injection risk)"},{pattern:/setTimeout\s*\(\s*["']/g,name:"setTimeout with string (code injection)"},{pattern:/setInterval\s*\(\s*["']/g,name:"setInterval with string (code injection)"}],infoExposure:[{pattern:/console\.(log|info|warn|error)\s*\(/g,name:"Console logging (remove in production)"},{pattern:/debugger/g,name:"Debugger statement"},{pattern:/TODO.*password/gi,name:"TODO mentioning password"}]};function tr(){return`# .github/workflows/sast.yml
|
|
7
|
+
name: Security Scan (SAST)
|
|
8
|
+
|
|
9
|
+
on:
|
|
10
|
+
push:
|
|
11
|
+
branches: [main, develop]
|
|
12
|
+
pull_request:
|
|
13
|
+
branches: [main]
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
sast:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- name: Run Semgrep
|
|
22
|
+
uses: returntocorp/semgrep-action@v2
|
|
23
|
+
with:
|
|
24
|
+
config: >-
|
|
25
|
+
p/security-audit
|
|
26
|
+
p/secrets
|
|
27
|
+
p/javascript
|
|
28
|
+
p/typescript
|
|
29
|
+
|
|
30
|
+
- name: Run ESLint Security
|
|
31
|
+
run: |
|
|
32
|
+
npm ci
|
|
33
|
+
npx eslint --config eslint.security.config.js --format json --output-file eslint-security.json ./src
|
|
34
|
+
|
|
35
|
+
- name: Upload SARIF
|
|
36
|
+
uses: github/codeql-action/upload-sarif@v3
|
|
37
|
+
with:
|
|
38
|
+
sarif_file: semgrep.sarif
|
|
39
|
+
|
|
40
|
+
codeql:
|
|
41
|
+
runs-on: ubuntu-latest
|
|
42
|
+
permissions:
|
|
43
|
+
security-events: write
|
|
44
|
+
steps:
|
|
45
|
+
- uses: actions/checkout@v4
|
|
46
|
+
|
|
47
|
+
- name: Initialize CodeQL
|
|
48
|
+
uses: github/codeql-action/init@v3
|
|
49
|
+
with:
|
|
50
|
+
languages: javascript-typescript
|
|
51
|
+
|
|
52
|
+
- name: Perform Analysis
|
|
53
|
+
uses: github/codeql-action/analyze@v3
|
|
54
|
+
`}function rr(){return`# .github/workflows/sca.yml
|
|
55
|
+
name: Dependency Security (SCA)
|
|
56
|
+
|
|
57
|
+
on:
|
|
58
|
+
push:
|
|
59
|
+
branches: [main]
|
|
60
|
+
pull_request:
|
|
61
|
+
branches: [main]
|
|
62
|
+
schedule:
|
|
63
|
+
- cron: '0 0 * * *' # Daily at midnight
|
|
64
|
+
|
|
65
|
+
jobs:
|
|
66
|
+
npm-audit:
|
|
67
|
+
runs-on: ubuntu-latest
|
|
68
|
+
steps:
|
|
69
|
+
- uses: actions/checkout@v4
|
|
70
|
+
|
|
71
|
+
- name: Setup Node
|
|
72
|
+
uses: actions/setup-node@v4
|
|
73
|
+
with:
|
|
74
|
+
node-version: '20'
|
|
75
|
+
|
|
76
|
+
- name: Install dependencies
|
|
77
|
+
run: npm ci
|
|
78
|
+
|
|
79
|
+
- name: Run npm audit
|
|
80
|
+
run: npm audit --audit-level=high --json > npm-audit.json || true
|
|
81
|
+
|
|
82
|
+
- name: Check critical vulnerabilities
|
|
83
|
+
run: |
|
|
84
|
+
CRITICAL=$(cat npm-audit.json | jq '.metadata.vulnerabilities.critical')
|
|
85
|
+
HIGH=$(cat npm-audit.json | jq '.metadata.vulnerabilities.high')
|
|
86
|
+
if [ "$CRITICAL" -gt 0 ] || [ "$HIGH" -gt 0 ]; then
|
|
87
|
+
echo "Critical: $CRITICAL, High: $HIGH vulnerabilities found"
|
|
88
|
+
exit 1
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
- name: Upload audit results
|
|
92
|
+
uses: actions/upload-artifact@v4
|
|
93
|
+
with:
|
|
94
|
+
name: npm-audit
|
|
95
|
+
path: npm-audit.json
|
|
96
|
+
|
|
97
|
+
license-check:
|
|
98
|
+
runs-on: ubuntu-latest
|
|
99
|
+
steps:
|
|
100
|
+
- uses: actions/checkout@v4
|
|
101
|
+
|
|
102
|
+
- name: Check licenses
|
|
103
|
+
run: |
|
|
104
|
+
npx license-checker --production --onlyAllow "MIT;Apache-2.0;BSD-2-Clause;BSD-3-Clause;ISC;CC0-1.0"
|
|
105
|
+
|
|
106
|
+
snyk:
|
|
107
|
+
runs-on: ubuntu-latest
|
|
108
|
+
steps:
|
|
109
|
+
- uses: actions/checkout@v4
|
|
110
|
+
|
|
111
|
+
- name: Run Snyk
|
|
112
|
+
uses: snyk/actions/node@master
|
|
113
|
+
env:
|
|
114
|
+
SNYK_TOKEN: \${{ secrets.SNYK_TOKEN }}
|
|
115
|
+
with:
|
|
116
|
+
args: --severity-threshold=high
|
|
117
|
+
`}const sr=[{name:"AWS Access Key ID",pattern:/AKIA[0-9A-Z]{16}/g,severity:"critical"},{name:"AWS Secret Access Key",pattern:/[A-Za-z0-9/+=]{40}/g,severity:"critical"},{name:"Google API Key",pattern:/AIza[0-9A-Za-z-_]{35}/g,severity:"high"},{name:"GitHub Token",pattern:/gh[ps]_[A-Za-z0-9_]{36}/g,severity:"critical"},{name:"GitLab Token",pattern:/glpat-[A-Za-z0-9-_]{20}/g,severity:"critical"},{name:"Slack Token",pattern:/xox[baprs]-[0-9]{10,13}-[0-9]{10,13}[a-zA-Z0-9-]*/g,severity:"high"},{name:"Stripe Key",pattern:/sk_live_[0-9a-zA-Z]{24}/g,severity:"critical"},{name:"SendGrid Key",pattern:/SG\.[a-zA-Z0-9_-]{22}\.[a-zA-Z0-9_-]{43}/g,severity:"high"},{name:"RSA Private Key",pattern:/-----BEGIN RSA PRIVATE KEY-----/g,severity:"critical"},{name:"SSH Private Key",pattern:/-----BEGIN OPENSSH PRIVATE KEY-----/g,severity:"critical"},{name:"PGP Private Key",pattern:/-----BEGIN PGP PRIVATE KEY BLOCK-----/g,severity:"critical"},{name:"Basic Auth",pattern:/basic [a-zA-Z0-9_\-:.=]+/gi,severity:"high"},{name:"Bearer Token",pattern:/bearer [a-zA-Z0-9_\-.=]+/gi,severity:"high"},{name:"Connection String",pattern:/[a-z]+:\/\/[^:]+:[^@]+@[^/]+/gi,severity:"critical"}];function nr(){return`#!/bin/sh
|
|
118
|
+
# .git/hooks/pre-commit
|
|
119
|
+
|
|
120
|
+
echo "Scanning for secrets..."
|
|
121
|
+
|
|
122
|
+
# Define patterns to check
|
|
123
|
+
PATTERNS=(
|
|
124
|
+
'AKIA[0-9A-Z]{16}'
|
|
125
|
+
'gh[ps]_[A-Za-z0-9_]{36}'
|
|
126
|
+
'sk_live_[0-9a-zA-Z]{24}'
|
|
127
|
+
'-----BEGIN.*PRIVATE KEY-----'
|
|
128
|
+
'password.*=.*["'][^'"]+["']'
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
FILES=$(git diff --cached --name-only --diff-filter=ACM)
|
|
132
|
+
|
|
133
|
+
for FILE in $FILES; do
|
|
134
|
+
for PATTERN in "\${PATTERNS[@]}"; do
|
|
135
|
+
if grep -qE "$PATTERN" "$FILE" 2>/dev/null; then
|
|
136
|
+
echo "ERROR: Potential secret found in $FILE"
|
|
137
|
+
echo "Pattern: $PATTERN"
|
|
138
|
+
exit 1
|
|
139
|
+
fi
|
|
140
|
+
done
|
|
141
|
+
done
|
|
142
|
+
|
|
143
|
+
echo "No secrets detected."
|
|
144
|
+
exit 0
|
|
145
|
+
`}function ir(){return`# .github/workflows/secret-scanning.yml
|
|
146
|
+
name: Secret Scanning
|
|
147
|
+
|
|
148
|
+
on:
|
|
149
|
+
push:
|
|
150
|
+
branches: [main, develop]
|
|
151
|
+
pull_request:
|
|
152
|
+
branches: [main]
|
|
153
|
+
|
|
154
|
+
jobs:
|
|
155
|
+
gitleaks:
|
|
156
|
+
runs-on: ubuntu-latest
|
|
157
|
+
steps:
|
|
158
|
+
- uses: actions/checkout@v4
|
|
159
|
+
with:
|
|
160
|
+
fetch-depth: 0
|
|
161
|
+
|
|
162
|
+
- name: Run Gitleaks
|
|
163
|
+
uses: gitleaks/gitleaks-action@v2
|
|
164
|
+
env:
|
|
165
|
+
GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
|
|
166
|
+
|
|
167
|
+
trufflehog:
|
|
168
|
+
runs-on: ubuntu-latest
|
|
169
|
+
steps:
|
|
170
|
+
- uses: actions/checkout@v4
|
|
171
|
+
with:
|
|
172
|
+
fetch-depth: 0
|
|
173
|
+
|
|
174
|
+
- name: Run TruffleHog
|
|
175
|
+
uses: trufflesecurity/trufflehog@main
|
|
176
|
+
with:
|
|
177
|
+
path: ./
|
|
178
|
+
base: \${{ github.event.repository.default_branch }}
|
|
179
|
+
head: HEAD
|
|
180
|
+
`}function ar(e){return`# Security Advisory
|
|
181
|
+
|
|
182
|
+
## ${e.cves.join(", ")} - ${e.description}
|
|
183
|
+
|
|
184
|
+
**Severity:** ${e.severity.toUpperCase()}
|
|
185
|
+
**Date:** ${e.date}
|
|
186
|
+
|
|
187
|
+
### Affected Versions
|
|
188
|
+
|
|
189
|
+
${e.affectedVersions}
|
|
190
|
+
|
|
191
|
+
### Fixed In
|
|
192
|
+
|
|
193
|
+
${e.fixedIn}
|
|
194
|
+
|
|
195
|
+
### Description
|
|
196
|
+
|
|
197
|
+
${e.description}
|
|
198
|
+
|
|
199
|
+
### Remediation
|
|
200
|
+
|
|
201
|
+
Update to version ${e.version} or later:
|
|
202
|
+
|
|
203
|
+
\`\`\`bash
|
|
204
|
+
npm install @nice2dev/ui@${e.version}
|
|
205
|
+
\`\`\`
|
|
206
|
+
|
|
207
|
+
${e.acknowledgments?`### Acknowledgments
|
|
208
|
+
|
|
209
|
+
Thank you to the following researchers for responsibly disclosing this issue:
|
|
210
|
+
|
|
211
|
+
${e.acknowledgments.map(t=>`- ${t}`).join(`
|
|
212
|
+
`)}
|
|
213
|
+
`:""}
|
|
214
|
+
|
|
215
|
+
### Timeline
|
|
216
|
+
|
|
217
|
+
- **Date reported:** ${e.date}
|
|
218
|
+
- **Date fixed:** ${e.date}
|
|
219
|
+
- **Date disclosed:** ${e.date}
|
|
220
|
+
|
|
221
|
+
### References
|
|
222
|
+
|
|
223
|
+
${e.cves.map(t=>`- [${t}](https://www.cve.org/CVERecord?id=${t})`).join(`
|
|
224
|
+
`)}
|
|
225
|
+
`}function or(){return`# Security Policy
|
|
226
|
+
|
|
227
|
+
## Supported Versions
|
|
228
|
+
|
|
229
|
+
| Version | Supported |
|
|
230
|
+
| ------- | ------------------ |
|
|
231
|
+
| 1.0.x | :white_check_mark: |
|
|
232
|
+
| < 1.0 | :x: |
|
|
233
|
+
|
|
234
|
+
## Reporting a Vulnerability
|
|
235
|
+
|
|
236
|
+
We take security seriously. If you discover a security vulnerability, please follow these steps:
|
|
237
|
+
|
|
238
|
+
### 1. Do Not Create a Public Issue
|
|
239
|
+
|
|
240
|
+
**Please do not report security vulnerabilities through public GitHub issues.**
|
|
241
|
+
|
|
242
|
+
### 2. Report Privately
|
|
243
|
+
|
|
244
|
+
Send an email to **security@nice2dev.com** with:
|
|
245
|
+
|
|
246
|
+
- Description of the vulnerability
|
|
247
|
+
- Steps to reproduce
|
|
248
|
+
- Potential impact
|
|
249
|
+
- Any suggested fixes (optional)
|
|
250
|
+
|
|
251
|
+
### 3. Encryption
|
|
252
|
+
|
|
253
|
+
For sensitive reports, use our PGP key:
|
|
254
|
+
|
|
255
|
+
\`\`\`
|
|
256
|
+
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
257
|
+
[PGP KEY HERE]
|
|
258
|
+
-----END PGP PUBLIC KEY BLOCK-----
|
|
259
|
+
\`\`\`
|
|
260
|
+
|
|
261
|
+
## Response Timeline
|
|
262
|
+
|
|
263
|
+
- **Initial Response:** Within 24 hours
|
|
264
|
+
- **Severity Assessment:** Within 48 hours
|
|
265
|
+
- **Fix Development:** Depends on severity
|
|
266
|
+
- Critical: Within 24 hours
|
|
267
|
+
- High: Within 72 hours
|
|
268
|
+
- Medium: Within 1 week
|
|
269
|
+
- Low: Within 2 weeks
|
|
270
|
+
- **Disclosure:** After fix is released
|
|
271
|
+
|
|
272
|
+
## Bug Bounty
|
|
273
|
+
|
|
274
|
+
We offer bug bounties for qualifying vulnerabilities:
|
|
275
|
+
|
|
276
|
+
| Severity | Bounty Range |
|
|
277
|
+
| -------- | ------------ |
|
|
278
|
+
| Critical | $1,000 - $5,000 |
|
|
279
|
+
| High | $500 - $1,000 |
|
|
280
|
+
| Medium | $100 - $500 |
|
|
281
|
+
| Low | Acknowledgment |
|
|
282
|
+
|
|
283
|
+
## Safe Harbor
|
|
284
|
+
|
|
285
|
+
We will not pursue legal action against researchers who:
|
|
286
|
+
|
|
287
|
+
- Make good faith efforts to comply with this policy
|
|
288
|
+
- Report vulnerabilities in a timely manner
|
|
289
|
+
- Do not access, modify, or delete user data
|
|
290
|
+
- Do not disrupt our services
|
|
291
|
+
- Do not disclose vulnerabilities before they are fixed
|
|
292
|
+
`}exports.NiceDeviceTrust=At;exports.NiceFaceRecognition=rt;exports.NiceFingerprintScanner=Qe;exports.NiceI18nProvider=Ze;exports.NiceIrisScanner=et;exports.NiceMfaSelector=St;exports.NicePassphraseInput=Ct;exports.NicePatternLock=ft;exports.NicePinKeypad=ct;exports.NiceSecurityAuditLog=xt;exports.NiceSessionManager=kt;exports.NiceWebAuthnButton=gt;exports.SECRET_PATTERNS=sr;exports.SECURITY_PATTERNS=er;exports.authenticateWebAuthn=ze;exports.captureFrame=te;exports.checkColorContrast=Yt;exports.checkHeadingHierarchy=Xt;exports.checkLiveness=de;exports.clearNonEssentialCookies=Ot;exports.collectDeviceInfo=he;exports.compareFaceToPhoto=Me;exports.createAuditLogger=Qt;exports.createCSRFFetch=Lt;exports.createHIPAASession=Jt;exports.createRateLimiter=Be;exports.createSafeHtml=Nt;exports.detectIris=Ce;exports.escapeHtml=$e;exports.extractFaceFeatures=ne;exports.extractMinutiae=ke;exports.faceToTemplate=Pe;exports.fingerprintToTemplate=je;exports.generateCSPHeader=It;exports.generateCSRFToken=zt;exports.generateDataExport=qt;exports.generateDeviceFingerprint=se;exports.generateLivenessChallenge=Je;exports.generateNonce=Dt;exports.generatePreCommitHook=nr;exports.generateSASTConfig=tr;exports.generateSCAConfig=rr;exports.generateSecretScanningConfig=ir;exports.generateSecurityAdvisory=ar;exports.generateSecurityMd=or;exports.getCSRFTokenFromCookie=pe;exports.getCameraStream=oe;exports.getConsentPreferences=_e;exports.getRecommendedCSP=Rt;exports.getSOC2Checklist=Vt;exports.hasAccessibleName=Zt;exports.hasConsent=Ut;exports.irisToTemplate=Re;exports.isPasskeyAvailable=Fe;exports.isWebAuthnAvailable=fe;exports.logPHIAccess=Gt;exports.matchFaces=ue;exports.matchFingerprints=Ae;exports.matchIris=Ie;exports.registerWebAuthn=Ne;exports.requestDataDeletion=Kt;exports.resolveConfig=ie;exports.sanitizeInput=Pt;exports.sanitizeSvg=Ft;exports.sanitizeUrl=Et;exports.saveConsentPreferences=Ht;exports.scanFileForViruses=_t;exports.templateToFace=Ee;exports.templateToFingerprint=Te;exports.templateToIris=De;exports.useCSRFToken=$t;exports.useNiceTranslation=X;exports.useRateLimiter=Bt;exports.validateFile=We;exports.validateFiles=Wt;exports.verifyWithBackend=ce;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @nice2dev/ui-security — barrel export
|
|
3
|
+
*/
|
|
4
|
+
export { NiceFingerprintScanner } from './components/NiceFingerprintScanner';
|
|
5
|
+
export type { NiceFingerprintScannerProps } from './components/NiceFingerprintScanner';
|
|
6
|
+
export { NiceIrisScanner } from './components/NiceIrisScanner';
|
|
7
|
+
export type { NiceIrisScannerProps } from './components/NiceIrisScanner';
|
|
8
|
+
export { NiceFaceRecognition } from './components/NiceFaceRecognition';
|
|
9
|
+
export type { NiceFaceRecognitionProps } from './components/NiceFaceRecognition';
|
|
10
|
+
export { NicePinKeypad } from './components/NicePinKeypad';
|
|
11
|
+
export type { NicePinKeypadProps } from './components/NicePinKeypad';
|
|
12
|
+
export { NicePatternLock } from './components/NicePatternLock';
|
|
13
|
+
export type { NicePatternLockProps } from './components/NicePatternLock';
|
|
14
|
+
export { NiceWebAuthnButton } from './components/NiceWebAuthnButton';
|
|
15
|
+
export type { NiceWebAuthnButtonProps } from './components/NiceWebAuthnButton';
|
|
16
|
+
export { NiceSecurityAuditLog } from './components/NiceSecurityAuditLog';
|
|
17
|
+
export type { NiceSecurityAuditLogProps } from './components/NiceSecurityAuditLog';
|
|
18
|
+
export { NiceMfaSelector } from './components/NiceMfaSelector';
|
|
19
|
+
export type { NiceMfaSelectorProps, MfaOption } from './components/NiceMfaSelector';
|
|
20
|
+
export { NiceSessionManager } from './components/NiceSessionManager';
|
|
21
|
+
export type { NiceSessionManagerProps, SessionInfo } from './components/NiceSessionManager';
|
|
22
|
+
export { NiceDeviceTrust } from './components/NiceDeviceTrust';
|
|
23
|
+
export type { NiceDeviceTrustProps } from './components/NiceDeviceTrust';
|
|
24
|
+
export { NicePassphraseInput } from './components/NicePassphraseInput';
|
|
25
|
+
export type { NicePassphraseInputProps } from './components/NicePassphraseInput';
|
|
26
|
+
export type { SecurityVerificationStatus, BiometricMethod, BiometricTemplate, BiometricConfig, VerificationResult, FingerPosition, MinutiaePoint, FingerprintFeatures, IrisFeatures, FaceFeatures, FaceLivenessChallenge, KeypadConfig, PatternLockConfig, WebAuthnConfig, SecurityAuditEntry, DeviceTrustScore, } from './core/types';
|
|
27
|
+
export { resolveConfig, getCameraStream, captureFrame, extractMinutiae, matchFingerprints, fingerprintToTemplate, templateToFingerprint, detectIris, matchIris, irisToTemplate, templateToIris, extractFaceFeatures, matchFaces, compareFaceToPhoto, faceToTemplate, templateToFace, generateLivenessChallenge, checkLiveness, collectDeviceInfo, generateDeviceFingerprint, isWebAuthnAvailable, isPasskeyAvailable, registerWebAuthn, authenticateWebAuthn, verifyWithBackend, } from './core/biometricEngine';
|
|
28
|
+
export { NiceI18nProvider, useNiceTranslation } from './core/i18n';
|
|
29
|
+
export type { NiceTranslateFn } from './core/i18n';
|
|
30
|
+
export * from './content-safety';
|
|
31
|
+
export { generateCSPHeader, getRecommendedCSP, generateNonce, type CSPConfig, type CSPDirectives, escapeHtml, sanitizeInput, sanitizeUrl, sanitizeSvg, createSafeHtml, generateCSRFToken, getCSRFTokenFromCookie, createCSRFFetch, useCSRFToken, type CSRFConfig, createRateLimiter, useRateLimiter, type RateLimitConfig, validateFile, validateFiles, scanFileForViruses, type FileUploadConfig, type FileValidationResult, } from './security-utilities';
|
|
32
|
+
export { getConsentPreferences, saveConsentPreferences, hasConsent, clearNonEssentialCookies, generateDataExport, requestDataDeletion, type GDPRConfig, type CookieCategory, type CookieInfo, type ConsentPreferences, logPHIAccess, createHIPAASession, type HIPAAConfig, type PHIAccessLog, checkColorContrast, hasAccessibleName, checkHeadingHierarchy, type WCAGIssue, createAuditLogger, type AuditLogConfig, type AuditLogEntry, getSOC2Checklist, type SOC2ControlStatus, } from './compliance-utilities';
|
|
33
|
+
export { SECURITY_PATTERNS, generateSASTConfig, type SASTConfig, type SASTFinding, generateSCAConfig, type SCAConfig, type SCAVulnerability, SECRET_PATTERNS, generatePreCommitHook, generateSecretScanningConfig, type SecretPattern, generateSecurityAdvisory, generateSecurityMd, type SecurityRelease, } from './security-automation';
|