@arcjet/analyze
Version:
Arcjet local analysis engine
119 lines (116 loc) • 4.3 kB
JavaScript
import { initializeWasm } from '@arcjet/analyze-wasm';
const FREE_EMAIL_PROVIDERS = [
"gmail.com",
"yahoo.com",
"hotmail.com",
"aol.com",
"hotmail.co.uk",
];
function noOpSensitiveInfoDetect() {
return [];
}
function noOpBotsDetect() {
return [];
}
function createCoreImports(detect) {
if (typeof detect !== "function") {
detect = noOpSensitiveInfoDetect;
}
return {
"arcjet:js-req/bot-identifier": {
detect: noOpBotsDetect,
},
"arcjet:js-req/email-validator-overrides": {
isFreeEmail(domain) {
if (FREE_EMAIL_PROVIDERS.includes(domain)) {
return "yes";
}
return "unknown";
},
isDisposableEmail() {
return "unknown";
},
hasMxRecords() {
return "unknown";
},
hasGravatar() {
return "unknown";
},
},
// TODO(@wooorm-arcjet): figure out a test case for this with the default `detect`.
"arcjet:js-req/sensitive-information-identifier": {
detect,
},
// TODO(@wooorm-arcjet): figure out a test case for this that calls `verify`.
"arcjet:js-req/verify-bot": {
verify() {
return "unverifiable";
},
},
};
}
// TODO(@wooorm-arcjet): document what is used to fingerprint.
/**
* Generate a fingerprint for the client. This is used to identify the client
* across multiple requests.
* @param context - The Arcjet Analyze context.
* @param request - The request to fingerprint.
* @returns A SHA-256 string fingerprint.
*/
async function generateFingerprint(context, request) {
const { log } = context;
const coreImports = createCoreImports();
const analyze = await initializeWasm(coreImports);
if (typeof analyze !== "undefined") {
return analyze.generateFingerprint(JSON.stringify(request), context.characteristics);
// Ignore the `else` branch as we test in places that have WebAssembly.
/* node:coverage ignore next 4 */
}
log.debug("WebAssembly is not supported in this runtime");
return "";
}
// TODO(@wooorm-arcjet): docs.
async function isValidEmail(context, candidate, options) {
const { log } = context;
const coreImports = createCoreImports();
const analyze = await initializeWasm(coreImports);
if (typeof analyze !== "undefined") {
return analyze.isValidEmail(candidate, options);
// Ignore the `else` branch as we test in places that have WebAssembly.
/* node:coverage ignore next 4 */
}
log.debug("WebAssembly is not supported in this runtime");
return { blocked: [], validity: "valid" };
}
// TODO(@wooorm-arcjet): docs.
async function detectBot(context, request, options) {
const { log } = context;
const coreImports = createCoreImports();
const analyze = await initializeWasm(coreImports);
if (typeof analyze !== "undefined") {
return analyze.detectBot(JSON.stringify(request), options);
// Ignore the `else` branch as we test in places that have WebAssembly.
/* node:coverage ignore next 4 */
}
log.debug("WebAssembly is not supported in this runtime");
return { allowed: [], denied: [], spoofed: false, verified: false };
}
// TODO(@wooorm-arcjet): docs.
async function detectSensitiveInfo(context, candidate, entities, contextWindowSize, detect) {
const { log } = context;
const coreImports = createCoreImports(detect);
const analyze = await initializeWasm(coreImports);
if (typeof analyze !== "undefined") {
const skipCustomDetect = typeof detect !== "function";
return analyze.detectSensitiveInfo(candidate, {
entities,
contextWindowSize,
skipCustomDetect,
});
// Ignore the `else` branch as we test in places that have WebAssembly.
/* node:coverage ignore next 4 */
}
log.debug("WebAssembly is not supported in this runtime");
throw new Error("SENSITIVE_INFO rule failed to run because Wasm is not supported in this environment.");
}
export { detectBot, detectSensitiveInfo, generateFingerprint, isValidEmail };