diff --git a/analyze-wasm/wasm/arcjet_analyze_js_req.component.core.wasm b/analyze-wasm/wasm/arcjet_analyze_js_req.component.core.wasm index 969d04b35..258df1ca1 100644 Binary files a/analyze-wasm/wasm/arcjet_analyze_js_req.component.core.wasm and b/analyze-wasm/wasm/arcjet_analyze_js_req.component.core.wasm differ diff --git a/analyze-wasm/wasm/arcjet_analyze_js_req.component.d.ts b/analyze-wasm/wasm/arcjet_analyze_js_req.component.d.ts index c0a627926..3625150da 100644 --- a/analyze-wasm/wasm/arcjet_analyze_js_req.component.d.ts +++ b/analyze-wasm/wasm/arcjet_analyze_js_req.component.d.ts @@ -12,10 +12,24 @@ export interface EmailValidationResult { validity: EmailValidity, blocked: Array, } -export interface EmailValidationConfig { +export interface AllowEmailValidationConfig { requireTopLevelDomain: boolean, allowDomainLiteral: boolean, - blockedEmails: Array, + allow: Array, +} +export interface DenyEmailValidationConfig { + requireTopLevelDomain: boolean, + allowDomainLiteral: boolean, + deny: Array, +} +export type EmailValidationConfig = EmailValidationConfigAllowEmailValidationConfig | EmailValidationConfigDenyEmailValidationConfig; +export interface EmailValidationConfigAllowEmailValidationConfig { + tag: 'allow-email-validation-config', + val: AllowEmailValidationConfig, +} +export interface EmailValidationConfigDenyEmailValidationConfig { + tag: 'deny-email-validation-config', + val: DenyEmailValidationConfig, } export type SensitiveInfoEntities = SensitiveInfoEntitiesAllow | SensitiveInfoEntitiesDeny; export interface SensitiveInfoEntitiesAllow { diff --git a/analyze-wasm/wasm/arcjet_analyze_js_req.component.js b/analyze-wasm/wasm/arcjet_analyze_js_req.component.js index 39e37af98..9ff89296b 100644 --- a/analyze-wasm/wasm/arcjet_analyze_js_req.component.js +++ b/analyze-wasm/wasm/arcjet_analyze_js_req.component.js @@ -514,61 +514,101 @@ function instantiate(getCoreModule, imports, instantiateCore = WebAssembly.insta function isValidEmail(arg0, arg1) { var ptr0 = utf8Encode(arg0, realloc0, memory0); var len0 = utf8EncodedLen; - var {requireTopLevelDomain: v1_0, allowDomainLiteral: v1_1, blockedEmails: v1_2 } = arg1; - var vec3 = v1_2; - var len3 = vec3.length; - var result3 = realloc0(0, 0, 4, len3 * 8); - for (let i = 0; i < vec3.length; i++) { - const e = vec3[i]; - const base = result3 + i * 8;var ptr2 = utf8Encode(e, realloc0, memory0); - var len2 = utf8EncodedLen; - dataView(memory0).setInt32(base + 4, len2, true); - dataView(memory0).setInt32(base + 0, ptr2, true); + var variant7 = arg1; + let variant7_0; + let variant7_1; + let variant7_2; + let variant7_3; + let variant7_4; + switch (variant7.tag) { + case 'allow-email-validation-config': { + const e = variant7.val; + var {requireTopLevelDomain: v1_0, allowDomainLiteral: v1_1, allow: v1_2 } = e; + var vec3 = v1_2; + var len3 = vec3.length; + var result3 = realloc0(0, 0, 4, len3 * 8); + for (let i = 0; i < vec3.length; i++) { + const e = vec3[i]; + const base = result3 + i * 8;var ptr2 = utf8Encode(e, realloc0, memory0); + var len2 = utf8EncodedLen; + dataView(memory0).setInt32(base + 4, len2, true); + dataView(memory0).setInt32(base + 0, ptr2, true); + } + variant7_0 = 0; + variant7_1 = v1_0 ? 1 : 0; + variant7_2 = v1_1 ? 1 : 0; + variant7_3 = result3; + variant7_4 = len3; + break; + } + case 'deny-email-validation-config': { + const e = variant7.val; + var {requireTopLevelDomain: v4_0, allowDomainLiteral: v4_1, deny: v4_2 } = e; + var vec6 = v4_2; + var len6 = vec6.length; + var result6 = realloc0(0, 0, 4, len6 * 8); + for (let i = 0; i < vec6.length; i++) { + const e = vec6[i]; + const base = result6 + i * 8;var ptr5 = utf8Encode(e, realloc0, memory0); + var len5 = utf8EncodedLen; + dataView(memory0).setInt32(base + 4, len5, true); + dataView(memory0).setInt32(base + 0, ptr5, true); + } + variant7_0 = 1; + variant7_1 = v4_0 ? 1 : 0; + variant7_2 = v4_1 ? 1 : 0; + variant7_3 = result6; + variant7_4 = len6; + break; + } + default: { + throw new TypeError(`invalid variant tag value \`${JSON.stringify(variant7.tag)}\` (received \`${variant7}\`) specified for \`EmailValidationConfig\``); + } } - const ret = exports1['is-valid-email'](ptr0, len0, v1_0 ? 1 : 0, v1_1 ? 1 : 0, result3, len3); - let variant8; + const ret = exports1['is-valid-email'](ptr0, len0, variant7_0, variant7_1, variant7_2, variant7_3, variant7_4); + let variant12; switch (dataView(memory0).getUint8(ret + 0, true)) { case 0: { - let enum4; + let enum8; switch (dataView(memory0).getUint8(ret + 4, true)) { case 0: { - enum4 = 'valid'; + enum8 = 'valid'; break; } case 1: { - enum4 = 'invalid'; + enum8 = 'invalid'; break; } default: { throw new TypeError('invalid discriminant specified for EmailValidity'); } } - var len6 = dataView(memory0).getInt32(ret + 12, true); - var base6 = dataView(memory0).getInt32(ret + 8, true); - var result6 = []; - for (let i = 0; i < len6; i++) { - const base = base6 + i * 8; - var ptr5 = dataView(memory0).getInt32(base + 0, true); - var len5 = dataView(memory0).getInt32(base + 4, true); - var result5 = utf8Decoder.decode(new Uint8Array(memory0.buffer, ptr5, len5)); - result6.push(result5); + var len10 = dataView(memory0).getInt32(ret + 12, true); + var base10 = dataView(memory0).getInt32(ret + 8, true); + var result10 = []; + for (let i = 0; i < len10; i++) { + const base = base10 + i * 8; + var ptr9 = dataView(memory0).getInt32(base + 0, true); + var len9 = dataView(memory0).getInt32(base + 4, true); + var result9 = utf8Decoder.decode(new Uint8Array(memory0.buffer, ptr9, len9)); + result10.push(result9); } - variant8= { + variant12= { tag: 'ok', val: { - validity: enum4, - blocked: result6, + validity: enum8, + blocked: result10, } }; break; } case 1: { - var ptr7 = dataView(memory0).getInt32(ret + 4, true); - var len7 = dataView(memory0).getInt32(ret + 8, true); - var result7 = utf8Decoder.decode(new Uint8Array(memory0.buffer, ptr7, len7)); - variant8= { + var ptr11 = dataView(memory0).getInt32(ret + 4, true); + var len11 = dataView(memory0).getInt32(ret + 8, true); + var result11 = utf8Decoder.decode(new Uint8Array(memory0.buffer, ptr11, len11)); + variant12= { tag: 'err', - val: result7 + val: result11 }; break; } @@ -576,7 +616,7 @@ function instantiate(getCoreModule, imports, instantiateCore = WebAssembly.insta throw new TypeError('invalid variant discriminant for expected'); } } - const retVal = variant8; + const retVal = variant12; postReturn3(ret); if (typeof retVal === 'object' && retVal.tag === 'err') { throw new ComponentError(retVal.val); diff --git a/analyze-wasm/wasm/arcjet_analyze_js_req.component.wasm b/analyze-wasm/wasm/arcjet_analyze_js_req.component.wasm index cfa68c8f3..69c259522 100644 Binary files a/analyze-wasm/wasm/arcjet_analyze_js_req.component.wasm and b/analyze-wasm/wasm/arcjet_analyze_js_req.component.wasm differ diff --git a/analyze/index.ts b/analyze/index.ts index 4fa8608dc..119fb26af 100644 --- a/analyze/index.ts +++ b/analyze/index.ts @@ -113,20 +113,14 @@ export async function generateFingerprint( export async function isValidEmail( context: AnalyzeContext, candidate: string, - options?: EmailValidationConfig, + options: EmailValidationConfig, ): Promise { const { log } = context; const coreImports = createCoreImports(); const analyze = await initializeWasm(coreImports); - const optionsOrDefault = { - requireTopLevelDomain: true, - allowDomainLiteral: false, - blockedEmails: [], - ...options, - }; if (typeof analyze !== "undefined") { - return analyze.isValidEmail(candidate, optionsOrDefault); + return analyze.isValidEmail(candidate, options); } else { log.debug("WebAssembly is not supported in this runtime"); // Skip the local evaluation of the rule if WASM is not available diff --git a/arcjet/index.ts b/arcjet/index.ts index dcf107587..e90404b6e 100644 --- a/arcjet/index.ts +++ b/arcjet/index.ts @@ -36,6 +36,7 @@ import type { DetectedSensitiveInfoEntity, SensitiveInfoEntity, BotConfig, + EmailValidationConfig, } from "@arcjet/analyze"; import * as duration from "@arcjet/duration"; import ArcjetHeaders from "@arcjet/headers"; @@ -521,13 +522,24 @@ type BotOptionsDeny = { export type BotOptions = BotOptionsAllow | BotOptionsDeny; -export type EmailOptions = { +type EmailOptionsAllow = { mode?: ArcjetMode; - block?: ArcjetEmailType[]; + allow: ArcjetEmailType[]; + deny?: never; + requireTopLevelDomain?: boolean; + allowDomainLiteral?: boolean; +}; + +type EmailOptionsDeny = { + mode?: ArcjetMode; + allow?: never; + deny: ArcjetEmailType[]; requireTopLevelDomain?: boolean; allowDomainLiteral?: boolean; }; +export type EmailOptions = EmailOptionsAllow | EmailOptionsDeny; + type DetectSensitiveInfoEntities = ( tokens: string[], ) => Array; @@ -946,22 +958,65 @@ export function validateEmail( validateEmailOptions(options); const mode = options.mode === "LIVE" ? "LIVE" : "DRY_RUN"; - const block = options.block ?? []; + if ( + typeof options.allow !== "undefined" && + typeof options.deny !== "undefined" + ) { + throw new Error( + "`validateEmail` options error: `allow` and `deny` cannot be provided together", + ); + } + if ( + typeof options.allow === "undefined" && + typeof options.deny === "undefined" + ) { + throw new Error( + "`validateEmail` options error: either `allow` or `deny` must be specified", + ); + } + const allow = options.allow ?? []; + const deny = options.deny ?? []; const requireTopLevelDomain = options.requireTopLevelDomain ?? true; const allowDomainLiteral = options.allowDomainLiteral ?? false; - const emailOpts = { - requireTopLevelDomain, - allowDomainLiteral, - blockedEmails: block, + let config: EmailValidationConfig = { + tag: "allow-email-validation-config", + val: { + requireTopLevelDomain, + allowDomainLiteral, + allow: [], + }, }; + if (typeof options.allow !== "undefined") { + config = { + tag: "allow-email-validation-config", + val: { + requireTopLevelDomain, + allowDomainLiteral, + allow: options.allow, + }, + }; + } + + if (typeof options.deny !== "undefined") { + config = { + tag: "deny-email-validation-config", + val: { + requireTopLevelDomain, + allowDomainLiteral, + deny: options.deny, + }, + }; + } + return [ >{ type: "EMAIL", priority: Priority.EmailValidation, mode, - block, + allow, + deny, requireTopLevelDomain, allowDomainLiteral, @@ -979,7 +1034,7 @@ export function validateEmail( context: ArcjetContext, { email }: ArcjetRequestDetails & { email: string }, ): Promise { - const result = await analyze.isValidEmail(context, email, emailOpts); + const result = await analyze.isValidEmail(context, email, config); if (result.validity === "valid") { return new ArcjetRuleResult({ ttl: 0, diff --git a/arcjet/test/arcjet.test.ts b/arcjet/test/arcjet.test.ts index 66ebe7a48..dca927be3 100644 --- a/arcjet/test/arcjet.test.ts +++ b/arcjet/test/arcjet.test.ts @@ -1221,9 +1221,9 @@ describe("Primitive > validateEmail", () => { ); }); - test("allows specifying EmailTypes to block", async () => { + test("allows specifying EmailTypes to deny", async () => { const options = { - block: [ + deny: [ ArcjetEmailType.DISPOSABLE, ArcjetEmailType.FREE, ArcjetEmailType.NO_GRAVATAR, @@ -1234,7 +1234,29 @@ describe("Primitive > validateEmail", () => { const [rule] = validateEmail(options); expect(rule.type).toEqual("EMAIL"); - expect(rule).toHaveProperty("block", [ + expect(rule).toHaveProperty("deny", [ + "DISPOSABLE", + "FREE", + "NO_GRAVATAR", + "NO_MX_RECORDS", + "INVALID", + ]); + }); + + test("allows specifying EmailTypes to allow", async () => { + const options = { + allow: [ + ArcjetEmailType.DISPOSABLE, + ArcjetEmailType.FREE, + ArcjetEmailType.NO_GRAVATAR, + ArcjetEmailType.NO_MX_RECORDS, + ArcjetEmailType.INVALID, + ], + }; + + const [rule] = validateEmail(options); + expect(rule.type).toEqual("EMAIL"); + expect(rule).toHaveProperty("allow", [ "DISPOSABLE", "FREE", "NO_GRAVATAR", @@ -1256,7 +1278,7 @@ describe("Primitive > validateEmail", () => { email: "abc@example.com", }; - const [rule] = validateEmail({ mode: "LIVE" }); + const [rule] = validateEmail({ mode: "LIVE", deny: [] }); expect(rule.type).toEqual("EMAIL"); assertIsLocalRule(rule); expect(() => { @@ -1277,7 +1299,7 @@ describe("Primitive > validateEmail", () => { email: undefined, }; - const [rule] = validateEmail({ mode: "LIVE" }); + const [rule] = validateEmail({ mode: "LIVE", deny: [] }); expect(rule.type).toEqual("EMAIL"); assertIsLocalRule(rule); expect(() => { @@ -1307,7 +1329,7 @@ describe("Primitive > validateEmail", () => { extra: {}, }; - const [rule] = validateEmail({ mode: "LIVE" }); + const [rule] = validateEmail({ mode: "LIVE", deny: [] }); expect(rule.type).toEqual("EMAIL"); assertIsLocalRule(rule); const result = await rule.protect(context, details); @@ -1342,7 +1364,7 @@ describe("Primitive > validateEmail", () => { extra: {}, }; - const [rule] = validateEmail({ mode: "LIVE" }); + const [rule] = validateEmail({ mode: "LIVE", deny: [] }); expect(rule.type).toEqual("EMAIL"); assertIsLocalRule(rule); const result = await rule.protect(context, details); @@ -1377,7 +1399,7 @@ describe("Primitive > validateEmail", () => { extra: {}, }; - const [rule] = validateEmail({ mode: "LIVE" }); + const [rule] = validateEmail({ mode: "LIVE", deny: [] }); expect(rule.type).toEqual("EMAIL"); assertIsLocalRule(rule); const result = await rule.protect(context, details); @@ -1413,7 +1435,7 @@ describe("Primitive > validateEmail", () => { }; const [rule] = validateEmail({ - block: [], + deny: [], }); expect(rule.type).toEqual("EMAIL"); assertIsLocalRule(rule); @@ -1449,7 +1471,7 @@ describe("Primitive > validateEmail", () => { extra: {}, }; - const [rule] = validateEmail({ mode: "LIVE" }); + const [rule] = validateEmail({ mode: "LIVE", deny: [] }); expect(rule.type).toEqual("EMAIL"); assertIsLocalRule(rule); const result = await rule.protect(context, details); @@ -1484,7 +1506,7 @@ describe("Primitive > validateEmail", () => { extra: {}, }; - const [rule] = validateEmail({ mode: "LIVE" }); + const [rule] = validateEmail({ mode: "LIVE", deny: [] }); expect(rule.type).toEqual("EMAIL"); assertIsLocalRule(rule); const result = await rule.protect(context, details); @@ -1521,6 +1543,7 @@ describe("Primitive > validateEmail", () => { const [rule] = validateEmail({ requireTopLevelDomain: false, + deny: [], }); expect(rule.type).toEqual("EMAIL"); assertIsLocalRule(rule); @@ -1558,6 +1581,7 @@ describe("Primitive > validateEmail", () => { const [rule] = validateEmail({ allowDomainLiteral: true, + deny: [], }); expect(rule.type).toEqual("EMAIL"); assertIsLocalRule(rule); @@ -2288,6 +2312,7 @@ describe("Products > protectSignup", () => { allow: [], }, email: { + allow: [], mode: ArcjetMode.LIVE, }, }); diff --git a/examples/nestjs-fastify/src/validate-email/validate-email.controller.ts b/examples/nestjs-fastify/src/validate-email/validate-email.controller.ts index 6f34e3a52..248350984 100644 --- a/examples/nestjs-fastify/src/validate-email/validate-email.controller.ts +++ b/examples/nestjs-fastify/src/validate-email/validate-email.controller.ts @@ -19,7 +19,7 @@ export class ValidateEmailController { // also running ArcjetGuard on the handlers calling `protect()` to avoid // making multiple requests to Arcjet. @Inject(ARCJET) private readonly arcjet: ArcjetNest, - ) {} + ) { } @Post() async validateEmail(@Req() req: Request, @Body() email: string) { @@ -27,7 +27,10 @@ export class ValidateEmailController { .withRule( validateEmail({ mode: 'LIVE', - block: ['DISPOSABLE', 'INVALID', 'NO_MX_RECORDS'], + deny: ['DISPOSABLE', 'INVALID', 'NO_MX_RECORDS'], + // Alternatively, you can specify a list of email types to allow. + // This will block all others. + // allow: ['FREE'], }), ) .protect(req, { email }); diff --git a/examples/nestjs/src/validate-email/validate-email.controller.ts b/examples/nestjs/src/validate-email/validate-email.controller.ts index 6f34e3a52..248350984 100644 --- a/examples/nestjs/src/validate-email/validate-email.controller.ts +++ b/examples/nestjs/src/validate-email/validate-email.controller.ts @@ -19,7 +19,7 @@ export class ValidateEmailController { // also running ArcjetGuard on the handlers calling `protect()` to avoid // making multiple requests to Arcjet. @Inject(ARCJET) private readonly arcjet: ArcjetNest, - ) {} + ) { } @Post() async validateEmail(@Req() req: Request, @Body() email: string) { @@ -27,7 +27,10 @@ export class ValidateEmailController { .withRule( validateEmail({ mode: 'LIVE', - block: ['DISPOSABLE', 'INVALID', 'NO_MX_RECORDS'], + deny: ['DISPOSABLE', 'INVALID', 'NO_MX_RECORDS'], + // Alternatively, you can specify a list of email types to allow. + // This will block all others. + // allow: ['FREE'], }), ) .protect(req, { email }); diff --git a/examples/nextjs-app-dir-rate-limit/app/api/custom_timeout/route.ts b/examples/nextjs-app-dir-rate-limit/app/api/custom_timeout/route.ts index a77227ef5..210b39abc 100644 --- a/examples/nextjs-app-dir-rate-limit/app/api/custom_timeout/route.ts +++ b/examples/nextjs-app-dir-rate-limit/app/api/custom_timeout/route.ts @@ -13,7 +13,10 @@ const aj = arcjet({ rules: [ validateEmail({ mode: "LIVE", // will block requests. Use "DRY_RUN" to log only - block: ["NO_MX_RECORDS"], // block email addresses with no MX records + deny: ["NO_MX_RECORDS"], // block email addresses with no MX records + // Alternatively, you can specify a list of email types to allow. + // This will block all others. + // allow: ['FREE'], }), ], client, @@ -35,4 +38,4 @@ export async function GET(req: Request) { } return NextResponse.json({ message: "Hello World" }); -} \ No newline at end of file +} diff --git a/examples/nextjs-app-dir-validate-email/app/api/arcjet/route.ts b/examples/nextjs-app-dir-validate-email/app/api/arcjet/route.ts index 4a34db8e1..6193c40e8 100644 --- a/examples/nextjs-app-dir-validate-email/app/api/arcjet/route.ts +++ b/examples/nextjs-app-dir-validate-email/app/api/arcjet/route.ts @@ -13,7 +13,10 @@ const aj = arcjet({ }), validateEmail({ mode: "LIVE", // will block requests. Use "DRY_RUN" to log only - block: ["NO_MX_RECORDS"], // block email addresses with no MX records + deny: ["NO_MX_RECORDS"], // block email addresses with no MX records + // Alternatively, you can specify a list of email types to allow. + // This will block all others. + // allow: ['FREE'], }), ], }); @@ -37,4 +40,4 @@ export async function GET(req: Request) { return NextResponse.json({ message: "Hello world", }); -} \ No newline at end of file +} diff --git a/examples/nextjs-server-actions/app/actions.ts b/examples/nextjs-server-actions/app/actions.ts index 0474dd36e..29c316aa8 100644 --- a/examples/nextjs-server-actions/app/actions.ts +++ b/examples/nextjs-server-actions/app/actions.ts @@ -7,7 +7,13 @@ const aj = arcjet({ // Use the `uid` cookie that is set by the middleware to fingerprint requests characteristics: ['http.request.cookie["uid"]'], rules: [ - validateEmail({ mode: "LIVE", block: ["DISPOSABLE", "NO_MX_RECORDS"] }) + validateEmail({ + mode: "LIVE", + deny: ["DISPOSABLE", "NO_MX_RECORDS"] + // Alternatively, you can specify a list of email types to allow. + // This will block all others. + // allow: ['FREE'], + }) ] }); diff --git a/protocol/convert.ts b/protocol/convert.ts index be22430a0..47d922815 100644 --- a/protocol/convert.ts +++ b/protocol/convert.ts @@ -619,15 +619,19 @@ export function ArcjetRuleToProtocol( } if (isEmailRule(rule)) { - const block = Array.isArray(rule.block) - ? rule.block.map(ArcjetEmailTypeToProtocol) + const allow = Array.isArray(rule.allow) + ? rule.allow.map(ArcjetEmailTypeToProtocol) + : []; + const deny = Array.isArray(rule.deny) + ? rule.deny.map(ArcjetEmailTypeToProtocol) : []; return new Rule({ rule: { case: "email", value: { mode: ArcjetModeToProtocol(rule.mode), - block, + allow, + deny, requireTopLevelDomain: rule.requireTopLevelDomain, allowDomainLiteral: rule.allowDomainLiteral, }, diff --git a/protocol/index.ts b/protocol/index.ts index d256511da..e0c86f8a0 100644 --- a/protocol/index.ts +++ b/protocol/index.ts @@ -765,7 +765,8 @@ export interface ArcjetEmailRule extends ArcjetLocalRule { type: "EMAIL"; - block: ArcjetEmailType[]; + allow: ArcjetEmailType[]; + deny: ArcjetEmailType[]; requireTopLevelDomain: boolean; allowDomainLiteral: boolean; } diff --git a/protocol/proto/decide/v1alpha1/decide_pb.d.ts b/protocol/proto/decide/v1alpha1/decide_pb.d.ts index a5d5cac1d..4ad8c54b0 100644 --- a/protocol/proto/decide/v1alpha1/decide_pb.d.ts +++ b/protocol/proto/decide/v1alpha1/decide_pb.d.ts @@ -1257,7 +1257,8 @@ export declare class EmailRule extends Message { * The email types to block. This may be one or more of the `EmailType` * values. * - * @generated from field: repeated proto.decide.v1alpha1.EmailType block = 2; + * @generated from field: repeated proto.decide.v1alpha1.EmailType block = 2 [deprecated = true]; + * @deprecated */ block: EmailType[]; @@ -1271,6 +1272,16 @@ export declare class EmailRule extends Message { */ allowDomainLiteral: boolean; + /** + * @generated from field: repeated proto.decide.v1alpha1.EmailType allow = 5; + */ + allow: EmailType[]; + + /** + * @generated from field: repeated proto.decide.v1alpha1.EmailType deny = 6; + */ + deny: EmailType[]; + constructor(data?: PartialMessage); static readonly runtime: typeof proto3; diff --git a/protocol/proto/decide/v1alpha1/decide_pb.js b/protocol/proto/decide/v1alpha1/decide_pb.js index 963176f3a..fd98d63de 100644 --- a/protocol/proto/decide/v1alpha1/decide_pb.js +++ b/protocol/proto/decide/v1alpha1/decide_pb.js @@ -378,6 +378,8 @@ export const EmailRule = /*@__PURE__*/ proto3.makeMessageType( { no: 2, name: "block", kind: "enum", T: proto3.getEnumType(EmailType), repeated: true }, { no: 3, name: "require_top_level_domain", kind: "scalar", T: 8 /* ScalarType.BOOL */ }, { no: 4, name: "allow_domain_literal", kind: "scalar", T: 8 /* ScalarType.BOOL */ }, + { no: 5, name: "allow", kind: "enum", T: proto3.getEnumType(EmailType), repeated: true }, + { no: 6, name: "deny", kind: "enum", T: proto3.getEnumType(EmailType), repeated: true }, ], ); diff --git a/protocol/test/convert.test.ts b/protocol/test/convert.test.ts index b2ab97b92..5130f72aa 100644 --- a/protocol/test/convert.test.ts +++ b/protocol/test/convert.test.ts @@ -661,7 +661,7 @@ describe("convert", () => { type: "EMAIL", mode: "DRY_RUN", priority: 1, - block: ["INVALID"], + deny: ["INVALID"], }), ).toEqual( new Rule({ @@ -669,7 +669,27 @@ describe("convert", () => { case: "email", value: { mode: Mode.DRY_RUN, - block: [EmailType.INVALID], + allow: [], + deny: [EmailType.INVALID], + }, + }, + }), + ); + expect( + ArcjetRuleToProtocol(>{ + type: "EMAIL", + mode: "DRY_RUN", + priority: 1, + allow: ["INVALID"], + }), + ).toEqual( + new Rule({ + rule: { + case: "email", + value: { + mode: Mode.DRY_RUN, + allow: [EmailType.INVALID], + deny: [], }, }, }),