diff --git a/analyze/edge-light.ts b/analyze/edge-light.ts index 4b213c273..b4003eb41 100644 --- a/analyze/edge-light.ts +++ b/analyze/edge-light.ts @@ -75,14 +75,6 @@ async function init( } const coreImports: ImportObject = { - "arcjet:js-req/logger": { - debug(msg) { - log.debug(msg); - }, - error(msg) { - log.error(msg); - }, - }, "arcjet:js-req/email-validator-overrides": { isFreeEmail(domain) { if (FREE_EMAIL_PROVIDERS.includes(domain)) { diff --git a/analyze/index.ts b/analyze/index.ts index cf5c1c74d..7d968e8d4 100644 --- a/analyze/index.ts +++ b/analyze/index.ts @@ -89,14 +89,6 @@ async function init( } const coreImports: ImportObject = { - "arcjet:js-req/logger": { - debug(msg) { - log.debug(msg); - }, - error(msg) { - log.error(msg); - }, - }, "arcjet:js-req/email-validator-overrides": { isFreeEmail(domain) { if (FREE_EMAIL_PROVIDERS.includes(domain)) { diff --git a/analyze/wasm/arcjet_analyze_js_req.component.core.wasm b/analyze/wasm/arcjet_analyze_js_req.component.core.wasm index 61e62b0ec..1075a6e50 100644 Binary files a/analyze/wasm/arcjet_analyze_js_req.component.core.wasm and b/analyze/wasm/arcjet_analyze_js_req.component.core.wasm differ diff --git a/analyze/wasm/arcjet_analyze_js_req.component.core2.wasm b/analyze/wasm/arcjet_analyze_js_req.component.core2.wasm index fff86cfa2..1a64ba43b 100644 Binary files a/analyze/wasm/arcjet_analyze_js_req.component.core2.wasm and b/analyze/wasm/arcjet_analyze_js_req.component.core2.wasm differ diff --git a/analyze/wasm/arcjet_analyze_js_req.component.core3.wasm b/analyze/wasm/arcjet_analyze_js_req.component.core3.wasm index 85f7ba66b..03d778025 100644 Binary files a/analyze/wasm/arcjet_analyze_js_req.component.core3.wasm and b/analyze/wasm/arcjet_analyze_js_req.component.core3.wasm differ diff --git a/analyze/wasm/arcjet_analyze_js_req.component.d.ts b/analyze/wasm/arcjet_analyze_js_req.component.d.ts index 69d7f0304..a606151ed 100644 --- a/analyze/wasm/arcjet_analyze_js_req.component.d.ts +++ b/analyze/wasm/arcjet_analyze_js_req.component.d.ts @@ -63,16 +63,15 @@ export interface BotResult { denied: Array, } import { ArcjetJsReqEmailValidatorOverrides } from './interfaces/arcjet-js-req-email-validator-overrides.js'; -import { ArcjetJsReqLogger } from './interfaces/arcjet-js-req-logger.js'; import { ArcjetJsReqSensitiveInformationIdentifier } from './interfaces/arcjet-js-req-sensitive-information-identifier.js'; export interface ImportObject { 'arcjet:js-req/email-validator-overrides': typeof ArcjetJsReqEmailValidatorOverrides, - 'arcjet:js-req/logger': typeof ArcjetJsReqLogger, 'arcjet:js-req/sensitive-information-identifier': typeof ArcjetJsReqSensitiveInformationIdentifier, } export interface Root { detectBot(request: string, options: BotConfig): BotResult, generateFingerprint(request: string, characteristics: Array): string, + validateCharacteristics(request: string, characteristics: Array): void, isValidEmail(candidate: string, options: EmailValidationConfig): EmailValidationResult, detectSensitiveInfo(content: string, options: SensitiveInfoConfig): SensitiveInfoResult, } diff --git a/analyze/wasm/arcjet_analyze_js_req.component.js b/analyze/wasm/arcjet_analyze_js_req.component.js index 4b0a81891..1d7f7ab36 100644 --- a/analyze/wasm/arcjet_analyze_js_req.component.js +++ b/analyze/wasm/arcjet_analyze_js_req.component.js @@ -39,7 +39,6 @@ function instantiate(getCoreModule, imports, instantiateCore = WebAssembly.insta const module2 = getCoreModule('arcjet_analyze_js_req.component.core3.wasm'); const { hasGravatar, hasMxRecords, isDisposableEmail, isFreeEmail } = imports['arcjet:js-req/email-validator-overrides']; - const { debug, error } = imports['arcjet:js-req/logger']; const { detect } = imports['arcjet:js-req/sensitive-information-identifier']; let gen = (function* init () { let exports0; @@ -48,20 +47,6 @@ function instantiate(getCoreModule, imports, instantiateCore = WebAssembly.insta let realloc0; function trampoline0(arg0, arg1) { - var ptr0 = arg0; - var len0 = arg1; - var result0 = utf8Decoder.decode(new Uint8Array(memory0.buffer, ptr0, len0)); - debug(result0); - } - - function trampoline1(arg0, arg1) { - var ptr0 = arg0; - var len0 = arg1; - var result0 = utf8Decoder.decode(new Uint8Array(memory0.buffer, ptr0, len0)); - error(result0); - } - - function trampoline2(arg0, arg1) { var ptr0 = arg0; var len0 = arg1; var result0 = utf8Decoder.decode(new Uint8Array(memory0.buffer, ptr0, len0)); @@ -92,7 +77,7 @@ function instantiate(getCoreModule, imports, instantiateCore = WebAssembly.insta return enum1; } - function trampoline3(arg0, arg1) { + function trampoline1(arg0, arg1) { var ptr0 = arg0; var len0 = arg1; var result0 = utf8Decoder.decode(new Uint8Array(memory0.buffer, ptr0, len0)); @@ -123,7 +108,7 @@ function instantiate(getCoreModule, imports, instantiateCore = WebAssembly.insta return enum1; } - function trampoline4(arg0, arg1) { + function trampoline2(arg0, arg1) { var ptr0 = arg0; var len0 = arg1; var result0 = utf8Decoder.decode(new Uint8Array(memory0.buffer, ptr0, len0)); @@ -154,7 +139,7 @@ function instantiate(getCoreModule, imports, instantiateCore = WebAssembly.insta return enum1; } - function trampoline5(arg0, arg1) { + function trampoline3(arg0, arg1) { var ptr0 = arg0; var len0 = arg1; var result0 = utf8Decoder.decode(new Uint8Array(memory0.buffer, ptr0, len0)); @@ -185,7 +170,7 @@ function instantiate(getCoreModule, imports, instantiateCore = WebAssembly.insta return enum1; } - function trampoline6(arg0, arg1, arg2) { + function trampoline4(arg0, arg1, arg2) { var len1 = arg1; var base1 = arg0; var result1 = []; @@ -248,21 +233,18 @@ function instantiate(getCoreModule, imports, instantiateCore = WebAssembly.insta let postReturn1; let postReturn2; let postReturn3; + let postReturn4; Promise.all([module0, module1, module2]).catch(() => {}); ({ exports: exports0 } = yield instantiateCore(yield module1)); ({ exports: exports1 } = yield instantiateCore(yield module0, { 'arcjet:js-req/email-validator-overrides': { - 'has-gravatar': exports0['5'], - 'has-mx-records': exports0['4'], - 'is-disposable-email': exports0['3'], - 'is-free-email': exports0['2'], - }, - 'arcjet:js-req/logger': { - debug: exports0['0'], - error: exports0['1'], + 'has-gravatar': exports0['3'], + 'has-mx-records': exports0['2'], + 'is-disposable-email': exports0['1'], + 'is-free-email': exports0['0'], }, 'arcjet:js-req/sensitive-information-identifier': { - detect: exports0['6'], + detect: exports0['4'], }, })); memory0 = exports1.memory; @@ -275,14 +257,13 @@ function instantiate(getCoreModule, imports, instantiateCore = WebAssembly.insta '2': trampoline2, '3': trampoline3, '4': trampoline4, - '5': trampoline5, - '6': trampoline6, }, })); postReturn0 = exports1['cabi_post_detect-bot']; postReturn1 = exports1['cabi_post_generate-fingerprint']; - postReturn2 = exports1['cabi_post_is-valid-email']; - postReturn3 = exports1['cabi_post_detect-sensitive-info']; + postReturn2 = exports1['cabi_post_validate-characteristics']; + postReturn3 = exports1['cabi_post_is-valid-email']; + postReturn4 = exports1['cabi_post_detect-sensitive-info']; function detectBot(arg0, arg1) { var ptr0 = utf8Encode(arg0, realloc0, memory0); @@ -404,12 +385,83 @@ function instantiate(getCoreModule, imports, instantiateCore = WebAssembly.insta dataView(memory0).setInt32(base + 0, ptr1, true); } const ret = exports1['generate-fingerprint'](ptr0, len0, result2, len2); - var ptr3 = dataView(memory0).getInt32(ret + 0, true); - var len3 = dataView(memory0).getInt32(ret + 4, true); - var result3 = utf8Decoder.decode(new Uint8Array(memory0.buffer, ptr3, len3)); - const retVal = result3; + let variant5; + switch (dataView(memory0).getUint8(ret + 0, true)) { + case 0: { + var ptr3 = dataView(memory0).getInt32(ret + 4, true); + var len3 = dataView(memory0).getInt32(ret + 8, true); + var result3 = utf8Decoder.decode(new Uint8Array(memory0.buffer, ptr3, len3)); + variant5= { + tag: 'ok', + val: result3 + }; + break; + } + case 1: { + var ptr4 = dataView(memory0).getInt32(ret + 4, true); + var len4 = dataView(memory0).getInt32(ret + 8, true); + var result4 = utf8Decoder.decode(new Uint8Array(memory0.buffer, ptr4, len4)); + variant5= { + tag: 'err', + val: result4 + }; + break; + } + default: { + throw new TypeError('invalid variant discriminant for expected'); + } + } + const retVal = variant5; postReturn1(ret); - return retVal; + if (typeof retVal === 'object' && retVal.tag === 'err') { + throw new ComponentError(retVal.val); + } + return retVal.val; + } + + function validateCharacteristics(arg0, arg1) { + var ptr0 = utf8Encode(arg0, realloc0, memory0); + var len0 = utf8EncodedLen; + var vec2 = arg1; + var len2 = vec2.length; + var result2 = realloc0(0, 0, 4, len2 * 8); + for (let i = 0; i < vec2.length; i++) { + const e = vec2[i]; + const base = result2 + i * 8;var ptr1 = utf8Encode(e, realloc0, memory0); + var len1 = utf8EncodedLen; + dataView(memory0).setInt32(base + 4, len1, true); + dataView(memory0).setInt32(base + 0, ptr1, true); + } + const ret = exports1['validate-characteristics'](ptr0, len0, result2, len2); + let variant4; + switch (dataView(memory0).getUint8(ret + 0, true)) { + case 0: { + variant4= { + tag: 'ok', + val: undefined + }; + break; + } + case 1: { + var ptr3 = dataView(memory0).getInt32(ret + 4, true); + var len3 = dataView(memory0).getInt32(ret + 8, true); + var result3 = utf8Decoder.decode(new Uint8Array(memory0.buffer, ptr3, len3)); + variant4= { + tag: 'err', + val: result3 + }; + break; + } + default: { + throw new TypeError('invalid variant discriminant for expected'); + } + } + const retVal = variant4; + postReturn2(ret); + if (typeof retVal === 'object' && retVal.tag === 'err') { + throw new ComponentError(retVal.val); + } + return retVal.val; } function isValidEmail(arg0, arg1) { @@ -478,7 +530,7 @@ function instantiate(getCoreModule, imports, instantiateCore = WebAssembly.insta } } const retVal = variant8; - postReturn2(ret); + postReturn3(ret); if (typeof retVal === 'object' && retVal.tag === 'err') { throw new ComponentError(retVal.val); } @@ -704,11 +756,11 @@ function instantiate(getCoreModule, imports, instantiateCore = WebAssembly.insta allowed: result12, denied: result15, }; - postReturn3(ret); + postReturn4(ret); return retVal; } - return { detectBot, detectSensitiveInfo, generateFingerprint, isValidEmail, }; + return { detectBot, detectSensitiveInfo, generateFingerprint, isValidEmail, validateCharacteristics, }; })(); let promise, resolve, reject; function runNext (value) { diff --git a/analyze/wasm/arcjet_analyze_js_req.component.wasm b/analyze/wasm/arcjet_analyze_js_req.component.wasm index 70591385b..0896d8f53 100644 Binary files a/analyze/wasm/arcjet_analyze_js_req.component.wasm and b/analyze/wasm/arcjet_analyze_js_req.component.wasm differ diff --git a/analyze/workerd.ts b/analyze/workerd.ts index 5f7025c37..e9c19c83d 100644 --- a/analyze/workerd.ts +++ b/analyze/workerd.ts @@ -75,14 +75,6 @@ async function init( } const coreImports: ImportObject = { - "arcjet:js-req/logger": { - debug(msg) { - log.debug(msg); - }, - error(msg) { - log.error(msg); - }, - }, "arcjet:js-req/email-validator-overrides": { isFreeEmail(domain) { if (FREE_EMAIL_PROVIDERS.includes(domain)) { diff --git a/arcjet/index.ts b/arcjet/index.ts index 5b8e3556b..44437b9f1 100644 --- a/arcjet/index.ts +++ b/arcjet/index.ts @@ -1246,13 +1246,32 @@ export default function arcjet< ...ctx, }; - log.time?.("fingerprint"); - const fingerprint = await analyze.generateFingerprint( - baseContext, - toAnalyzeRequest(details), - ); - log.debug("fingerprint (%s): %s", rt, fingerprint); - log.timeEnd?.("fingerprint"); + let fingerprint = ""; + try { + log.time?.("fingerprint"); + fingerprint = await analyze.generateFingerprint( + baseContext, + toAnalyzeRequest(details), + ); + log.debug("fingerprint (%s): %s", rt, fingerprint); + } catch (e) { + log.error( + "Failed to build fingerprint. Please verify your Characteristics.", + ); + + const decision = new ArcjetErrorDecision({ + ttl: 0, + reason: new ArcjetErrorReason("Failed to build fingerprint"), + // No results because we couldn't create a fingerprint + results: [], + }); + + // TODO: Consider sending this to Report when we have an infallible fingerprint + + return decision; + } finally { + log.timeEnd?.("fingerprint"); + } const context: ArcjetContext = Object.freeze({ ...baseContext, diff --git a/arcjet/test/index.edge.test.ts b/arcjet/test/index.edge.test.ts index 3de7f29c0..fe0f6e279 100644 --- a/arcjet/test/index.edge.test.ts +++ b/arcjet/test/index.edge.test.ts @@ -109,7 +109,7 @@ describe("Arcjet: Env = Edge runtime", () => { abc: 123, requested: 1, email: "", - ip: "", + ip: "100.100.100.100", method: "", protocol: "", host: "", diff --git a/arcjet/test/index.node.test.ts b/arcjet/test/index.node.test.ts index ccf7c9eb6..157fd5277 100644 --- a/arcjet/test/index.node.test.ts +++ b/arcjet/test/index.node.test.ts @@ -2623,7 +2623,7 @@ describe("SDK", () => { expect(denied.protect).toHaveBeenCalledTimes(1); }); - test("works with an empty request object", async () => { + test("returns an ERROR decision if fingerprint cannot be generated", async () => { const client = { decide: jest.fn(async () => { return new ArcjetAllowDecision({ @@ -2649,10 +2649,10 @@ describe("SDK", () => { }; const decision = await aj.protect(context, request); - expect(decision.conclusion).toEqual("ALLOW"); + expect(decision.conclusion).toEqual("ERROR"); }); - test("does not crash with no request object", async () => { + test("returns an ERROR decision with no request object", async () => { const client = { decide: jest.fn(async () => { return new ArcjetAllowDecision({ @@ -2673,7 +2673,7 @@ describe("SDK", () => { // @ts-expect-error const decision = await aj.protect(); - expect(decision.conclusion).toEqual("ALLOW"); + expect(decision.conclusion).toEqual("ERROR"); }); test("returns an ERROR decision when more than 10 rules are generated", async () => { @@ -2688,7 +2688,9 @@ describe("SDK", () => { report: jest.fn(), }; - const request = {}; + const request = { + ip: "100.100.100.100", + }; const rules: ArcjetRule[][] = []; // We only iterate 4 times because `testRuleMultiple` generates 3 rules diff --git a/redact-wasm/wasm/arcjet_analyze_bindings_redact.component.core.wasm b/redact-wasm/wasm/arcjet_analyze_bindings_redact.component.core.wasm index c8c98a3ff..b35e52752 100644 Binary files a/redact-wasm/wasm/arcjet_analyze_bindings_redact.component.core.wasm and b/redact-wasm/wasm/arcjet_analyze_bindings_redact.component.core.wasm differ diff --git a/redact-wasm/wasm/arcjet_analyze_bindings_redact.component.core2.wasm b/redact-wasm/wasm/arcjet_analyze_bindings_redact.component.core2.wasm index 2e8bae216..16654bcfa 100644 Binary files a/redact-wasm/wasm/arcjet_analyze_bindings_redact.component.core2.wasm and b/redact-wasm/wasm/arcjet_analyze_bindings_redact.component.core2.wasm differ diff --git a/redact-wasm/wasm/arcjet_analyze_bindings_redact.component.core3.wasm b/redact-wasm/wasm/arcjet_analyze_bindings_redact.component.core3.wasm index acd59fb74..33e68cd44 100644 Binary files a/redact-wasm/wasm/arcjet_analyze_bindings_redact.component.core3.wasm and b/redact-wasm/wasm/arcjet_analyze_bindings_redact.component.core3.wasm differ diff --git a/redact-wasm/wasm/arcjet_analyze_bindings_redact.component.wasm b/redact-wasm/wasm/arcjet_analyze_bindings_redact.component.wasm index 422cc5b5f..3f9747d23 100644 Binary files a/redact-wasm/wasm/arcjet_analyze_bindings_redact.component.wasm and b/redact-wasm/wasm/arcjet_analyze_bindings_redact.component.wasm differ