@corbado/autocapture 1.0.1 → 1.1.0
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/README.md +41 -0
- package/dist/chunk-7E5QDUX5.mjs +1 -0
- package/dist/chunk-JR557W27.mjs +1 -0
- package/dist/chunk-WY3VIPYX.mjs +1 -0
- package/dist/guards-C1SJi1-7.d.mts +351 -0
- package/dist/guards-wCMqiGRi.d.ts +351 -0
- package/dist/index.d.mts +3 -246
- package/dist/index.d.ts +3 -246
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/probe/fixtures.d.mts +38 -0
- package/dist/probe/fixtures.d.ts +38 -0
- package/dist/probe/fixtures.js +1 -0
- package/dist/probe/fixtures.mjs +1 -0
- package/dist/probe.d.mts +28 -0
- package/dist/probe.d.ts +28 -0
- package/dist/probe.js +2 -0
- package/dist/probe.mjs +2 -0
- package/dist/types-CXJAj2DU.d.mts +247 -0
- package/dist/types-CXJAj2DU.d.ts +247 -0
- package/package.json +49 -4
package/README.md
CHANGED
|
@@ -241,6 +241,47 @@ It does not activate automatically or collect field values/message text.
|
|
|
241
241
|
See [the API and evidence contract](src/input-validation.contract.md), including the limits of
|
|
242
242
|
asynchronous DOM inference and the `beginAttempt()`, `requestStarted()`, and `refresh()` methods.
|
|
243
243
|
|
|
244
|
+
## Probe capture (`@corbado/autocapture/probe`)
|
|
245
|
+
|
|
246
|
+
A separate subpath (existing imports of `@corbado/autocapture` do not load it): a config-driven
|
|
247
|
+
diagnostic capture for Corbado autocapture bundles. A JSON config selects surfaces (`page`, `ui`,
|
|
248
|
+
`act`, `nav`, `res`, `store`, `net`, `form`, `err`, `console`, `dl`, `msg`, `glob`, `cev`, each
|
|
249
|
+
`off | inventory | shape | values`), redaction rules, actions (`snapshot`, `correlate`, `count`),
|
|
250
|
+
conditions and a flight-recorder trigger. Redacted items go to an injected sink, normally the
|
|
251
|
+
internal `tracker.probe()` of Observe ≥ 1.4 (no transport of its own).
|
|
252
|
+
|
|
253
|
+
```ts
|
|
254
|
+
import { startProbes, validateProbeConfig } from "@corbado/autocapture/probe";
|
|
255
|
+
|
|
256
|
+
const handle = startProbes(config, {
|
|
257
|
+
sink: (item) => tracker.probe(item),
|
|
258
|
+
projectId,
|
|
259
|
+
network: { subscribe: (subscriber) => hub.subscribeNetwork(subscriber) }, // else captureNetwork
|
|
260
|
+
navigation: { subscribe: (listener) => hub.subscribeNavigation(listener) }, // else captureNavigation
|
|
261
|
+
webauthn: { subscribe: (listener) => hub.subscribeWebAuthn(listener) }, // taint feed only
|
|
262
|
+
context: () => ({ state, flowType, step }),
|
|
263
|
+
tags: () => flowTags,
|
|
264
|
+
sessionId: () => tracker.getSessionId(),
|
|
265
|
+
});
|
|
266
|
+
handle.signal("step-error"); // trigger / action events from the host
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Defaults are conservative: every value no rule names becomes its class (`<email>`, `<digits:6>`,
|
|
270
|
+
`<text:3w>`), free text keeps plain words and classes every other token, and `clear` happens only
|
|
271
|
+
through an explicit rule. Always-on guards that no config can loosen: field values are read through
|
|
272
|
+
one path (password, one-time-code and card fields, and inputs of WebAuthn-bound forms yield at most
|
|
273
|
+
their length), typed secrets, WebAuthn ceremony parts, cookie values and Authorization headers are
|
|
274
|
+
fingerprinted and replaced wherever they show up, a pattern pass removes JWT/JWE, card numbers,
|
|
275
|
+
WebAuthn client data, password/WebAuthn keys and high-entropy tokens, a failing guard drops the item,
|
|
276
|
+
and items are capped at 16 KB (large views are split into several items). One engine per page;
|
|
277
|
+
`startProbes` never throws. When injecting no sources, the engine installs `captureNetwork` /
|
|
278
|
+
`captureNavigation` itself, which then occupy those APIs for other captures on the page.
|
|
279
|
+
|
|
280
|
+
See [the probe contract](src/probe/probe.contract.md) for the config reference and an example
|
|
281
|
+
config. The guard conformance suite (`probeGuardFixtures`, `runProbeGuardFixture`, `applyGuards`) lives
|
|
282
|
+
in its own subpath, `@corbado/autocapture/probe/fixtures`, so bundles that import `/probe` never carry
|
|
283
|
+
its fake secrets. The package is marked `"sideEffects": false`.
|
|
284
|
+
|
|
244
285
|
## Local development
|
|
245
286
|
|
|
246
287
|
Run `pnpm --filter @corbado/autocapture... build` from the workspace root before linting or
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var pe={log:()=>{}};function _(e){return e?{log:(...r)=>{try{let n=e.log(...r);if(n&&(typeof n=="object"||typeof n=="function"))try{Promise.resolve(n).catch(()=>{})}catch{}}catch{}}}:pe}var re=Symbol.for("corbado.autocapture.installed");function U(e){try{return typeof e=="function"&&Object.prototype.hasOwnProperty.call(e,re)}catch{return!1}}function X(e,r){var o,a;let n=r;try{Object.defineProperty(e,re,{value:r,configurable:!0})}catch{}try{Object.defineProperty(e,"name",{value:(o=n.name)!=null?o:"",configurable:!0})}catch{}try{Object.defineProperty(e,"length",{value:(a=n.length)!=null?a:0,configurable:!0})}catch{}return e}function k(){return{mode:"unavailable",disconnect:()=>{}}}function Z(e,r){return!!e&&"value"in e&&"value"in r&&e.value===r.value&&e.writable===r.writable&&e.enumerable===r.enumerable&&e.configurable===r.configurable}function V(e,r,n,o,a,p=String(r)){try{let c=Object.getOwnPropertyDescriptor(e,r);Z(c,{...o,value:n})&&Object.defineProperty(e,r,o)}catch(c){a.log(`${p} restoration skipped`,c)}}function z(e,r,n){let o=_(e);return a=>{try{let p=n(a);if(p&&(typeof p=="object"||typeof p=="function"))try{Promise.resolve(p).catch(c=>o.log(`${r} listener failed`,c))}catch(c){o.log(`${r} listener failed`,c)}}catch(p){o.log(`${r} listener failed`,p)}}}var oe=0;function ae(){return oe+=1,`network-${oe}`}function fe(e,r){let n=e.responseType;if(n===""||n==="text")return r(e.responseText);if(n==="json"){let o=e.response;return o==null?void 0:r(o)}}var he=500,se=Symbol("body-read-timeout");function ie(e){return/event-stream|octet-stream/i.test(e)?!1:/json|text|urlencoded/i.test(e)}async function ue(e,r){let n=e.body;if(!n)return;let o=n.getReader(),a;try{let p=new Promise(m=>{a=setTimeout(()=>m(se),he)}),c=new TextDecoder,q=[];for(;;){let m=await Promise.race([o.read(),p]);if(m===se){r.log("body omitted: read timed out"),o.cancel().catch(()=>{});return}if(m.done)break;q.push(c.decode(m.value,{stream:!0}))}return q.push(c.decode()),q.join("")}catch{o.cancel().catch(()=>{});return}finally{a!==void 0&&clearTimeout(a)}}function ee(e){var r;(r=e==null?void 0:e.body)==null||r.cancel().catch(()=>{})}function ve(e){var w,P,te;let{onExchange:r,onRequest:n,match:o}=e;if(typeof r!="function"||typeof o!="function")throw new TypeError("captureNetwork requires onExchange and match callbacks");let a=_(e.logger),p=(w=e.transports)!=null?w:["xhr","fetch"],c=(P=e.bodyCapture)==null?void 0:P.request,q=(te=e.bodyCapture)==null?void 0:te.response,m=typeof c=="function",H=typeof q=="function",b=!1,L=z(a,"network",d=>{if(b)return r(d)}),$=z(a,"network request",d=>{if(b)return n==null?void 0:n(d)}),D=(d,h,g)=>{if(typeof g=="function")try{return g(d,h)}catch(y){a.log("body projection failed",y);return}},C=(d,h)=>{try{let g=typeof document!="undefined"?document.baseURI:void 0,y=new URL(String(d),g);return o(y,h)===!0?{url:y.href,path:y.pathname}:void 0}catch{return}},M=()=>{if(typeof XMLHttpRequest=="undefined")return a.log("xhr capture unavailable: XMLHttpRequest missing"),null;let d=XMLHttpRequest.prototype,h=Object.getOwnPropertyDescriptor(d,"open"),g=Object.getOwnPropertyDescriptor(d,"send");if(!h||!("value"in h)||typeof h.value!="function"||!g||!("value"in g)||typeof g.value!="function")return a.log("xhr capture unavailable: XMLHttpRequest methods missing"),null;let y=h.value,F=g.value;if(U(y)||U(F))return a.log("xhr capture unavailable: an equivalent capture is already active"),null;let N=new WeakMap,f=new Set,R=!1,x={open(...l){var i;let t=Reflect.apply(y,this,l);if(!b||!R)return t;try{let E=N.get(this);E&&(E.reported=!0,(i=E.cleanupListeners)==null||i.call(E));let B=String(l[0]).toUpperCase(),v=C(l[1],B);v?N.set(this,{method:B,url:v.url,path:v.path,reported:!1}):N.delete(this)}catch(E){a.log("xhr open observation failed",E)}return t}}.open,j={send(...l){let t=b&&R?N.get(this):void 0;if(!t||t.reported||t.cleanupListeners)return Reflect.apply(F,this,l);let i=()=>{},E=!1;try{t.requestId=ae();let v={direction:"request",transport:"xhr",method:t.method,url:t.url,path:t.path};t.requestBody=m&&typeof l[0]=="string"?D(l[0],v,c):void 0;let K=()=>{t.outcome===void 0&&(t.outcome="abort")},W=()=>{t.outcome===void 0&&(t.outcome="timeout")},s=()=>{t.outcome===void 0&&(t.outcome="error")},u=()=>{var I;i();try{if(!b||!R||t.reported||!t.requestId)return;t.reported=!0;let O={direction:"response",transport:"xhr",method:t.method,url:t.url,path:t.path},Q=this.status,ne={requestId:t.requestId,transport:"xhr",method:t.method,url:t.url,path:t.path,status:Q,ok:Q>=200&&Q<300,outcome:(I=t.outcome)!=null?I:"load",durationMs:t.startedAt!==void 0?Date.now()-t.startedAt:void 0,responseUrl:this.responseURL||void 0,requestBody:t.requestBody,responseBody:H?fe(this,le=>D(le,O,q)):void 0};t.requestEmitted?L(ne):t.pendingExchange=ne}catch(O){a.log("xhr exchange observation failed",O)}finally{N.get(this)===t&&N.delete(this)}},S=()=>{try{this.readyState===XMLHttpRequest.DONE&&this.status!==0&&u()}catch(I){a.log("xhr ready-state observation failed",I)}},T=()=>u();i=()=>{for(let[I,O]of[["readystatechange",S],["abort",K],["timeout",W],["error",s],["loadend",T]])this.removeEventListener(I,O);t.cleanupListeners===i&&(t.cleanupListeners=void 0),f.delete(i)},this.addEventListener("readystatechange",S),this.addEventListener("abort",K),this.addEventListener("timeout",W),this.addEventListener("error",s),this.addEventListener("loadend",T),t.cleanupListeners=i,f.add(i),t.startedAt=Date.now(),E=!0}catch(v){a.log("xhr send observation failed",v),i()}let B;try{B=Reflect.apply(F,this,l)}catch(v){throw i(),v}if(E&&t.requestId!==void 0&&t.startedAt!==void 0){t.requestEmitted=!0,$({requestId:t.requestId,transport:"xhr",method:t.method,url:t.url,path:t.path,startedAt:t.startedAt,requestBody:t.requestBody});let v=t.pendingExchange;t.pendingExchange=void 0,v&&L(v)}return B}}.send;return X(x,y),X(j,F),h.writable!==!0||g.writable!==!0?(a.log("xhr capture unavailable: XMLHttpRequest methods are not writable"),null):(Object.defineProperty(d,"open",{...h,value:x}),Object.defineProperty(d,"send",{...g,value:j}),R=!0,()=>{R=!1;for(let l of[...f])l();V(d,"open",x,h,a),V(d,"send",j,g,a)})},G=()=>{let d=globalThis,h=Object.getOwnPropertyDescriptor(d,"fetch");if(!h||!("value"in h))return a.log("fetch capture unavailable: fetch is not an own data property"),null;let g=h.value;if(typeof g!="function")return a.log("fetch capture unavailable: fetch missing"),null;if(U(g))return a.log("fetch capture unavailable: an equivalent capture is already active"),null;let y=!1,F=async(f,R,x,j)=>{try{if(!b||!y){ee(x);return}let[l,t]=await Promise.all([j!=null?j:Promise.resolve(void 0),x?ue(x,a):Promise.resolve(void 0)]);if(!b||!y)return;let i={direction:"request",transport:"fetch",method:f.method,url:f.url,path:f.path},E={...i,direction:"response"},B=f.requestBody;B===void 0&&l!==void 0&&(B=D(l,i,c));let v=t!==void 0?D(t,E,q):void 0;L({requestId:f.requestId,transport:"fetch",method:f.method,url:f.url,path:f.path,status:R.status,ok:R.ok,outcome:"load",durationMs:Date.now()-f.startedAt,responseUrl:R.url||void 0,requestBody:B,responseBody:v})}catch(l){a.log("fetch exchange observation failed",l)}},N={fetch(...f){var B,v,K,W;let R;try{let s=f[0],u=f[1];if(b&&y&&m&&typeof Request!="undefined"&&s instanceof Request&&(u==null?void 0:u.body)===void 0&&s.body){let S=String((B=u==null?void 0:u.method)!=null?B:s.method).toUpperCase(),T=(v=s.headers.get("content-type"))!=null?v:"";C(s.url,S)&&ie(T)&&(R=s.clone())}}catch(s){a.log("fetch observation failed",s)}let x,j=Date.now();try{x=Reflect.apply(g,this,f)}catch(s){throw ee(R),s}let l,t;try{if(b&&y){let s=f[0],u=f[1],S=typeof Request!="undefined"&&s instanceof Request,T=String((K=u==null?void 0:u.method)!=null?K:S?s.method:"GET").toUpperCase(),I=S?s.url:s,O=C(I,T);O&&(l={requestId:ae(),method:T,url:O.url,path:O.path,startedAt:j},t=(W=u==null?void 0:u.signal)!=null?W:S?s.signal:void 0,m&&typeof(u==null?void 0:u.body)=="string"&&(l.requestBody=D(u.body,{direction:"request",transport:"fetch",method:T,url:O.url,path:O.path},c)))}}catch(s){a.log("fetch observation failed",s)}if(!l)return ee(R),x;let i=l;$({requestId:i.requestId,transport:"fetch",method:i.method,url:i.url,path:i.path,startedAt:i.startedAt,requestBody:i.requestBody});let E=R?ue(R,a):void 0;return x.then(s=>{var S;let u;try{if(b&&y&&H){let T=(S=s.headers.get("content-type"))!=null?S:"";ie(T)&&s.body&&(u=s.clone())}}catch{}F(i,s,u,E)},s=>{try{if(!b||!y)return;let u=(t==null?void 0:t.aborted)===!0||(s==null?void 0:s.name)==="AbortError"||typeof DOMException!="undefined"&&s instanceof DOMException&&s.code===DOMException.ABORT_ERR;L({requestId:i.requestId,transport:"fetch",method:i.method,url:i.url,path:i.path,status:0,ok:!1,outcome:u?"abort":"error",durationMs:Date.now()-i.startedAt})}catch(u){a.log("fetch failure observation failed",u)}}),x}}.fetch;return X(N,g),h.writable!==!0?(a.log("fetch capture unavailable: fetch is not writable"),null):(Object.defineProperty(d,"fetch",{...h,value:N}),y=!0,()=>{y=!1,V(d,"fetch",N,h,a)})},A=[];if(p.includes("xhr")){let d=M();d&&A.push(d)}if(p.includes("fetch")){let d=G();d&&A.push(d)}return A.length===0?k():(b=!0,{mode:"standard",disconnect:()=>{b=!1;for(let d of A.splice(0))d()}})}function we(e){let r=e.onNavigate;if(typeof r!="function")throw new TypeError("captureNavigation requires an onNavigate callback");let n=_(e.logger),o,a,p,c,q,m;try{if(o=window,a=o==null?void 0:o.history,!o||!a)return n.log("navigation capture unavailable: window/history missing"),k();if(q=de(a,"pushState"),m=de(a,"replaceState"),!q||!m)return n.log("navigation capture unavailable: history method descriptors missing"),k();if(p=q.descriptor.value,c=m.descriptor.value,typeof p!="function"||typeof c!="function")return n.log("navigation capture unavailable: history methods missing"),k();if(typeof o.addEventListener!="function"||typeof o.removeEventListener!="function")return n.log("navigation capture unavailable: window event methods missing"),k()}catch(w){return n.log("navigation capture unavailable: history inspection failed",w),k()}if(U(p)||U(c))return n.log("navigation capture unavailable: an equivalent capture is already active"),k();let H=!1,b=()=>({path:o.location.pathname,search:o.location.search,hash:o.location.hash}),L;try{L=b()}catch(w){return n.log("navigation capture unavailable: location inspection failed",w),k()}let $=z(n,"navigation",w=>{if(H)return r(w)}),D=w=>{if(H)try{let P=b();if(P.path===L.path&&P.search===L.search&&P.hash===L.hash)return;L=P,$({...P,source:w})}catch(P){n.log("navigation observation failed",P)}},C={pushState(...w){let P=Reflect.apply(p,this,w);return D("push"),P}}.pushState,M={replaceState(...w){let P=Reflect.apply(c,this,w);return D("replace"),P}}.replaceState;X(C,p),X(M,c);let G=()=>D("pop"),A=()=>D("hash");try{if(ce(q,C),ce(m,M),a.pushState!==C||a.replaceState!==M)throw new Error("history method replacement did not take effect");o.addEventListener("popstate",G),o.addEventListener("hashchange",A),H=!0}catch(w){return H=!1,J(o,"popstate",G,n),J(o,"hashchange",A,n),Y(m,M,n),Y(q,C,n),n.log("navigation capture unavailable: history methods are not writable",w),r=()=>{},$=()=>{},n=_(),k()}return{mode:"standard",disconnect:()=>{H=!1,r=()=>{},J(o,"popstate",G,n),J(o,"hashchange",A,n),Y(q,C,n),Y(m,M,n),$=()=>{},n=_()}}}function de(e,r){let n=e;for(;n;){let o=Object.getOwnPropertyDescriptor(n,r);if(o)return!("value"in o)||typeof o.value!="function"?null:{owner:n,key:r,descriptor:o};n=Object.getPrototypeOf(n)}return null}function ce(e,r){if(e.descriptor.writable!==!0)throw new TypeError(`${e.key} is not writable`);let n=Object.getOwnPropertyDescriptor(e.owner,e.key);if(!Z(n,e.descriptor))throw new Error(`${e.key} changed during installation`);Object.defineProperty(e.owner,e.key,{...e.descriptor,value:r})}function Y(e,r,n){V(e.owner,e.key,r,e.descriptor,n,`navigation ${e.key}`)}function J(e,r,n,o){try{e.removeEventListener(r,n)}catch(a){o.log(`navigation ${r} listener removal skipped`,a)}}var qe="1.1.0";export{_ as a,U as b,X as c,k as d,z as e,ve as f,we as g,qe as h};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var d=Object.defineProperty;var e=(b,a,c)=>a in b?d(b,a,{enumerable:!0,configurable:!0,writable:!0,value:c}):b[a]=c;var f=(b,a,c)=>e(b,typeof a!="symbol"?a+"":a,c);export{f as a};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as E}from"./chunk-JR557W27.mjs";function J(n,t=2166136261){let e=t>>>0;for(let r=0;r<n.length;r++)e^=n.charCodeAt(r),e=Math.imul(e,16777619);return e>>>0}function B(n){return J(n).toString(36).padStart(7,"0")+J(n,1540483477).toString(36).padStart(7,"0")}function Wt(n){return JSON.stringify(_(n))}function _(n){if(Array.isArray(n))return n.map(_);if(n&&typeof n=="object"){let t={};for(let e of Object.keys(n).sort())t[e]=_(n[e]);return t}return n}function nt(n){let t=0;for(let e=0;e<n.length;e++){let r=n.charCodeAt(e);r<128?t+=1:r<2048?t+=2:r>=55296&&r<=56319&&e+1<n.length?(t+=4,e++):t+=3}return t}function Vt(n){try{let t=JSON.stringify(n);return t===void 0?0:nt(t)}catch{return 1/0}}var p=n=>n.toLowerCase().replace(/[-_\s]/g,""),T=new Map;function et(n){let t=T.get(n);if(!t){let e=n.split("").map(r=>r==="*"?".*":r==="?"?".":r.replace(/[.+^${}()|[\]\\/]/g,"\\$&")).join("");t=new RegExp(`^${e}$`,"i"),T.size>500&&T.clear(),T.set(n,t)}return t}function A(n,t){if(n===void 0)return!0;let e=typeof n=="string"?[n]:n;for(let r of e)if(et(r).test(t))return!0;return!1}var k=n=>n===void 0?[]:Array.isArray(n)?n:[n];function x(n){let t=new Uint8Array(n);try{let e=typeof crypto!="undefined"?crypto:void 0;if(e&&typeof e.getRandomValues=="function")return e.getRandomValues(t),t}catch{}for(let e=0;e<n;e++)t[e]=Math.floor(Math.random()*256);return t}var rt="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";function Xt(n){let t=x(n),e="";for(let r=0;r<n;r++)e+=rt[t[r]&63];return e}function Gt(n){try{return n()}catch{return}}function O(n){let t=n.trim();if(t.startsWith("{")&&t.endsWith("}")||t.startsWith("[")&&t.endsWith("]"))try{return JSON.parse(t)}catch{return}}function H(n){return!!n&&typeof n=="object"&&!Array.isArray(n)}function Yt(n){try{return n.getAttribute("id")||void 0}catch{return}}function qt(n){var e;let t=(e=n.getAttribute("action"))!=null?e:"";try{return new URL(t,document.baseURI).href}catch{return t}}function Qt(n){return(n.getAttribute("method")||"get").toLowerCase()}var it=new Set(["drop","presence","length"]),st=/(^|\s)(current-password|new-password|one-time-code|cc-[a-z-]+)(\s|$)/i,ot=/(password|passwd|passcode|^pwd$|^otp|otp$|onetime|^pin$|^cvv|^cvc|^ssn$|securitycode|verificationcode)/;function N(n){try{let t=n.value;return typeof t=="string"?t:""}catch{return""}}function X(n){var t,e,r;try{let i=n;if(n.tagName==="INPUT"&&(i.type||"").toLowerCase()==="password")return!0;let s=(t=n.getAttribute("autocomplete"))!=null?t:"";if(st.test(s))return!0;for(let c of[i.name,n.id])if(c&&ot.test(p(c)))return!0;let o=(e=i.form)!=null?e:n.closest("form");if(o){for(let c of Array.from(o.querySelectorAll("input[autocomplete]")).slice(0,50))if(/(^|\s)webauthn(\s|$)/i.test((r=c.getAttribute("autocomplete"))!=null?r:""))return!0}return!1}catch{return!0}}function nn(n,t,e){let r=X(n)&&!it.has(t.method)?{method:"length"}:t;return e(N(n),r)}function en(n){return N(n).length}var F=6,ct=4096,ft=400,z=class{constructor(){E(this,"base1");E(this,"base2");E(this,"byLength",new Map);E(this,"order",[]);let t=x(8),e=r=>(t[r]<<24|t[r+1]<<16|t[r+2]<<8|t[r+3])>>>0;this.base1=(e(0)|65537)>>>0,this.base2=(e(4)|65537)>>>0}get size(){return this.order.length}add(t){if(typeof t!="string"||t.length<F||t.length>ct)return;let e=new Set([t]);try{e.add(encodeURIComponent(t))}catch{}try{e.add(new URLSearchParams({v:t}).toString().slice(2))}catch{}e.add(JSON.stringify(t).slice(1,-1));for(let r of e)this.addOne(r)}addOne(t){var i;let e=this.fingerprint(t,0,t.length),r=this.byLength.get(t.length);if(r||this.byLength.set(t.length,r=new Set),!r.has(e))for(r.add(e),this.order.push([t.length,e]);this.order.length>ft;){let[s,o]=this.order.shift();(i=this.byLength.get(s))==null||i.delete(o)}}fingerprint(t,e,r){let i=0,s=0;for(let o=e;o<e+r;o++){let c=t.charCodeAt(o);i=Math.imul(i,this.base1)+c>>>0,s=Math.imul(s,this.base2)+c>>>0}return`${i}:${s}`}scrub(t){if(this.order.length===0||t.length<F)return t;let e=[];for(let[o,c]of this.byLength){if(c.size===0||o>t.length)continue;let f=1,d=1;for(let u=0;u<o-1;u++)f=Math.imul(f,this.base1)>>>0,d=Math.imul(d,this.base2)>>>0;let h=0,a=0;for(let u=0;u<o;u++){let g=t.charCodeAt(u);h=Math.imul(h,this.base1)+g>>>0,a=Math.imul(a,this.base2)+g>>>0}for(let u=0;;u++){c.has(`${h}:${a}`)&&e.push([u,u+o]);let g=u+o;if(g>=t.length)break;let l=t.charCodeAt(u),b=t.charCodeAt(g);h=Math.imul(h-Math.imul(l,f)>>>0,this.base1)+b>>>0,a=Math.imul(a-Math.imul(l,d)>>>0,this.base2)+b>>>0}}if(e.length===0)return t;e.sort((o,c)=>o[0]-c[0]||c[1]-o[1]);let r="",i=0,s=0;for(;s<e.length;){let[o,c]=e[s];for(s++;s<e.length&&e[s][0]<c;)c=Math.max(c,e[s][1]),s++;o<i&&(o=i),r+=t.slice(i,o)+`<tainted:${c-o}>`,i=c}return r+t.slice(i)}};function rn(n=[]){let t=new z;for(let e of n)t.add(e);return t}var ut=new Set(["challenge","id","rawId","userHandle","signature","clientDataJSON","authenticatorData","attestationObject","publicKey"].map(p));function sn(n,t){if(!t||typeof t!="object")return;let e=t;for(let r of["requestOptionsJson","creationOptionsJson","credentialJson"]){let i=e[r];if(typeof i!="string")continue;n.add(i);let s;try{s=JSON.parse(i)}catch{continue}let o=0,c=(f,d,h)=>{if(!(h>8||++o>500)){if(typeof f=="string"){ut.has(p(d))&&n.add(f);return}if(Array.isArray(f)){for(let a of f.slice(0,50))c(a,d,h+1);return}if(f&&typeof f=="object")for(let[a,u]of Object.entries(f))c(u,a,h+1)}};c(s,"",0)}}function on(n,t){if(t)try{let e=Array.from(t.querySelectorAll("input, textarea")).slice(0,200),r=0;for(let i of e){if(r>=30)break;X(i)&&(r++,n.add(N(i)))}}catch{}}function cn(n,t){for(let e of t.split(";").slice(0,100)){let r=e.indexOf("=");if(r<0)continue;let i=e.slice(r+1).trim();n.add(i);try{let s=decodeURIComponent(i);s!==i&&n.add(s)}catch{}}}function fn(n,t){if(typeof t!="string")return;n.add(t);let e=t.trim().split(/\s+/);e.length>1&&n.add(e.slice(1).join(" "))}var at=new Set(["password","passwd","pwd","passphrase","clientDataJSON","authenticatorData","signature","attestationObject","userHandle","authorization","proxyAuthorization","cookie","setCookie","privateKey","clientSecret"].map(p));function y(n){let t=p(n);return at.has(t)||t.includes("password")}var dt=/eyJ0eXBlIjoid2ViYXV0aG4u[A-Za-z0-9_\-+/=]*/gi,ht=/eyJ[A-Za-z0-9_-]{16,}(?:\.[A-Za-z0-9_-]*){0,4}/gi,gt=/("|\\")(password|passwd|pwd|clientDataJSON|authenticatorData|signature|attestationObject|userHandle|authorization)\1(\s*:\s*)\1(?!<)((?:(?!\1)[^\\]|\\.)*?)\1/gi,lt=/(^|[?&;\s,])(password|passwd|pwd)=([^&\s;,]+)/gi,pt=/\b(Bearer|Basic)\s+([A-Za-z0-9._~+/=-]{8,})/g,mt=/\b((?:proxy-)?authorization)(\s*[:=]\s*|"\s*:\s*")((?:Bearer|Basic|Digest|Token|Negotiate)\s+)?(?!<)([^\s,;"&]+)/gi;function j(n){return n.replace(mt,(t,e,r,i,s)=>`${e}${r}${i!=null?i:""}<redacted:${s.length}>`)}var bt=/\d(?:[ -]?\d){12,}/g,yt=/[A-Za-z0-9_\-+/]{24,}={0,2}/g;function $t(n){let t=0,e=!1;for(let r=n.length-1;r>=0;r--){let i=n.charCodeAt(r)-48;e&&(i*=2,i>9&&(i-=9)),t+=i,e=!e}return t%10===0}function G(n){for(let t=13;t<=Math.min(19,n.length);t++)for(let e=0;e+t<=n.length;e++)if($t(n.slice(e,e+t)))return!0;return!1}function wt(n){var r;let t=new Map;for(let i of n)t.set(i,((r=t.get(i))!=null?r:0)+1);let e=0;for(let i of t.values()){let s=i/n.length;e-=s*Math.log2(s)}return e}function W(n){return n.length>=24&&/\d/.test(n)&&/[A-Za-z]/.test(n)&&wt(n)>=3}var At=/^([A-Za-z][a-z]*(?:[-_.][A-Za-z]+)*|v\d{1,2}|\d{1,5}|)$/;function Rt(n){if(!n.includes("/"))return!1;let t=n.split("/");return t.filter(r=>At.test(r)).length*2>=t.length}function St(n){return Rt(n)?n.split("/").map(t=>W(t)?`<tok:${t.length}>`:t).join("/"):W(n)?`<tok:${n.length}>`:n}function V(n,t){let e=t?t.scrub(n):n;return e=j(e),e=e.replace(gt,(r,i,s,o,c)=>`${i}${s}${i}${o}${i}<redacted:${c.length}>${i}`),e=e.replace(lt,(r,i,s,o)=>o.startsWith("<")?r:`${i}${s}=<redacted:${o.length}>`),e=e.replace(pt,(r,i,s)=>`${i} <redacted:${s.length}>`),e=e.replace(dt,r=>`<webauthn:${r.length}>`),e=e.replace(ht,r=>`<jwt:${r.length}>`),e=e.replace(bt,r=>{let i=r.replace(/[ -]/g,"");return i.length>19?`<digits:${i.length}>`:G(i)?`<card:${i.length}>`:r}),e=e.replace(yt,St),e}function Et(n){if(!Number.isFinite(n))return null;if(!Number.isInteger(n))return n;let t=String(Math.abs(n));return t.length>=13&&G(t)?`<card:${t.length}>`:n}function Tt(n){return n==null||typeof n=="boolean"?n:typeof n=="string"?Ot.test(n)?n:`<redacted:${n.length}>`:typeof n=="number"?"<redacted:num>":"<redacted:obj>"}var Ot=/^<[a-z]+(?::[A-Za-z0-9.]{1,12})?>$/,Mt=24;function L(n,t,e){if(e>Mt)return"<deep>";if(n===null||typeof n=="boolean")return n;if(typeof n=="string")return V(n,t);if(typeof n=="number")return Et(n);if(Array.isArray(n))return n.map(r=>{let i=L(r,t,e+1);return i===void 0?null:i});if(typeof n=="object"){let r={};for(let[i,s]of Object.entries(n)){let o=V(i,t),c=y(i)?Tt(s):L(s,t,e+1);c!==void 0&&(r[o]=c)}return r}}function un(n,t){try{return L(n,t!=null?t:void 0,0)}catch{return}}var _t=/^[^\s@]{1,64}@[^\s@]+\.[^\s@]{2,}$/,kt=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,xt=/^[a-z][a-z0-9+.-]*:\/\/\S+$/i,zt=/^\d{4}-\d{2}-\d{2}([T ][\d:.]+(Z|[+-]\d{2}:?\d{2})?)?$/,Lt=/^\+?[\d\s().-]{7,20}$/;function m(n){if(n==="")return"";let t=n.length;return/^eyJ/i.test(n)&&t>20?`<jwt:${t}>`:_t.test(n)?"<email>":kt.test(n)?"<uuid>":xt.test(n)?"<url>":zt.test(n)?"<date>":/^\d+$/.test(n)?`<digits:${t}>`:Lt.test(n)&&/\d{3}/.test(n)?"<phone>":/^(true|false|null|undefined)$/i.test(n)?`<${n.toLowerCase()}>`:/^[A-Za-z]+$/.test(n)?`<alpha:${t}>`:/^[0-9a-f]+$/i.test(n)&&t>=8?`<hex:${t}>`:/^[A-Za-z0-9]+$/.test(n)?`<alnum:${t}>`:/^[A-Za-z0-9_-]+$/.test(n)?`<id:${t}>`:/^[A-Za-z0-9+/]+={0,2}$/.test(n)&&t>=16?`<b64:${t}>`:/\s/.test(n.trim())?`<text:${n.trim().split(/\s+/).length}w>`:`<str:${t}>`}function w(n){return n==null||typeof n=="boolean"?n:typeof n=="number"?Number.isFinite(n)&&Number.isInteger(n)?`<int:${String(Math.abs(n)).length}>`:"<num>":typeof n=="string"?m(n):Array.isArray(n)?`<arr:${n.length}>`:typeof n=="object"?`<obj:${Object.keys(n).length}>`:`<${typeof n}>`}function I(n){return n===null?"null":Array.isArray(n)?"array":typeof n}function P(n,t=0){let e=Math.max(0,Math.min(t,n.length));return n.slice(0,e)+n.slice(e).replace(/[0-9]/g,"9").replace(/[A-Za-zÀ-ɏ]/g,"a")}function Y(n,t=0,e=0){let r=Math.max(0,t),i=Math.max(0,e);return r+i>=n.length?"*".repeat(n.length):n.slice(0,r)+"*".repeat(n.length-r-i)+n.slice(n.length-i)}var Nt=/^[A-Za-zÀ-ɏͰ-ϿЀ-ӿ]+(?:['’_.-][A-Za-zÀ-ɏͰ-ϿЀ-ӿ]+)*$/;function M(n){return n.length<=40&&Nt.test(n)}var R=Symbol("probe.drop"),jt=new Set(["otp","passcode","onetimepassword","onetimecode","securitycode","verificationcode","smscode","pin","cvv","cvc","answer","answers","securityanswer","useranswer","ssn","taxid","tin","socialsecuritynumber","token","accesstoken","idtoken","refreshtoken","sessiontoken","authtoken","bearer","apikey","ticket","codeverifier","secret","samlresponse","samlrequest","wresult","csrf","xsrf","csrftoken","xsrftoken","sessionid","deviceid","publickey","keypair","challenge","credential","assertion"].map(p)),It=/(password|passwd|token|secret|^otp|otp$|answer|ssn|ticket|cookie|credential)/,Pt=/^[A-Za-z0-9_-]{16,}$/,D=3e5,U=4e3,Dt=12,C=100,q=200,Ut=new Set(["drop","presence","length","hash"]),K=/^<[a-z]+(?::[^<>\s]{0,24})?>$/,Ct=/<[a-z]+(?::[^<>\s]{0,24})?>/,Kt=/(<[a-z]+(?::[^<>\s]{0,24})?>)/,Zt=/(^|[^A-Za-z0-9_%]|%[0-9A-Fa-f]{2})([A-Za-z_][A-Za-z0-9_.-]{0,40})(\s*[:=]\s*|%3D|%3A)((?:(?!%26|%2C|%20|%23|%3B|%7C)[^\s&"',;#<>|])+)/gi;function S(n){let t=p(n);return jt.has(t)||It.test(t)}function Jt(n,t){return/^[A-Za-z_$][\w$.:-]{0,63}$/.test(n)&&!/\d{5,}/.test(n)||/^\d{1,4}$/.test(n)?n:`<key${t}:${m(n).replace(/[<>]/g,"")}>`}function Q(n){return n.split("/").map(t=>{if(t==="")return t;let e=t;try{e=decodeURIComponent(t)}catch{}return M(e)||/^v\d{1,2}(\.\d{1,2})?$/i.test(e)||/^\d{1,3}$/.test(e)||/^[A-Za-z][A-Za-z0-9_-]{0,40}(\.[A-Za-z0-9_-]{1,40}){0,3}\.[a-z0-9]{1,6}$/i.test(e)&&!/\d{6,}/.test(e)||/^[a-z]+[-_][a-z0-9]{1,3}$/i.test(e)?t:m(e)}).join("/")}var v=class{constructor(t,e){this.rules=t;this.salt=e}ruleFor(t,e,r){for(let i of this.rules)if(this.matches(i,t,e,r))return i}matches(t,e,r,i){if(t.surface!==void 0&&!k(t.surface).includes(e.surface)||t.part!==void 0&&t.part!==e.part||t.host!==void 0&&(e.host===void 0||!A(t.host,e.host))||t.path!==void 0&&(e.path===void 0||!A(t.path,e.path)))return!1;if(t.selector!==void 0){if(!e.el)return!1;try{if(!e.el.closest(t.selector))return!1}catch{return!1}}return t.key!==void 0?r===void 0?!1:k(t.key).some(s=>Bt(s,r,i!=null?i:r)):!0}method(t,e,r,i=""){var s;switch(e.method){case"drop":return R;case"presence":return t==null?t:t===""||Array.isArray(t)&&t.length===0?"<empty>":"<set>";case"length":return t==null?t:typeof t=="string"?`<len:${t.length}>`:Array.isArray(t)?`<len:${t.length}>`:typeof t=="object"?`<len:${Object.keys(t).length}>`:`<len:${String(t).length}>`;case"hash":return t==null?t:`<h:${B(this.salt+(typeof t=="string"?t:JSON.stringify(t)))}>`;case"shape":return typeof t=="string"?P(t,e.keepPrefix):typeof t=="number"?P(String(t),e.keepPrefix):typeof t=="object"&&t!==null?this.tree(t,r,"shape",i):t;case"mask":return typeof t=="string"||typeof t=="number"?Y(String(t),e.keepStart,e.keepEnd):w(t);case"enum":return t==null||typeof t=="boolean"?t:typeof t=="string"||typeof t=="number"?((s=e.values)!=null?s:[]).includes(String(t))?t:w(t):w(t);case"clear":return this.leaf(t,r,i,e);default:return this.leaf(t,r,i,void 0)}}leaf(t,e,r,i){if(typeof t=="string"){if(t.length>D)return`<len:${t.length}>`;let s=O(t);return s!==void 0&&typeof s=="object"&&s!==null?this.tree(s,e,"values",r,i):/^https?:\/\/\S+$/i.test(t)?this.url(t,e,"values",i):/\s/.test(t.trim())?this.text(t,e,"values",i):i?t:m(t)}return t!==null&&typeof t=="object"?this.tree(t,e,"values",r,i):i?t:w(t)}keyed(t,e,r,i,s){if(y(t))return this.method(e,{method:"length"},r);let o=this.ruleFor(r,t,i);return o?this.method(e,o,r,i):S(t)?this.method(e,{method:"length"},r):p(t)==="code"&&typeof e=="string"&&Pt.test(e)?this.method(e,{method:"length"},r):this.leaf(e,r,i,s)}tree(t,e,r,i="",s,o=0){var c;if(o>Dt)return"<deep>";if(Array.isArray(t)){let f=(c=i.split(".").pop())!=null?c:"",d=[];for(let h of t.slice(0,C)){let a=h!==null&&typeof h=="object"?this.tree(h,e,r,i,s,o+1):this.scalar(f,h,e,r,i,s);a!==R&&d.push(a)}return t.length>C&&d.push(`<more:${t.length-C}>`),d}if(H(t)){let f={},d=typeof t.type=="string"&&"value"in t?t.type:void 0,h=0;for(let[a,u]of Object.entries(t)){if(h>=q){f["<more>"]=Object.keys(t).length-q;break}let g=d!==void 0&&a==="value"?d:a,l=i?`${i}.${g}`:g,b,$=r==="values"?this.hasKeyRule(g,e,l):!!this.restrictiveRule(g,e,l,r);u!==null&&typeof u=="object"&&!$?b=y(g)?this.method(u,{method:"length"},e):this.tree(u,e,r,l,s,o+1):b=this.scalar(g,u,e,r,l,s),b!==R&&(f[Jt(a,h)]=b),h++}return f}return this.scalar("",t,e,r,i,s)}hasKeyRule(t,e,r){var i;return y(t)||S(t)||((i=this.ruleFor(e,t,r))==null?void 0:i.key)!==void 0}restrictiveRule(t,e,r,i){if(!t)return;let s=this.ruleFor(e,t,r);if(!(!s||s.key===void 0))return s.method==="drop"||i==="shape"&&Ut.has(s.method)?s:void 0}scalar(t,e,r,i,s,o){if(i!=="values"){let f=this.restrictiveRule(t,r,s,i);if(f)return this.method(e,f,r,s)}if(i==="inventory")return I(e);if(i==="shape"){if(t&&(y(t)||S(t)))return this.method(e,{method:"length"},r);if(typeof e=="string"){let f=e.length<=D?O(e):void 0;if(f!==void 0&&typeof f=="object"&&f!==null)return this.tree(f,r,"shape",s)}return w(e)}if(t)return this.keyed(t,e,r,s,o);let c=this.ruleFor(r);return c?this.method(e,c,r,s):this.leaf(e,r,s,o)}text(t,e,r,i){if(r==="inventory"||r==="shape")return m(t);if(!i){let o=this.ruleFor(e);if(o){if(o.method==="class")return m(t);let c=this.method(t,o,e);if(c===R)return"";if(o.method!=="clear")return typeof c=="string"?c:JSON.stringify(c);i=o}}let s=j(t).replace(Zt,(o,c,f,d,h)=>{if(K.test(h))return o;let a;if(y(f))a=`<redacted:${h.length}>`;else{let u=this.ruleFor(e,f,f);u&&u.key!==void 0?a=this.method(h,u,e,f):S(f)&&(a=`<redacted:${h.length}>`)}return a===void 0?o:`${c}${f}${d}${a===R?"<dropped>":String(a)}`});return i?s:s.replace(/\S+/g,o=>this.token(o,e))}token(t,e,r=0){var f,d,h,a;if(K.test(t))return t;if(Ct.test(t))return t.split(Kt).map((u,g)=>g%2===1||u===""?u:this.token(u,e,r)).join("");let i=(d=(f=/^[([{"'“‘|<]+/.exec(t))==null?void 0:f[0])!=null?d:"",s=(a=(h=/[)\]}"'”’,.;:=!?|>/]+$/.exec(t.slice(i.length)))==null?void 0:h[0])!=null?a:"",o=t.slice(i.length,t.length-s.length);if(o===""||K.test(o)||M(o)||/^\d{1,3}$/.test(o))return t;if(/^https?:\/\//i.test(o))return i+this.url(o,e,"values")+s;let c=r===0?/[:=]/.exec(o):null;if(c&&c.index>0&&c.index<o.length-1){let u=o.slice(0,c.index),g=o.slice(c.index+1);return i+this.token(u,e,1)+c[0]+this.token(g,e,1)+s}return i+m(o)+s}url(t,e,r,i){var h;let s;try{s=new URL(t,typeof location!="undefined"?location.href:void 0)}catch{return r==="inventory"?"<url>":m(t)}let o={...e,host:s.hostname,path:s.pathname,part:(h=e.part)!=null?h:"url"},c=`${s.protocol}//${s.host}${Q(s.pathname)}`;if(r==="inventory")return c;let f=a=>{let u=[];return new URLSearchParams(a).forEach((g,l)=>{if(u.length>=60)return;let b=/^[\w.[\]-]{1,64}$/.test(l)?l:m(l),$;if(r==="shape"){let Z=this.restrictiveRule(l,o,l,r);$=Z?this.method(g,Z,o,l):y(l)||S(l)?`<len:${g.length}>`:w(g)}else $=this.keyed(l,g,o,l,i);$!==R&&u.push(`${b}=${typeof $=="string"?$:JSON.stringify($)}`)}),u.join("&")};s.search.length>1&&(c+=`?${f(s.search.slice(1))}`);let d=s.hash.slice(1);if(d)if(d.startsWith("/")){let a=d.indexOf("?");c+=`#${Q(a<0?d:d.slice(0,a))}${a<0?"":`?${f(d.slice(a+1))}`}`}else d.includes("=")?c+=`#${f(d)}`:c+=`#${M(d)?d:m(d)}`;return c}body(t,e,r){try{if(t==null)return;if(r==="inventory")return{type:I(t)};if(typeof t=="string"){if(t.length>D)return{len:t.length,skipped:"size"};let i=O(t);if(i!==void 0)return this.tree(i,e,r);if(Ht(t))return{form:this.tree(tt(new URLSearchParams(t)),e,r)};if(r==="shape")return{text:m(t)};let s=t.length>U?t.slice(0,U):t,o=Ft(s),c=/^\s*</.test(o)?o.replace(/</g," <").replace(/>/g,"> "):o;return{text:this.text(c,e,r).trim(),...t.length>U?{len:t.length}:{}}}if(typeof URLSearchParams!="undefined"&&t instanceof URLSearchParams)return{form:this.tree(tt(t),e,r)};if(typeof FormData!="undefined"&&t instanceof FormData){let i={};return t.forEach((s,o)=>{i[o]=typeof s=="string"?s:`<file:${s.size}>`}),{formData:this.tree(i,e,r)}}return typeof Blob!="undefined"&&t instanceof Blob?{blob:t.size}:typeof ArrayBuffer!="undefined"&&(t instanceof ArrayBuffer||ArrayBuffer.isView(t))?{bytes:t.byteLength}:typeof t=="object"?this.tree(t,e,r):this.scalar("",t,e,r,"")}catch{return{error:"redact-failed"}}}};function Bt(n,t,e){return n.includes(".")?A(n,e)||A(`*.${n}`,e):n.includes("*")||n.includes("?")?A(n,t):p(n)===p(t)}function Ht(n){return/^[^\s<>{}=&]+=[^\s<>]*(&[^\s<>{}=&]+=[^\s<>]*)*$/.test(n.trim())}function tt(n){let t={};return n.forEach((e,r)=>{r in t?t[r]=[].concat(t[r],e):t[r]=e}),t}function Ft(n){let t=e=>y(e)||S(e);return n.replace(/(<input\b[^>]*\bname\s*=\s*["']?([\w.-]+)["']?[^>]*\bvalue\s*=\s*)(["'])([^"'>]*)\3/gi,(e,r,i,s,o)=>t(i)?`${r}${s}<redacted:${o.length}>${s}`:e).replace(/(<input\b[^>]*\bvalue\s*=\s*)(["'])([^"'>]*)\2([^>]*\bname\s*=\s*["']?([\w.-]+)["']?)/gi,(e,r,i,s,o,c)=>t(c)?`${r}${i}<redacted:${s.length}>${i}${o}`:e)}export{J as a,B as b,Wt as c,Vt as d,A as e,k as f,Xt as g,Gt as h,O as i,H as j,Yt as k,qt as l,Qt as m,nn as n,en as o,z as p,rn as q,sn as r,on as s,cn as t,fn as u,un as v,m as w,w as x,I as y,R as z,Q as A,v as B};
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import { g as NetworkBodyProjectionContext, c as HttpRequestStarted, H as HttpExchange, d as NavigationEvent, m as WebAuthnCeremonyEvent } from './types-CXJAj2DU.mjs';
|
|
2
|
+
|
|
3
|
+
/** Capture depth of a surface. `values` applies the redaction rules; anything no rule names becomes its class. */
|
|
4
|
+
type ProbeLevel = "off" | "inventory" | "shape" | "values";
|
|
5
|
+
/** Everything a probe config can observe. */
|
|
6
|
+
type ProbeSurface = "page" | "ui" | "act" | "nav" | "res" | "store" | "net" | "form" | "err" | "console" | "dl" | "msg" | "glob" | "cev";
|
|
7
|
+
/**
|
|
8
|
+
* Redaction method of a rule.
|
|
9
|
+
*
|
|
10
|
+
* - `drop`: the key / element is left out.
|
|
11
|
+
* - `presence`: `<set>` or `<empty>`.
|
|
12
|
+
* - `length`: `<len:n>`.
|
|
13
|
+
* - `class`: a coarse class such as `<email>`, `<digits:6>`, `<alpha:5>`, `<uuid>`, `<text:4w>` (the default).
|
|
14
|
+
* - `shape`: format mask — digits → `9`, letters → `a`, separators kept; optional `keepPrefix`.
|
|
15
|
+
* - `hash`: `<h:…>`, salted per page (the salt never leaves the page).
|
|
16
|
+
* - `mask`: `*` for every character except `keepStart` / `keepEnd`.
|
|
17
|
+
* - `enum`: the value when it is one of `values`, its class otherwise.
|
|
18
|
+
* - `clear`: the value itself (still subject to the always-on guards).
|
|
19
|
+
*/
|
|
20
|
+
type ProbeMethod = "drop" | "presence" | "length" | "class" | "shape" | "hash" | "mask" | "enum" | "clear";
|
|
21
|
+
/** Options shared by every surface. */
|
|
22
|
+
type ProbeSurfaceConfig = {
|
|
23
|
+
level: ProbeLevel;
|
|
24
|
+
};
|
|
25
|
+
/** `net` surface options. */
|
|
26
|
+
type ProbeNetSurfaceConfig = ProbeSurfaceConfig & {
|
|
27
|
+
/** Host globs to observe (default: every host except Corbado's own). */
|
|
28
|
+
hosts?: string[];
|
|
29
|
+
/** Host globs never observed (Corbado's own hosts are always excluded). */
|
|
30
|
+
excludeHosts?: string[];
|
|
31
|
+
/** Path globs to observe (default: every path). */
|
|
32
|
+
paths?: string[];
|
|
33
|
+
/** Uppercase methods to observe (default: all). */
|
|
34
|
+
methods?: string[];
|
|
35
|
+
/** Read and redact bodies at `shape` / `values` (default true). */
|
|
36
|
+
bodies?: boolean;
|
|
37
|
+
};
|
|
38
|
+
/** `res` surface options. */
|
|
39
|
+
type ProbeResSurfaceConfig = ProbeSurfaceConfig & {
|
|
40
|
+
/** Host globs (default: all but Corbado's own). */
|
|
41
|
+
hosts?: string[];
|
|
42
|
+
/** Poll interval for new Resource Timing entries (default 5000 ms, min 1000). */
|
|
43
|
+
everyMs?: number;
|
|
44
|
+
};
|
|
45
|
+
/** `ui` surface options. */
|
|
46
|
+
type ProbeUiSurfaceConfig = ProbeSurfaceConfig & {
|
|
47
|
+
/** Max distinct views per document (default 30). */
|
|
48
|
+
maxViews?: number;
|
|
49
|
+
};
|
|
50
|
+
/** `console` surface options. */
|
|
51
|
+
type ProbeConsoleSurfaceConfig = ProbeSurfaceConfig & {
|
|
52
|
+
/** Console methods to observe (default `["error", "warn"]`). */
|
|
53
|
+
levels?: Array<"error" | "warn" | "info" | "log" | "debug">;
|
|
54
|
+
};
|
|
55
|
+
type ProbeSurfaces = {
|
|
56
|
+
page?: ProbeLevel | ProbeSurfaceConfig;
|
|
57
|
+
ui?: ProbeLevel | ProbeUiSurfaceConfig;
|
|
58
|
+
act?: ProbeLevel | ProbeSurfaceConfig;
|
|
59
|
+
nav?: ProbeLevel | ProbeSurfaceConfig;
|
|
60
|
+
res?: ProbeLevel | ProbeResSurfaceConfig;
|
|
61
|
+
store?: ProbeLevel | ProbeSurfaceConfig;
|
|
62
|
+
net?: ProbeLevel | ProbeNetSurfaceConfig;
|
|
63
|
+
form?: ProbeLevel | ProbeSurfaceConfig;
|
|
64
|
+
err?: ProbeLevel | ProbeSurfaceConfig;
|
|
65
|
+
console?: ProbeLevel | ProbeConsoleSurfaceConfig;
|
|
66
|
+
dl?: ProbeLevel | ProbeSurfaceConfig;
|
|
67
|
+
msg?: ProbeLevel | ProbeSurfaceConfig;
|
|
68
|
+
glob?: ProbeLevel | ProbeSurfaceConfig;
|
|
69
|
+
cev?: ProbeLevel | ProbeSurfaceConfig;
|
|
70
|
+
};
|
|
71
|
+
/** Method options (used by rules, snapshot fields and correlate values). */
|
|
72
|
+
type ProbeMethodOptions = {
|
|
73
|
+
method: ProbeMethod;
|
|
74
|
+
/** `enum`: the values that may be emitted as they are. */
|
|
75
|
+
values?: string[];
|
|
76
|
+
/** `shape`: leading characters kept as they are. */
|
|
77
|
+
keepPrefix?: number;
|
|
78
|
+
/** `mask`: characters kept at the start / end. */
|
|
79
|
+
keepStart?: number;
|
|
80
|
+
keepEnd?: number;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* One redaction rule. A rule applies when every scope it names matches; the first matching rule wins.
|
|
84
|
+
* Keys are compared case-insensitively with `-`, `_` and spaces ignored; a key containing `.` is a dotted
|
|
85
|
+
* path glob matched against the end of the value's path (`data.json_data.bound`, `*.assertion_id`).
|
|
86
|
+
*/
|
|
87
|
+
type ProbeRule = ProbeMethodOptions & {
|
|
88
|
+
surface?: ProbeSurface | ProbeSurface[];
|
|
89
|
+
/** Host globs of the URL the value belongs to (`net`, `res`, `page`, `nav`); the page host for DOM surfaces. */
|
|
90
|
+
host?: string | string[];
|
|
91
|
+
/** Path globs of that URL; the page path for DOM surfaces. */
|
|
92
|
+
path?: string | string[];
|
|
93
|
+
/** Key names or dotted path globs (body keys, query parameters, storage keys, form field names). */
|
|
94
|
+
key?: string | string[];
|
|
95
|
+
/** CSS selector (`ui`, `act`, `form`): applies to matching elements and their subtree. */
|
|
96
|
+
selector?: string;
|
|
97
|
+
/** `net` only: which part of the exchange. */
|
|
98
|
+
part?: "url" | "request" | "response";
|
|
99
|
+
};
|
|
100
|
+
/** Network matcher. */
|
|
101
|
+
type ProbeNetMatch = {
|
|
102
|
+
host?: string | string[];
|
|
103
|
+
path?: string | string[];
|
|
104
|
+
method?: string | string[];
|
|
105
|
+
/** Status codes, or `ok` (2xx/3xx) / `error` (0, ≥ 400 or not loaded). Ignored at request time. */
|
|
106
|
+
status?: number[] | "ok" | "error";
|
|
107
|
+
/** Request body conditions: dotted path → expected value(s), compared as strings. */
|
|
108
|
+
body?: Record<string, string | string[]>;
|
|
109
|
+
/** Response body conditions (same form). */
|
|
110
|
+
response?: Record<string, string | string[]>;
|
|
111
|
+
};
|
|
112
|
+
/** Something that happens on the page: used by `trigger.on`, `snapshot.on` and `count.on`. */
|
|
113
|
+
type ProbeMatch = {
|
|
114
|
+
net?: ProbeNetMatch;
|
|
115
|
+
/** A visible element matching this selector appears. */
|
|
116
|
+
selector?: string;
|
|
117
|
+
/** A click on (or inside) an element matching this selector. */
|
|
118
|
+
click?: string;
|
|
119
|
+
/** A form submit (`true` = any form, string = form selector). */
|
|
120
|
+
submit?: string | true;
|
|
121
|
+
/** `handle.signal(name)` from the host. */
|
|
122
|
+
signal?: string;
|
|
123
|
+
/** The host context (`deps.context().state`) enters this state. */
|
|
124
|
+
state?: string;
|
|
125
|
+
/** An uncaught error or unhandled rejection. */
|
|
126
|
+
error?: true;
|
|
127
|
+
};
|
|
128
|
+
/** A body value to read: dotted path (`[]` iterates arrays, `**` searches any depth; JSON strings are parsed). */
|
|
129
|
+
type ProbePathPick = Partial<ProbeMethodOptions> & {
|
|
130
|
+
path: string;
|
|
131
|
+
/** Output name (default: the path). */
|
|
132
|
+
as?: string;
|
|
133
|
+
};
|
|
134
|
+
type ProbeSnapshotAction = {
|
|
135
|
+
type: "snapshot";
|
|
136
|
+
name: string;
|
|
137
|
+
on: ProbeMatch;
|
|
138
|
+
/** Form fields: value via `method` (default `class`), validity flags, `aria-invalid`, nearby error text. */
|
|
139
|
+
fields?: Array<Partial<ProbeMethodOptions> & {
|
|
140
|
+
selector: string;
|
|
141
|
+
as?: string;
|
|
142
|
+
}>;
|
|
143
|
+
/** Visible texts of these selectors (free-text redaction). */
|
|
144
|
+
texts?: string[];
|
|
145
|
+
/** Request / response body values (only when `on.net` matched). */
|
|
146
|
+
request?: ProbePathPick[];
|
|
147
|
+
response?: ProbePathPick[];
|
|
148
|
+
/** Max snapshots per document (default 20). */
|
|
149
|
+
max?: number;
|
|
150
|
+
};
|
|
151
|
+
/**
|
|
152
|
+
* Remember `key → value` pairs seen in one exchange and resolve the key in a later one, emitting only the
|
|
153
|
+
* value (e.g. an OTP send: the channel id never leaves the page, its channel type does).
|
|
154
|
+
*/
|
|
155
|
+
type ProbeCorrelateAction = {
|
|
156
|
+
type: "correlate";
|
|
157
|
+
name: string;
|
|
158
|
+
/** Item kind (default `corr`). */
|
|
159
|
+
kind?: string;
|
|
160
|
+
learn: {
|
|
161
|
+
net: ProbeNetMatch;
|
|
162
|
+
/** Body to learn from (default `response`). */
|
|
163
|
+
from?: "request" | "response";
|
|
164
|
+
/** Path of the objects to learn from (e.g. `**.channels[]`). */
|
|
165
|
+
items: string;
|
|
166
|
+
/** Path of the key inside an item (kept in memory only). */
|
|
167
|
+
key: string;
|
|
168
|
+
/** Path of the value inside an item. */
|
|
169
|
+
value: string;
|
|
170
|
+
/** How the value is emitted (default `enum` with `values`, else `class`). */
|
|
171
|
+
method?: ProbeMethod;
|
|
172
|
+
values?: string[];
|
|
173
|
+
/** Paths inside an item whose size is reported with the offered values (object keys / array length / 1). */
|
|
174
|
+
count?: string[];
|
|
175
|
+
};
|
|
176
|
+
resolve: {
|
|
177
|
+
net: ProbeNetMatch;
|
|
178
|
+
/** Body holding the key (default `request`). */
|
|
179
|
+
from?: "request" | "response";
|
|
180
|
+
/** Path(s) of the key; the first that resolves wins. */
|
|
181
|
+
key: string | string[];
|
|
182
|
+
/** Extra values emitted with the result. */
|
|
183
|
+
fields?: ProbePathPick[];
|
|
184
|
+
};
|
|
185
|
+
/** Max emissions per document (default 50). */
|
|
186
|
+
max?: number;
|
|
187
|
+
};
|
|
188
|
+
type ProbeCountAction = {
|
|
189
|
+
type: "count";
|
|
190
|
+
name: string;
|
|
191
|
+
on: ProbeMatch;
|
|
192
|
+
};
|
|
193
|
+
type ProbeAction = ProbeSnapshotAction | ProbeCorrelateAction | ProbeCountAction;
|
|
194
|
+
/** Conditions; all must hold. */
|
|
195
|
+
type ProbeWhen = {
|
|
196
|
+
/** Observe project ids (`deps.projectId`). */
|
|
197
|
+
projects?: string[];
|
|
198
|
+
/** ISO 8601 date or date-time; the probe is off after it. */
|
|
199
|
+
until?: string;
|
|
200
|
+
/** Fraction 0..1 of sessions, sticky per session id. */
|
|
201
|
+
sample?: number;
|
|
202
|
+
/** Browser names: `chrome`, `edge`, `safari`, `firefox`, `samsung`, `opera`, `other`. */
|
|
203
|
+
browser?: string[];
|
|
204
|
+
/** OS names: `windows`, `macos`, `ios`, `android`, `linux`, `chromeos`, `other`. */
|
|
205
|
+
os?: string[];
|
|
206
|
+
device?: Array<"desktop" | "mobile" | "tablet">;
|
|
207
|
+
/** Page path globs, evaluated per item. */
|
|
208
|
+
path?: string[];
|
|
209
|
+
/** Host context states (`deps.context().state`), evaluated per item. */
|
|
210
|
+
state?: string[];
|
|
211
|
+
/** Flow tags (`deps.tags()`): tag → allowed values (`*` = any). Items are buffered until the tag is known. */
|
|
212
|
+
tags?: Record<string, string[]>;
|
|
213
|
+
/** Integration version globs (`deps.integrationVersion`). */
|
|
214
|
+
integrationVersion?: string[];
|
|
215
|
+
};
|
|
216
|
+
/** Flight recorder: items are buffered and only sent when one of `on` happens. */
|
|
217
|
+
type ProbeTrigger = {
|
|
218
|
+
on: ProbeMatch[];
|
|
219
|
+
/** Ring buffer size in items (default 300) and bytes (default 300000). */
|
|
220
|
+
buffer?: number;
|
|
221
|
+
bufferBytes?: number;
|
|
222
|
+
/** After a trigger, items stream directly for this long (default 30000 ms) before buffering resumes. */
|
|
223
|
+
streamMs?: number;
|
|
224
|
+
};
|
|
225
|
+
type ProbeBudgets = {
|
|
226
|
+
/** Items per document (default 400). */
|
|
227
|
+
items?: number;
|
|
228
|
+
/** Serialized bytes per document (default 400000). */
|
|
229
|
+
bytes?: number;
|
|
230
|
+
/** Items per document and kind (defaults per kind, e.g. `ui` 40, `act` 150, `net` 150). */
|
|
231
|
+
perKind?: Record<string, number>;
|
|
232
|
+
};
|
|
233
|
+
/** Probe configuration, schema version 1. */
|
|
234
|
+
type ProbeConfig = {
|
|
235
|
+
v: 1;
|
|
236
|
+
/** Free label (not interpreted). */
|
|
237
|
+
name?: string;
|
|
238
|
+
when?: ProbeWhen;
|
|
239
|
+
trigger?: ProbeTrigger;
|
|
240
|
+
surfaces?: ProbeSurfaces;
|
|
241
|
+
rules?: ProbeRule[];
|
|
242
|
+
actions?: ProbeAction[];
|
|
243
|
+
budgets?: ProbeBudgets;
|
|
244
|
+
};
|
|
245
|
+
/** Host context stamped on items. */
|
|
246
|
+
type ProbeItemContext = {
|
|
247
|
+
state?: string;
|
|
248
|
+
flowType?: string;
|
|
249
|
+
step?: string;
|
|
250
|
+
};
|
|
251
|
+
/** What the engine hands to the sink (→ `tracker.probe`). */
|
|
252
|
+
type ProbeSinkItem = {
|
|
253
|
+
kind: string;
|
|
254
|
+
payload: Record<string, unknown> | unknown[];
|
|
255
|
+
pageId: string;
|
|
256
|
+
cfg: string;
|
|
257
|
+
ctx?: ProbeItemContext;
|
|
258
|
+
ts: number;
|
|
259
|
+
};
|
|
260
|
+
/**
|
|
261
|
+
* A network subscriber, shaped like autocapture-x's CaptureHub `NetworkSubscriber`: projectors run
|
|
262
|
+
* synchronously inside the network capture and are the only place raw bodies are seen.
|
|
263
|
+
*/
|
|
264
|
+
type ProbeNetworkSubscriber = {
|
|
265
|
+
id: string;
|
|
266
|
+
match(url: URL, method: string): boolean;
|
|
267
|
+
projectRequest?(body: unknown, context: NetworkBodyProjectionContext<"request">): unknown;
|
|
268
|
+
projectResponse?(body: unknown, context: NetworkBodyProjectionContext<"response">): unknown;
|
|
269
|
+
onRequest?(request: HttpRequestStarted<unknown>): void;
|
|
270
|
+
onExchange?(exchange: HttpExchange<unknown, unknown>): void;
|
|
271
|
+
};
|
|
272
|
+
/** CaptureHub-compatible network source: `{ subscribe: (s) => hub.subscribeNetwork(s) }`. */
|
|
273
|
+
type ProbeNetworkSource = {
|
|
274
|
+
/** Called synchronously by `startProbes`; may return an unsubscribe function. */
|
|
275
|
+
subscribe(subscriber: ProbeNetworkSubscriber): (() => void) | void;
|
|
276
|
+
};
|
|
277
|
+
type ProbeNavigationSource = {
|
|
278
|
+
subscribe(listener: (event: NavigationEvent) => void): (() => void) | void;
|
|
279
|
+
};
|
|
280
|
+
type ProbeWebAuthnSource = {
|
|
281
|
+
subscribe(listener: (event: WebAuthnCeremonyEvent) => void): (() => void) | void;
|
|
282
|
+
};
|
|
283
|
+
type ProbeDeps = {
|
|
284
|
+
/** Receives every redacted item (→ `tracker.probe(item)`). */
|
|
285
|
+
sink(item: ProbeSinkItem): void;
|
|
286
|
+
projectId: string;
|
|
287
|
+
/** Network source; falls back to the package's own `captureNetwork` when absent. */
|
|
288
|
+
network?: ProbeNetworkSource;
|
|
289
|
+
/** Navigation source; falls back to `captureNavigation` when absent. */
|
|
290
|
+
navigation?: ProbeNavigationSource;
|
|
291
|
+
/** WebAuthn events, used only to taint ceremony values; none when absent. */
|
|
292
|
+
webauthn?: ProbeWebAuthnSource;
|
|
293
|
+
context?(): ProbeItemContext | undefined;
|
|
294
|
+
tags?(): Record<string, string> | undefined;
|
|
295
|
+
/** Session id for sticky sampling. */
|
|
296
|
+
sessionId?(): string | undefined;
|
|
297
|
+
/** For `when.integrationVersion`. */
|
|
298
|
+
integrationVersion?: string;
|
|
299
|
+
now?(): number;
|
|
300
|
+
};
|
|
301
|
+
type ProbeHandle = {
|
|
302
|
+
/** `active`: capturing; `off`: a condition does not hold or the config is invalid; `unavailable`: no page or another engine runs. */
|
|
303
|
+
readonly mode: "active" | "off" | "unavailable";
|
|
304
|
+
/** Config hash stamped on every item (`cfg`). */
|
|
305
|
+
readonly hash: string;
|
|
306
|
+
/** Why the probe is not active. */
|
|
307
|
+
readonly reason?: string;
|
|
308
|
+
/** Host-signalled event (e.g. a step error) for `trigger.on` / actions `{ signal }`. */
|
|
309
|
+
signal(name: string): void;
|
|
310
|
+
disconnect(): void;
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Always-on guards. Not configurable: no config field reaches them.
|
|
315
|
+
*
|
|
316
|
+
* 1. Single DOM value read path: every field value read goes through {@link readFieldValue} /
|
|
317
|
+
* {@link fieldValueLength}; sensitive fields (passwords, one-time codes, card fields, inputs of
|
|
318
|
+
* WebAuthn-bound forms) yield at most their length.
|
|
319
|
+
* 2. Taint set: values that must never leave (typed passwords / OTPs, WebAuthn ceremony parts, cookie
|
|
320
|
+
* values, Authorization headers) are kept as salted rolling hashes; any occurrence anywhere in an
|
|
321
|
+
* item becomes `<tainted:len>`.
|
|
322
|
+
* 3. Pattern pass: JWT / JWE (any case), base64url WebAuthn client data, Luhn-valid card numbers,
|
|
323
|
+
* WebAuthn / password keys, high-entropy tokens ≥ 24 chars.
|
|
324
|
+
* 4. Fail closed: a guard that throws drops the item.
|
|
325
|
+
*/
|
|
326
|
+
|
|
327
|
+
/** Salted rolling-hash fingerprints of values that must never leave. Values themselves are not kept. */
|
|
328
|
+
declare class ProbeTaint {
|
|
329
|
+
private readonly base1;
|
|
330
|
+
private readonly base2;
|
|
331
|
+
private readonly byLength;
|
|
332
|
+
private readonly order;
|
|
333
|
+
constructor();
|
|
334
|
+
/** Number of fingerprints held. */
|
|
335
|
+
get size(): number;
|
|
336
|
+
/** Adds a value (and its URL-encoded / JSON-escaped forms). Values under 6 chars are ignored. */
|
|
337
|
+
add(value: unknown): void;
|
|
338
|
+
private addOne;
|
|
339
|
+
private fingerprint;
|
|
340
|
+
/** Replaces every tainted occurrence with `<tainted:len>`. */
|
|
341
|
+
scrub(text: string): string;
|
|
342
|
+
}
|
|
343
|
+
/** A fresh taint set (for tests / the conformance runner), optionally pre-filled. */
|
|
344
|
+
declare function createProbeTaint(values?: string[]): ProbeTaint;
|
|
345
|
+
/**
|
|
346
|
+
* The final always-on pass over an item: taint, pattern and key guards. Returns a guarded copy, or
|
|
347
|
+
* `undefined` when the pass fails (the item must then be dropped — fail closed).
|
|
348
|
+
*/
|
|
349
|
+
declare function applyGuards(item: unknown, taint?: ProbeTaint | null): unknown;
|
|
350
|
+
|
|
351
|
+
export { type ProbeTrigger as A, type ProbeUiSurfaceConfig as B, type ProbeWebAuthnSource as C, type ProbeWhen as D, applyGuards as E, createProbeTaint as F, type ProbeConfig as P, type ProbeDeps as a, type ProbeHandle as b, type ProbeAction as c, type ProbeBudgets as d, type ProbeConsoleSurfaceConfig as e, type ProbeCorrelateAction as f, type ProbeCountAction as g, type ProbeItemContext as h, type ProbeLevel as i, type ProbeMatch as j, type ProbeMethod as k, type ProbeMethodOptions as l, type ProbeNavigationSource as m, type ProbeNetMatch as n, type ProbeNetSurfaceConfig as o, type ProbeNetworkSource as p, type ProbeNetworkSubscriber as q, type ProbePathPick as r, type ProbeResSurfaceConfig as s, type ProbeRule as t, type ProbeSinkItem as u, type ProbeSnapshotAction as v, type ProbeSurface as w, type ProbeSurfaceConfig as x, type ProbeSurfaces as y, ProbeTaint as z };
|