Skip to content

Commit 0ff668f

Browse files
committed
feat: use v2 fingerprint
1 parent 988dbf3 commit 0ff668f

19 files changed

+485
-234
lines changed

analyze/edge-light.ts

+7-53
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { ArcjetLogger } from "@arcjet/protocol";
1+
import type { ArcjetLogger, ArcjetRequestDetails } from "@arcjet/protocol";
22

33
import * as core from "./wasm/arcjet_analyze_js_req.component.js";
44
import type {
@@ -14,6 +14,7 @@ import componentCore3Wasm from "./wasm/arcjet_analyze_js_req.component.core3.was
1414

1515
interface AnalyzeContext {
1616
log: ArcjetLogger;
17+
characteristics: string[];
1718
}
1819

1920
async function moduleFromPath(path: string): Promise<WebAssembly.Module> {
@@ -72,45 +73,19 @@ export {
7273
/**
7374
* Generate a fingerprint for the client. This is used to identify the client
7475
* across multiple requests.
75-
* @param ip - The IP address of the client.
76+
* @param context - The Arcjet Analyze context.
77+
* @param request - The request to fingerprint.
78+
* @param characteristics - The characteristics on which to fingerprint the request.
7679
* @returns A SHA-256 string fingerprint.
7780
*/
7881
export async function generateFingerprint(
7982
context: AnalyzeContext,
80-
ip: string,
83+
request: Partial<ArcjetRequestDetails>,
8184
): Promise<string> {
82-
if (ip == "") {
83-
return "";
84-
}
85-
8685
const analyze = await init(context);
8786

8887
if (typeof analyze !== "undefined") {
89-
return analyze.generateFingerprint(ip);
90-
}
91-
92-
if (hasSubtleCryptoDigest()) {
93-
// Fingerprint v1 is just the IP address
94-
const fingerprintRaw = `fp_1_${ip}`;
95-
96-
// Based on MDN example at
97-
// https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#converting_a_digest_to_a_hex_string
98-
99-
// Encode the raw fingerprint into a utf-8 Uint8Array
100-
const fingerprintUint8 = new TextEncoder().encode(fingerprintRaw);
101-
// Hash the message with SHA-256
102-
const fingerprintArrayBuffer = await crypto.subtle.digest(
103-
"SHA-256",
104-
fingerprintUint8,
105-
);
106-
// Convert the ArrayBuffer to a byte array
107-
const fingerprintArray = Array.from(new Uint8Array(fingerprintArrayBuffer));
108-
// Convert the bytes to a hex string
109-
const fingerprint = fingerprintArray
110-
.map((b) => b.toString(16).padStart(2, "0"))
111-
.join("");
112-
113-
return fingerprint;
88+
return analyze.generateFingerprint(JSON.stringify(request), context.characteristics);
11489
}
11590

11691
return "";
@@ -149,24 +124,3 @@ export async function detectBot(
149124
};
150125
}
151126
}
152-
153-
function hasSubtleCryptoDigest() {
154-
if (typeof crypto === "undefined") {
155-
return false;
156-
}
157-
158-
if (!("subtle" in crypto)) {
159-
return false;
160-
}
161-
if (typeof crypto.subtle === "undefined") {
162-
return false;
163-
}
164-
if (!("digest" in crypto.subtle)) {
165-
return false;
166-
}
167-
if (typeof crypto.subtle.digest !== "function") {
168-
return false;
169-
}
170-
171-
return true;
172-
}

analyze/index.ts

+6-53
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { ArcjetLogger } from "@arcjet/protocol";
1+
import type { ArcjetLogger, ArcjetRequestDetails } from "@arcjet/protocol";
22

33
import * as core from "./wasm/arcjet_analyze_js_req.component.js";
44
import type {
@@ -14,6 +14,7 @@ import { wasm as componentCore3Wasm } from "./wasm/arcjet_analyze_js_req.compone
1414

1515
interface AnalyzeContext {
1616
log: ArcjetLogger;
17+
characteristics: string[];
1718
}
1819

1920
// TODO: Do we actually need this wasmCache or does `import` cache correctly?
@@ -86,45 +87,18 @@ export {
8687
/**
8788
* Generate a fingerprint for the client. This is used to identify the client
8889
* across multiple requests.
89-
* @param ip - The IP address of the client.
90+
* @param context - The Arcjet Analyze context.
91+
* @param request - The request to fingerprint.
9092
* @returns A SHA-256 string fingerprint.
9193
*/
9294
export async function generateFingerprint(
9395
context: AnalyzeContext,
94-
ip: string,
96+
request: Partial<ArcjetRequestDetails>,
9597
): Promise<string> {
96-
if (ip == "") {
97-
return "";
98-
}
99-
10098
const analyze = await init(context);
10199

102100
if (typeof analyze !== "undefined") {
103-
return analyze.generateFingerprint(ip);
104-
}
105-
106-
if (hasSubtleCryptoDigest()) {
107-
// Fingerprint v1 is just the IP address
108-
const fingerprintRaw = `fp_1_${ip}`;
109-
110-
// Based on MDN example at
111-
// https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#converting_a_digest_to_a_hex_string
112-
113-
// Encode the raw fingerprint into a utf-8 Uint8Array
114-
const fingerprintUint8 = new TextEncoder().encode(fingerprintRaw);
115-
// Hash the message with SHA-256
116-
const fingerprintArrayBuffer = await crypto.subtle.digest(
117-
"SHA-256",
118-
fingerprintUint8,
119-
);
120-
// Convert the ArrayBuffer to a byte array
121-
const fingerprintArray = Array.from(new Uint8Array(fingerprintArrayBuffer));
122-
// Convert the bytes to a hex string
123-
const fingerprint = fingerprintArray
124-
.map((b) => b.toString(16).padStart(2, "0"))
125-
.join("");
126-
127-
return fingerprint;
101+
return analyze.generateFingerprint(JSON.stringify(request), context.characteristics);
128102
}
129103

130104
return "";
@@ -163,24 +137,3 @@ export async function detectBot(
163137
};
164138
}
165139
}
166-
167-
function hasSubtleCryptoDigest() {
168-
if (typeof crypto === "undefined") {
169-
return false;
170-
}
171-
172-
if (!("subtle" in crypto)) {
173-
return false;
174-
}
175-
if (typeof crypto.subtle === "undefined") {
176-
return false;
177-
}
178-
if (!("digest" in crypto.subtle)) {
179-
return false;
180-
}
181-
if (typeof crypto.subtle.digest !== "function") {
182-
return false;
183-
}
184-
185-
return true;
186-
}
Binary file not shown.
Binary file not shown.
Binary file not shown.

analyze/wasm/arcjet_analyze_js_req.component.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export interface ImportObject {
2828
}
2929
export interface Root {
3030
detectBot(headers: string, patternsAdd: string, patternsRemove: string): BotDetectionResult,
31-
generateFingerprint(ip: string): string,
31+
generateFingerprint(request: string, characteristics: string[]): string,
3232
isValidEmail(candidate: string, options: EmailValidationConfig | undefined): boolean,
3333
}
3434

analyze/wasm/arcjet_analyze_js_req.component.js

+16-6
Original file line numberDiff line numberDiff line change
@@ -163,15 +163,25 @@ async function instantiate(getCoreModule, imports, instantiateCore = WebAssembly
163163
return variant5.val;
164164
}
165165

166-
function generateFingerprint(arg0) {
166+
function generateFingerprint(arg0, arg1) {
167167
var ptr0 = utf8Encode(arg0, realloc0, memory0);
168168
var len0 = utf8EncodedLen;
169-
const ret = exports1['generate-fingerprint'](ptr0, len0);
170-
var ptr1 = dataView(memory0).getInt32(ret + 0, true);
171-
var len1 = dataView(memory0).getInt32(ret + 4, true);
172-
var result1 = utf8Decoder.decode(new Uint8Array(memory0.buffer, ptr1, len1));
169+
var vec2 = arg1;
170+
var len2 = vec2.length;
171+
var result2 = realloc0(0, 0, 4, len2 * 8);
172+
for (let i = 0; i < vec2.length; i++) {
173+
const e = vec2[i];
174+
const base = result2 + i * 8;var ptr1 = utf8Encode(e, realloc0, memory0);
175+
var len1 = utf8EncodedLen;
176+
dataView(memory0).setInt32(base + 4, len1, true);
177+
dataView(memory0).setInt32(base + 0, ptr1, true);
178+
}
179+
const ret = exports1['generate-fingerprint'](ptr0, len0, result2, len2);
180+
var ptr3 = dataView(memory0).getInt32(ret + 0, true);
181+
var len3 = dataView(memory0).getInt32(ret + 4, true);
182+
var result3 = utf8Decoder.decode(new Uint8Array(memory0.buffer, ptr3, len3));
173183
postReturn1(ret);
174-
return result1;
184+
return result3;
175185
}
176186

177187
function isValidEmail(arg0, arg1) {
Binary file not shown.
1.59 MB
Binary file not shown.

analyze/workerd.ts

+7-53
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { ArcjetLogger } from "@arcjet/protocol";
1+
import type { ArcjetLogger, ArcjetRequestDetails } from "@arcjet/protocol";
22

33
import * as core from "./wasm/arcjet_analyze_js_req.component.js";
44
import type {
@@ -14,6 +14,7 @@ import componentCore3Wasm from "./wasm/arcjet_analyze_js_req.component.core3.was
1414

1515
interface AnalyzeContext {
1616
log: ArcjetLogger;
17+
characteristics: string[];
1718
}
1819

1920
async function moduleFromPath(path: string): Promise<WebAssembly.Module> {
@@ -72,45 +73,19 @@ export {
7273
/**
7374
* Generate a fingerprint for the client. This is used to identify the client
7475
* across multiple requests.
75-
* @param ip - The IP address of the client.
76+
* @param context - The Arcjet Analyze context.
77+
* @param request - The request to fingerprint.
78+
* @param characteristics - The characteristics on which to fingerprint the request.
7679
* @returns A SHA-256 string fingerprint.
7780
*/
7881
export async function generateFingerprint(
7982
context: AnalyzeContext,
80-
ip: string,
83+
request: Partial<ArcjetRequestDetails>,
8184
): Promise<string> {
82-
if (ip == "") {
83-
return "";
84-
}
85-
8685
const analyze = await init(context);
8786

8887
if (typeof analyze !== "undefined") {
89-
return analyze.generateFingerprint(ip);
90-
}
91-
92-
if (hasSubtleCryptoDigest()) {
93-
// Fingerprint v1 is just the IP address
94-
const fingerprintRaw = `fp_1_${ip}`;
95-
96-
// Based on MDN example at
97-
// https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#converting_a_digest_to_a_hex_string
98-
99-
// Encode the raw fingerprint into a utf-8 Uint8Array
100-
const fingerprintUint8 = new TextEncoder().encode(fingerprintRaw);
101-
// Hash the message with SHA-256
102-
const fingerprintArrayBuffer = await crypto.subtle.digest(
103-
"SHA-256",
104-
fingerprintUint8,
105-
);
106-
// Convert the ArrayBuffer to a byte array
107-
const fingerprintArray = Array.from(new Uint8Array(fingerprintArrayBuffer));
108-
// Convert the bytes to a hex string
109-
const fingerprint = fingerprintArray
110-
.map((b) => b.toString(16).padStart(2, "0"))
111-
.join("");
112-
113-
return fingerprint;
88+
return analyze.generateFingerprint(JSON.stringify(request), context.characteristics);
11489
}
11590

11691
return "";
@@ -149,24 +124,3 @@ export async function detectBot(
149124
};
150125
}
151126
}
152-
153-
function hasSubtleCryptoDigest() {
154-
if (typeof crypto === "undefined") {
155-
return false;
156-
}
157-
158-
if (!("subtle" in crypto)) {
159-
return false;
160-
}
161-
if (typeof crypto.subtle === "undefined") {
162-
return false;
163-
}
164-
if (!("digest" in crypto.subtle)) {
165-
return false;
166-
}
167-
if (typeof crypto.subtle.digest !== "function") {
168-
return false;
169-
}
170-
171-
return true;
172-
}

0 commit comments

Comments
 (0)