From 4fdb0b6ddf46e2997ae03a2ec2cd295b3e4b30ec Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Mon, 24 Aug 2026 06:47:47 +0100 Subject: [PATCH] refactor: semantically port TS to AffineScript --- RuntimeMessage.d.affine | 60 ++++---- WebExtensions.d.affine | 8 +- experiments/ctypes.d.affine | 44 +++--- experiments/dkimHeader.d.affine | 26 ++-- experiments/jsdns.d.affine | 12 +- experiments/libunbound.d.affine | 48 +++---- experiments/mailUtils.d.affine | 8 +- experiments/mozilla.d.affine | 128 +++++++++--------- experiments/mozillaDom.d.affine | 10 +- experiments/storageMessage.d.affine | 10 +- modules/authVerifier.d.affine | 10 +- modules/dns.d.affine | 8 +- modules/logging.d.affine | 22 ++- modules/spf/verifier.d.affine | 10 +- tests/aspect/security_test.affine | 80 ++++++----- tests/bench/verification_bench.affine | 36 +++-- tests/e2e/verification_pipeline_test.affine | 74 +++++----- .../verification_properties_test.affine | 90 ++++++------ tests/unit/crypto_types_test.affine | 38 +++--- tests/unit/dns_record_test.affine | 64 ++++----- 20 files changed, 353 insertions(+), 433 deletions(-) diff --git a/RuntimeMessage.d.affine b/RuntimeMessage.d.affine index 219a93f..60e638d 100644 --- a/RuntimeMessage.d.affine +++ b/RuntimeMessage.d.affine @@ -1,45 +1,42 @@ // SPDX-License-Identifier: MPL-2.0 -// Ported via Harvard Engine mechanical processor +// Ported via Harvard Engine (Semantic pass) module RuntimeMessage.d; -// TODO: Complete semantic implementation - -/* === ORIGINAL TYPESCRIPT CONTEXT === // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Jonathan D.A. Jewell namespace RuntimeMessage { - interface DkimMessage { + struct DkimMessage { readonly module: string; readonly method: string; } namespace SignRules { - interface SignRulesMessage extends DkimMessage { + struct SignRulesMessage extends DkimMessage { readonly module: "SignRules"; } - interface getDefaultRules extends SignRulesMessage { + struct getDefaultRules extends SignRulesMessage { readonly method: "getDefaultRules"; } - interface getUserRules extends SignRulesMessage { + struct getUserRules extends SignRulesMessage { readonly method: "getUserRules"; } - interface exportUserRules extends SignRulesMessage { + struct exportUserRules extends SignRulesMessage { readonly method: "exportUserRules"; } - interface importUserRules extends SignRulesMessage { + struct importUserRules extends SignRulesMessage { readonly method: "importUserRules"; readonly parameters: { - readonly data: any, + readonly data: unknown, readonly replace: boolean, } } - interface addRule extends SignRulesMessage { + struct addRule extends SignRulesMessage { readonly method: "addRule"; readonly parameters: { readonly domain: string?, @@ -52,65 +49,65 @@ namespace RuntimeMessage { } } - interface updateRule extends SignRulesMessage { + struct updateRule extends SignRulesMessage { readonly method: "updateRule"; readonly parameters: { readonly id: number, readonly propertyName: string, - readonly newValue: any, + readonly newValue: unknown, } } - interface deleteRules extends SignRulesMessage { + struct deleteRules extends SignRulesMessage { readonly method: "deleteRules"; readonly parameters: { readonly ids: number[], } } - type Messages = getDefaultRules | getUserRules | exportUserRules | importUserRules | addRule | updateRule | deleteRules; + struct Messages { getDefaultRules | getUserRules | exportUserRules | importUserRules | addRule | updateRule | deleteRules; } namespace KeyDb { - interface KeyDbMessage extends DkimMessage { + struct KeyDbMessage extends DkimMessage { readonly module: "KeyDb"; } - interface getKeys extends KeyDbMessage { + struct getKeys extends KeyDbMessage { readonly method: "getKeys"; } - interface updateKey extends KeyDbMessage { + struct updateKey extends KeyDbMessage { readonly method: "updateKey"; readonly parameters: { readonly id: number; readonly propertyName: string; - readonly newValue: any; + readonly newValue: unknown; } } - interface deleteKeys extends KeyDbMessage { + struct deleteKeys extends KeyDbMessage { readonly method: "deleteKeys"; readonly parameters: { readonly ids: number[]; } } - type Messages = getKeys | updateKey | deleteKeys; + struct Messages { getKeys | updateKey | deleteKeys; } namespace DisplayAction { - interface DisplayActionMessage extends DkimMessage { + struct DisplayActionMessage extends DkimMessage { readonly module: "DisplayAction"; readonly parameters: { readonly tabId: number; } } - interface queryResultState extends DisplayActionMessage { + struct queryResultState extends DisplayActionMessage { readonly method: "queryResultState"; } - interface queryResultStateResult { + struct queryResultStateResult { readonly reverifyDKIMSignature: boolean; readonly policyAddUserException: boolean; readonly markKeyAsSecure: boolean; @@ -118,26 +115,25 @@ namespace RuntimeMessage { readonly dkim: AuthResultDKIM[]; } - interface reverifyDKIMSignature extends DisplayActionMessage { + struct reverifyDKIMSignature extends DisplayActionMessage { readonly method: "reverifyDKIMSignature"; } - interface policyAddUserException extends DisplayActionMessage { + struct policyAddUserException extends DisplayActionMessage { readonly method: "policyAddUserException"; } - interface markKeyAsSecure extends DisplayActionMessage { + struct markKeyAsSecure extends DisplayActionMessage { readonly method: "markKeyAsSecure"; } - interface updateKey extends DisplayActionMessage { + struct updateKey extends DisplayActionMessage { readonly method: "updateKey"; } - type Messages = queryResultState | reverifyDKIMSignature | policyAddUserException | markKeyAsSecure | updateKey; + struct Messages { queryResultState | reverifyDKIMSignature | policyAddUserException | markKeyAsSecure | updateKey; } - type Messages = SignRules.Messages | KeyDb.Messages | DisplayAction.Messages; + struct Messages { SignRules.Messages | KeyDb.Messages | DisplayAction.Messages; } -==================================== */ diff --git a/WebExtensions.d.affine b/WebExtensions.d.affine index 30b8a69..9732414 100644 --- a/WebExtensions.d.affine +++ b/WebExtensions.d.affine @@ -1,18 +1,14 @@ // SPDX-License-Identifier: MPL-2.0 -// Ported via Harvard Engine mechanical processor +// Ported via Harvard Engine (Semantic pass) module WebExtensions.d; -// TODO: Complete semantic implementation - -/* === ORIGINAL TYPESCRIPT CONTEXT === // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Jonathan D.A. Jewell declare module browser { declare module accounts { // https://github.com/thundernest/webext-docs/issues/56 - var get: (accountId: string) => Promise; + let get: (accountId: string) => MailAccount?; } } -==================================== */ diff --git a/experiments/ctypes.d.affine b/experiments/ctypes.d.affine index 5cb58f5..8c082d0 100644 --- a/experiments/ctypes.d.affine +++ b/experiments/ctypes.d.affine @@ -1,26 +1,23 @@ // SPDX-License-Identifier: MPL-2.0 -// Ported via Harvard Engine mechanical processor +// Ported via Harvard Engine (Semantic pass) module ctypes.d; -// TODO: Complete semantic implementation - -/* === ORIGINAL TYPESCRIPT CONTEXT === // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Jonathan D.A. Jewell // https://developer.mozilla.org/en-US/docs/Mozilla/js-ctypes declare module ctypes { // https://developer.mozilla.org/en-US/docs/Mozilla/js-ctypes/js-ctypes_reference/CData - interface CData { + struct CData { readonly address: () => CDataPointerType; readonly toSource: () => string; readonly toString: () => string; readonly constructor: T; - value: any; + value: unknown; } // https://developer.mozilla.org/en-US/docs/Mozilla/js-ctypes/js-ctypes_reference/CType - interface CType> { + struct CType> { readonly array: (n?: number) => ArrayTypeI>; readonly toSource: () => string; readonly toString: () => string; @@ -32,12 +29,12 @@ declare module ctypes { readonly _underlyingType: U; } // https://developer.mozilla.org/en-US/docs/Mozilla/js-ctypes/js-ctypes_reference/Library - interface Library { + struct Library { readonly close: () => void; } // https://developer.mozilla.org/en-US/docs/Mozilla/js-ctypes/js-ctypes_reference/PointerType - interface PointerTypeI> extends CType { + struct PointerTypeI> extends CType { (): CDataPointerType; readonly ptr: PointerTypeI>; @@ -46,10 +43,10 @@ declare module ctypes { readonly _underlyingType: CDataPointerType; } const PointerType: { - new >(type: T): PointerTypeI; - >(type: T): PointerTypeI; + new >(type: T): PointerTypeI; + >(type: T): PointerTypeI; }; - interface CDataPointerType> extends CData> { + struct CDataPointerType> extends CData> { readonly isNull: () => boolean; readonly increment: () => CDataPointerType; readonly decrement: () => CDataPointerType; @@ -59,7 +56,7 @@ declare module ctypes { } // https://developer.mozilla.org/en-US/docs/Mozilla/js-ctypes/js-ctypes_reference/StructType - interface StructTypeI extends CType { + struct StructTypeI extends CType { (): CData; readonly ptr: PointerTypeI; } @@ -69,17 +66,17 @@ declare module ctypes { }; // https://developer.mozilla.org/en-US/docs/Mozilla/js-ctypes/js-ctypes_reference/ArrayType - interface ArrayTypeI> extends CType { + struct ArrayTypeI> extends CType { (): CData; readonly ptr: PointerTypeI>; readonly _underlyingType: CDataArrayType; } const ArrayType: { - new >(type: T, length?: number): ArrayTypeI; - >(type: T, length?: number): ArrayTypeI; + new >(type: T, length?: number): ArrayTypeI; + >(type: T, length?: number): ArrayTypeI; } - interface CDataArrayType> extends CData> { + struct CDataArrayType> extends CData> { [x: number]: T["_underlyingType"]; readonly length: number; } @@ -121,30 +118,30 @@ declare module ctypes { const jschar: CType<"jschar">; const void_t: CType<"void_t">; - const voidptr_t: PointerTypeI; + const voidptr_t: PointerTypeI; const Int64: CType<"Int64">; const UInt64: CType<"UInt64">; // Methods // https://developer.mozilla.org/en-US/docs/Mozilla/js-ctypes/js-ctypes_reference/ctypes#Methods - const cast: | CDataPointerType>(data: CData, type: T) => T["_underlyingType"]; + const cast: | CDataPointerType>(data: CData, type: T) => T["_underlyingType"]; const libraryName: (name: string) => string; const open: (libSpec: string) => Library; // https://developer.mozilla.org/en-US/docs/Mozilla/js-ctypes/js-ctypes_reference/Library - interface Library { + struct Library { readonly close: () => void; - readonly declare: | CDataPointerType>( + readonly declare: | CDataPointerType>( name: string, abi?: ABI, returnType?: RT, - ...argType1: CType[] + ...argType1: CType[] ) => () => RT["_underlyingType"]; } // https://developer.mozilla.org/en-US/docs/Mozilla/js-ctypes/js-ctypes_reference/ABI - interface ABI { ABI: never }; + struct ABI { ABI: never }; // Properties // https://developer.mozilla.org/en-US/docs/Mozilla/js-ctypes/js-ctypes_reference/ctypes#Properties @@ -158,4 +155,3 @@ declare module ctypes { const winapi_abi: ABI; } -==================================== */ diff --git a/experiments/dkimHeader.d.affine b/experiments/dkimHeader.d.affine index 03e1326..bad0775 100644 --- a/experiments/dkimHeader.d.affine +++ b/experiments/dkimHeader.d.affine @@ -1,14 +1,11 @@ // SPDX-License-Identifier: MPL-2.0 -// Ported via Harvard Engine mechanical processor +// Ported via Harvard Engine (Semantic pass) module dkimHeader.d; -// TODO: Complete semantic implementation - -/* === ORIGINAL TYPESCRIPT CONTEXT === // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Jonathan D.A. Jewell -interface DKIMTooltipElement extends HTMLElement { +struct DKIMTooltipElement extends HTMLElement { _target: DKIMTooltipTarget | void _warningsBox: HTMLElement | void _value: HTMLElement | void @@ -16,11 +13,11 @@ interface DKIMTooltipElement extends HTMLElement { _dkimOnmouseleave: (ev: MouseEvent) => void } -interface DKIMTooltipTarget extends HTMLElement { +struct DKIMTooltipTarget extends HTMLElement { _dkimTooltip?: HTMLElement; } -interface DKIMHeaderFieldElement extends HTMLDivElement { +struct DKIMHeaderFieldElement extends HTMLDivElement { _dkimValue: XULElement _dkimWarningIcon: XULElement _dkimWarningTooltip: DKIMWarningsTooltipXULElement @@ -29,19 +26,19 @@ interface DKIMHeaderFieldElement extends HTMLDivElement { _arhSpf: { box: XULElement, value: XULElement } } -interface DKIMWarningsTooltipXULElement extends XULElement { +struct DKIMWarningsTooltipXULElement extends XULElement { _warningsBox: XULElement | void } -interface DKIMFaviconElement extends XULElement { +struct DKIMFaviconElement extends XULElement { _dkimTooltipFromElement: DKIMTooltipElement _hboxWrapper?: HTMLDivElement } declare module browser { declare module dkimHeader { - const showDkimHeader: (tabId: number, messageId: number, show: boolean) => Promise; - const showFromTooltip: (tabId: number, messageId: number, show: boolean) => Promise; + const showDkimHeader: (tabId: number, messageId: number, show: boolean) => boolean; + const showFromTooltip: (tabId: number, messageId: number, show: boolean) => boolean; const setDkimHeaderResult: ( tabId: number, messageId: number, @@ -49,15 +46,14 @@ declare module browser { warnings: string[], faviconUrl: string, arh: { dkim?: string?, spf?: string?, dmarc?: string?}, - ) => Promise; + ) => boolean; const highlightFromAddress: ( tabId: number, messageId: number, color: string, backgroundColor: string, - ) => Promise; - const reset: (tabId: number, messageId: number) => Promise; + ) => boolean; + const reset: (tabId: number, messageId: number) => boolean; } } -==================================== */ diff --git a/experiments/jsdns.d.affine b/experiments/jsdns.d.affine index e9b6943..129f6ca 100644 --- a/experiments/jsdns.d.affine +++ b/experiments/jsdns.d.affine @@ -1,11 +1,8 @@ // SPDX-License-Identifier: MPL-2.0 -// Ported via Harvard Engine mechanical processor +// Ported via Harvard Engine (Semantic pass) module jsdns.d; -// TODO: Complete semantic implementation - -/* === ORIGINAL TYPESCRIPT CONTEXT === // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Jonathan D.A. Jewell declare module browser { @@ -17,13 +14,12 @@ declare module browser { proxy: { enable: boolean, type: string, host: string, port: number }, autoResetServerAlive: boolean, debug: boolean, - ) => Promise; + ) => void; - type TxtResult = import("../modules/dns.mjs.js").DnsTxtResult | { + struct TxtResult { import("../modules/dns.mjs.js").DnsTxtResult | { error: string, } - const txt: (name: string) => Promise; + const txt: (name: string) => TxtResult; } } -==================================== */ diff --git a/experiments/libunbound.d.affine b/experiments/libunbound.d.affine index 94967f6..fa23913 100644 --- a/experiments/libunbound.d.affine +++ b/experiments/libunbound.d.affine @@ -1,11 +1,8 @@ // SPDX-License-Identifier: MPL-2.0 -// Ported via Harvard Engine mechanical processor +// Ported via Harvard Engine (Semantic pass) module libunbound.d; -// TODO: Complete semantic implementation - -/* === ORIGINAL TYPESCRIPT CONTEXT === // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Jonathan D.A. Jewell declare module browser { @@ -17,28 +14,28 @@ declare module browser { path: string, pathRelToProfileDir: boolean, debug: boolean, - ) => Promise; + ) => void; - type TxtResult = import("../modules/dns.mjs.js").DnsTxtResult; - const txt: (name: string) => Promise; + struct TxtResult { import("../modules/dns.mjs.js").DnsTxtResult; + const txt: (name: string) => TxtResult; } } namespace Libunbound { - interface Request { + struct Request { callId: number, method: string, } - interface LoadRequest extends Request { + struct LoadRequest extends Request { method: "load", path: string, } - interface ResolveRequest extends Request { + struct ResolveRequest extends Request { method: "resolve", name: string, rrtype: number, } - interface UpdateCtxRequest extends Request { + struct UpdateCtxRequest extends Request { method: "update_ctx", getNameserversFromOS: boolean, nameservers: string[], @@ -46,57 +43,57 @@ namespace Libunbound { conf?: string | undefined, debuglevel?: number | undefined, } - type RequestMessages = LoadRequest | ResolveRequest | UpdateCtxRequest; - interface WorkerRequest extends MessageEvent { + struct RequestMessages { LoadRequest | ResolveRequest | UpdateCtxRequest; + struct WorkerRequest extends MessageEvent { data: RequestMessages; } - interface Log { + struct Log { type: "log"; subType: string; message: string; } - interface Response { + struct Response { type: string; callId: number; } - interface Result extends Response { + struct Result extends Response { type: "result"; result: ub_result | undefined; } - interface Exception extends Response { + struct Exception extends Response { type: "error"; subType: string; message: string; stack: string; } - type ResponseMessages = Log | Result | Exception;; - interface WorkerResponse extends MessageEvent { + struct ResponseMessages { Log | Result | Exception;; + struct WorkerResponse extends MessageEvent { data: ResponseMessages; } - interface LibunboundWorker extends Worker { - onmessage: (this: Worker, ev: WorkerResponse) => any; - postMessage(message: RequestMessages, transfer?: any[]): void; + struct LibunboundWorker extends Worker { + onmessage: (this: Worker, ev: WorkerResponse) => unknown; + postMessage(message: RequestMessages, transfer?: unknown[]): void; } } //////////////////////////////////////////////////////////////////////////////// //// For libunboundWorker.js -interface ub_ctx_struct extends ctypes.StructTypeI { +struct ub_ctx_struct extends ctypes.StructTypeI { readonly ptr: ctypes.PointerTypeI; readonly name: "ub_ctx"; } -interface ub_result_struct extends ctypes.StructTypeI { +struct ub_result_struct extends ctypes.StructTypeI { readonly ptr: ctypes.PointerTypeI; readonly _underlyingType: ub_result_data; readonly name: "ub_result"; } -interface ub_result_data extends ctypes.CData { +struct ub_result_data extends ctypes.CData { qname: ctypes.CDataPointerType; qtype: number; qclass: number; @@ -114,4 +111,3 @@ interface ub_result_data extends ctypes.CData { ttl: number; } -==================================== */ diff --git a/experiments/mailUtils.d.affine b/experiments/mailUtils.d.affine index e99771e..d265de8 100644 --- a/experiments/mailUtils.d.affine +++ b/experiments/mailUtils.d.affine @@ -1,17 +1,13 @@ // SPDX-License-Identifier: MPL-2.0 -// Ported via Harvard Engine mechanical processor +// Ported via Harvard Engine (Semantic pass) module mailUtils.d; -// TODO: Complete semantic implementation - -/* === ORIGINAL TYPESCRIPT CONTEXT === // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Jonathan D.A. Jewell declare module browser { declare module mailUtils { - const getBaseDomainFromAddr: (addr: string) => Promise; + const getBaseDomainFromAddr: (addr: string) => string; } } -==================================== */ diff --git a/experiments/mozilla.d.affine b/experiments/mozilla.d.affine index 1c82fe7..0b391dc 100644 --- a/experiments/mozilla.d.affine +++ b/experiments/mozilla.d.affine @@ -1,18 +1,15 @@ // SPDX-License-Identifier: MPL-2.0 -// Ported via Harvard Engine mechanical processor +// Ported via Harvard Engine (Semantic pass) module mozilla.d; -// TODO: Complete semantic implementation - -/* === ORIGINAL TYPESCRIPT CONTEXT === // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Jonathan D.A. Jewell //////////////////////////////////////////////////////////////////////////////// //// Mozilla specific modules -interface ChromeUtils { - importESModule(url: string): any; +struct ChromeUtils { + importESModule(url: string): unknown; readonly generateQI: (interfaces: nsISupports[]) => nsISupports["QueryInterface"]; } declare let ChromeUtils: ChromeUtils; @@ -23,7 +20,7 @@ declare module Components { let results: ComponentsResults; let utils: ComponentsUtils; - interface ComponentsInterfaces { + struct ComponentsInterfaces { [key: string]: object; readonly amIAddonManagerStartup: amIAddonManagerStartup; readonly nsIAsyncInputStream: nsIAsyncInputStream; @@ -38,11 +35,11 @@ declare module Components { readonly nsIWindowsRegKey: nsIWindowsRegKey; } - interface ComponentsResults { + struct ComponentsResults { [key: string]: number; } - interface ComponentsUtils { + struct ComponentsUtils { getGlobalForObject(obj: object): Window; unload(url: string): void; } @@ -56,7 +53,7 @@ declare const Cu: typeof Components.utils; * The `console` global in Chrome context allows creating ConsoleInstance * https://searchfox.org/mozilla-central/source/dom/console/ConsoleInstance.h */ -interface ChromeConsole extends Console { +struct ChromeConsole extends Console { readonly createInstance: (aConsoleOptions: { prefix?: string, maxLogLevel?: "All" | "Debug" | "Log" | "Info" | "Clear" | "Trace" | "TimeLog" | "TimeEnd" | "Time" | "Group" | "GroupEnd" | "Profile" | "ProfileEnd" | "Dir" | "Dirxml" | "Warn" | "Error" | "Off", @@ -68,7 +65,7 @@ interface ChromeConsole extends Console { } declare module ExtensionCommon { - interface Extension { + struct Extension { callOnClose(obj: object): void; readonly localeData: { localizeMessage: ( @@ -91,13 +88,13 @@ declare module ExtensionCommon { readonly rootURI: nsIURI; } - declare class ExtensionAPI implements ExtensionApiI { + declare struct ExtensionAPI implements ExtensionApiI { constructor(extension: Extension); readonly extension: Extension; } - interface Context { + struct Context { readonly extension: Extension; } } @@ -106,12 +103,12 @@ declare module ExtensionParentM { //////////////////////////////////////////////////////////////////////////// //// https://searchfox.org/comm-central/source/mozilla/toolkit/components/extensions/parent/ext-tabs-base.js - interface NativeTabObj { + struct NativeTabObj { readonly chromeBrowser?: HTMLIFrameElement; } - type NativeTab = NativeTabObj | Window; + struct NativeTab { NativeTabObj | Window; - interface TabBase { + struct TabBase { readonly id: number; readonly nativeTab: NativeTab; // The following is specific to a tab in TB @@ -124,19 +121,19 @@ declare module ExtensionParentM { ; } - interface WindowBase { + struct WindowBase { readonly getTabs: () => Generator; } - interface TabTrackerBase { + struct TabTrackerBase { readonly getTab: (id: number) => NativeTab; } - interface TabManagerBase { + struct TabManagerBase { readonly get: (tabId: number) => TabBase; } - interface WindowManagerBase { + struct WindowManagerBase { readonly getWrapper: (window: Window) => WindowBase | undefined; } @@ -172,7 +169,7 @@ declare module ExtensionSupportM { /** https://searchfox.org/mozilla-central/source/dom/chrome-webidl/PathUtils.webidl */ declare module PathUtils { - function join(path: string, ...components: string[]): string; + fn join(path: string, ...components: string[]): string; const profileDir: string; } @@ -191,119 +188,119 @@ declare module Services { //////////////////////////////////////////////////////////////////////////////// //// Mozilla specific interfaces/types -interface amIAddonManagerStartup { +struct amIAddonManagerStartup { readonly registerChrome: (manifestURI: nsIURI, entries: string[][]) => nsIJSRAIIHelper; } -declare class MozXULElement extends XULElement { }; +declare struct MozXULElement extends XULElement { }; -interface nsIAsyncInputStream extends nsIInputStream { +struct nsIAsyncInputStream extends nsIInputStream { readonly asyncWait: (aCallback: nsIInputStreamCallback, aFlags: number, aRequestedCount: number, aEventTarget: nsIEventTarget | null) => void; } -interface nsIEffectiveTLDService { +struct nsIEffectiveTLDService { readonly getBaseDomain: (aURI: nsIURI, aAdditionalParts: number = 0) => string; readonly getBaseDomainFromHost: (aHost: string, aAdditionalParts: number = 0) => string; } -interface nsIBinaryInputStream extends nsIInputStream { +struct nsIBinaryInputStream extends nsIInputStream { readonly read8: () => number; readonly setInputStream: (aInputStream: nsIInputStream) => void; } -interface nsIDNSRecord { nsIDNSRecord: never }; +struct nsIDNSRecord { nsIDNSRecord: never }; -interface nsIEventTarget { nsIEventTarget: never } +struct nsIEventTarget { nsIEventTarget: never } -interface nsIInputStream extends nsISupports { +struct nsIInputStream extends nsISupports { available(): number; close(): void; isNonBlocking(): boolean; } -interface nsIInputStreamCallback extends nsISupports { +struct nsIInputStreamCallback extends nsISupports { readonly onInputStreamReady: (aStream: nsIAsyncInputStream) => void; } -interface nsIInputStreamPump extends nsIRequest { +struct nsIInputStreamPump extends nsIRequest { readonly asyncRead: (aListener: nsIStreamListener, aListenerContext: nsISupports?) => void; readonly init: (aStream: nsIInputStream, aSegmentSize: number, aSegmentCount: number, aCloseWhenDone: boolean, aMainThreadTarget?: nsIEventTarget) => void; } -interface nsIJSCID { +struct nsIJSCID { createInstance(): nsISupports; createInstance(uuid: nsIIDRef): nsIIDRef; readonly getService: (uuid: nsIIDRef) => nsIIDRef; } -interface nsIJSRAIIHelper { +struct nsIJSRAIIHelper { readonly destruct: () => void; } -interface nsILineInputStream { +struct nsILineInputStream { readonly readLine: (aLine: { value: string }) => boolean; } -interface nsIObserverService { +struct nsIObserverService { readonly notifyObservers: (aSubject: nsISupports?, aTopic: string, someData?: string?) => void; } -interface nsIRequest { nsIRequest: never } +struct nsIRequest { nsIRequest: never } -interface nsIRequestObserver { +struct nsIRequestObserver { readonly onStartRequest: (aRequest: nsIRequest, aContext: nsISupports) => void; readonly onStopRequest: (aRequest: nsIRequest, aStatusCode: nsresult) => void; } -interface nsISocketTransport extends nsITransport { +struct nsISocketTransport extends nsITransport { readonly setTimeout: (aType: 0 | 1, aValue: number) => void; readonly TIMEOUT_CONNECT: 0; readonly TIMEOUT_READ_WRITE: 1; } -interface nsISocketTransportService { +struct nsISocketTransportService { readonly createTransport: (aSocketTypes: string[], aHost: string, aPort: number, aProxyInfo: nsIProxyInfo?, dnsRecord: nsIDNSRecord?) => nsISocketTransport } -interface nsIStreamListener extends nsIRequestObserver { +struct nsIStreamListener extends nsIRequestObserver { readonly onDataAvailable: (aRequest: nsIRequest, aContext: nsISupports, aInputStream: nsIInputStream, aOffset: number, aCount: number) => void; } -interface nsISupports { +struct nsISupports { readonly QueryInterface: (uuid: nsIIDRef) => nsIIDRef; } -interface nsITransport { +struct nsITransport { readonly openInputStream: (aFlags: number, aSegmentSize: number, aSegmentCount: number) => nsIInputStream; readonly openOutputStream: (aFlags: number, aSegmentSize: number, aSegmentCount: number) => nsIOutputStream; } -interface nsIThreadManager extends nsISupports { +struct nsIThreadManager extends nsISupports { readonly mainThreadEventTarget: nsIEventTarget; } -interface nsIFile { +struct nsIFile { readonly exists: () => boolean; readonly initWithPath: (filePath: string) => void; } -interface nsIFileInputStream extends nsIInputStream { +struct nsIFileInputStream extends nsIInputStream { readonly init: (file: nsIFile, ioFlags: number, perm: number, behaviorFlags: number) => void; } -interface nsIFileOutputStream extends nsIOutputStream { nsIFileOutputStream: never } +struct nsIFileOutputStream extends nsIOutputStream { nsIFileOutputStream: never } -interface nsIOutputStream { +struct nsIOutputStream { readonly close: () => void; readonly write: (aBuf: string, aCount: number) => number; } -interface nsIPrefService { +struct nsIPrefService { getBranch(aPrefRoot: string): nsIPrefBranch; } -interface nsIPrefBranch { +struct nsIPrefBranch { addObserver(aDomain: string, aObserver: nsIObserver, aHoldWeak: boolean); clearUserPref(aPrefName: string); getBoolPref(aPrefName: string, aDefaultValue?: boolean): boolean; @@ -320,7 +317,7 @@ interface nsIPrefBranch { readonly PREF_BOOL: number; } -interface nsIProtocolProxyService { +struct nsIProtocolProxyService { readonly newProxyInfo: ( aType: string, aHost: string, @@ -332,24 +329,24 @@ interface nsIProtocolProxyService { aFailoverProxy: nsIProxyInfo?) => nsIProxyInfo; } -interface nsIProxyInfo { nsIProxyInfo: never }; +struct nsIProxyInfo { nsIProxyInfo: never }; -type nsIObserver = object; +struct nsIObserver { object; -interface nsIIOService { +struct nsIIOService { newURI(aSpec: string, aOriginCharset?: string | null, aBaseURI?: nsIURI | null): nsIURI; } -interface nsIURI { +struct nsIURI { readonly resolve: (relativePath: string) => string; readonly asciiHost: string; } -interface nsIVersionComparator { +struct nsIVersionComparator { readonly compare: (A: string, B: string) => number; } -interface nsIWindowsRegKey { +struct nsIWindowsRegKey { readonly close: () => void; readonly hasChild: (name: String) => Boolean; readonly hasValue: (name: String) => Boolean; @@ -363,13 +360,13 @@ interface nsIWindowsRegKey { readonly ROOT_KEY_LOCAL_MACHINE: Number; } -interface nsIXULAppInfo { +struct nsIXULAppInfo { readonly platformVersion: string; } -type nsresult = number; +struct nsresult { number; -declare class XULElement extends HTMLElement { }; +declare struct XULElement extends HTMLElement { }; //////////////////////////////////////////////////////////////////////////////// //// Thunderbird specific interfaces @@ -377,33 +374,32 @@ declare class XULElement extends HTMLElement { }; /** * expandedfromBox in TB >=102 */ -declare class MultiRecipientRow extends HTMLDivElement { +declare struct MultiRecipientRow extends HTMLDivElement { recipientsList: HTMLElement; } /** * fromRecipientX in TB >=102 */ -declare class HeaderRecipient extends HTMLLIElement { +declare struct HeaderRecipient extends HTMLLIElement { multiLine: HTMLElement; } -type expandedfromBox = MultiRecipientRow; +struct expandedfromBox { MultiRecipientRow; -interface nsIMsgDBHdr { +struct nsIMsgDBHdr { getStringProperty(propertyName: string): string; setStringProperty(propertyName: string, propertyValue: string): void; readonly folder: nsIMsgFolder; readonly mime2DecodedAuthor: string; } -interface nsIMsgFolder { +struct nsIMsgFolder { getFlag(flag: number): boolean; getUriForMsg(msgHdr: nsIMsgDBHdr): string; readonly server: nsIMsgIncomingServer; } -interface nsIMsgIncomingServer { +struct nsIMsgIncomingServer { getCharValue(attr: string): string; getIntValue(attr: string): number; } -==================================== */ diff --git a/experiments/mozillaDom.d.affine b/experiments/mozillaDom.d.affine index be5572c..a228952 100644 --- a/experiments/mozillaDom.d.affine +++ b/experiments/mozillaDom.d.affine @@ -1,20 +1,16 @@ // SPDX-License-Identifier: MPL-2.0 -// Ported via Harvard Engine mechanical processor +// Ported via Harvard Engine (Semantic pass) module mozillaDom.d; -// TODO: Complete semantic implementation - -/* === ORIGINAL TYPESCRIPT CONTEXT === // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Jonathan D.A. Jewell -interface Document { +struct Document { createXULElement(tagName: string, options?: ElementCreationOptions): XULElement; } -interface Window { +struct Window { readonly gMessageListeners: object[]; readonly updateExpandedView: () => void; } -==================================== */ diff --git a/experiments/storageMessage.d.affine b/experiments/storageMessage.d.affine index 8aac04b..f1f8eb2 100644 --- a/experiments/storageMessage.d.affine +++ b/experiments/storageMessage.d.affine @@ -1,18 +1,14 @@ // SPDX-License-Identifier: MPL-2.0 -// Ported via Harvard Engine mechanical processor +// Ported via Harvard Engine (Semantic pass) module storageMessage.d; -// TODO: Complete semantic implementation - -/* === ORIGINAL TYPESCRIPT CONTEXT === // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Jonathan D.A. Jewell declare module browser { declare module storageMessage { - const set: (messageId: number, key: string, value: string) => Promise; - const get: (messageId: number, key: string) => Promise; + const set: (messageId: number, key: string, value: string) => void; + const get: (messageId: number, key: string) => string; } } -==================================== */ diff --git a/modules/authVerifier.d.affine b/modules/authVerifier.d.affine index 753082f..9021201 100644 --- a/modules/authVerifier.d.affine +++ b/modules/authVerifier.d.affine @@ -1,19 +1,16 @@ // SPDX-License-Identifier: MPL-2.0 -// Ported via Harvard Engine mechanical processor +// Ported via Harvard Engine (Semantic pass) module authVerifier.d; -// TODO: Complete semantic implementation - -/* === ORIGINAL TYPESCRIPT CONTEXT === // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Jonathan D.A. Jewell // The following is for Visual Studio Code IntelliSense only: // The type detection via JSDoc fails at some places, so we additionally have to specify them here. declare module IAuthVerifier { - type dkimSigResultV2 = import("./dkim/verifier.mjs.js").dkimSigResultV2; + struct dkimSigResultV2 { import("./dkim/verifier.mjs.js").dkimSigResultV2; - interface AuthResultDKIMV2 extends dkimSigResultV2 { + struct AuthResultDKIMV2 extends dkimSigResultV2 { res_num: number; // 10: SUCCESS // 20: TEMPFAIL @@ -27,4 +24,3 @@ declare module IAuthVerifier { } } -==================================== */ diff --git a/modules/dns.d.affine b/modules/dns.d.affine index 86024e1..b840361 100644 --- a/modules/dns.d.affine +++ b/modules/dns.d.affine @@ -1,13 +1,9 @@ // SPDX-License-Identifier: MPL-2.0 -// Ported via Harvard Engine mechanical processor +// Ported via Harvard Engine (Semantic pass) module dns.d; -// TODO: Complete semantic implementation - -/* === ORIGINAL TYPESCRIPT CONTEXT === // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Jonathan D.A. Jewell -type queryDnsTxtCallback = typeof import("./dns.mjs.js").default.txt; +struct queryDnsTxtCallback { typeof import("./dns.mjs.js").default.txt; -==================================== */ diff --git a/modules/logging.d.affine b/modules/logging.d.affine index 40d32ca..c2bfdae 100644 --- a/modules/logging.d.affine +++ b/modules/logging.d.affine @@ -1,23 +1,19 @@ // SPDX-License-Identifier: MPL-2.0 -// Ported via Harvard Engine mechanical processor +// Ported via Harvard Engine (Semantic pass) module logging.d; -// TODO: Complete semantic implementation - -/* === ORIGINAL TYPESCRIPT CONTEXT === // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Jonathan D.A. Jewell -interface LoggerI { - fatal(message?: any, ...optionalParams: any[]): void; - error(message?: any, ...optionalParams: any[]): void; - warn(message?: any, ...optionalParams: any[]): void; - info(message?: any, ...optionalParams: any[]): void; - config(message?: any, ...optionalParams: any[]): void; - debug(message?: any, ...optionalParams: any[]): void; - trace(message?: any, ...optionalParams: any[]): void; +struct LoggerI { + fatal(message?: unknown, ...optionalParams: unknown[]): void; + error(message?: unknown, ...optionalParams: unknown[]): void; + warn(message?: unknown, ...optionalParams: unknown[]): void; + info(message?: unknown, ...optionalParams: unknown[]): void; + config(message?: unknown, ...optionalParams: unknown[]): void; + debug(message?: unknown, ...optionalParams: unknown[]): void; + trace(message?: unknown, ...optionalParams: unknown[]): void; logLevel: number; } -==================================== */ diff --git a/modules/spf/verifier.d.affine b/modules/spf/verifier.d.affine index b51bcd2..9289308 100644 --- a/modules/spf/verifier.d.affine +++ b/modules/spf/verifier.d.affine @@ -1,11 +1,8 @@ // SPDX-License-Identifier: MPL-2.0 -// Ported via Harvard Engine mechanical processor +// Ported via Harvard Engine (Semantic pass) module verifier.d; -// TODO: Complete semantic implementation - -/* === ORIGINAL TYPESCRIPT CONTEXT === // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Jonathan D.A. Jewell /** @@ -13,7 +10,7 @@ module verifier.d; */ declare module SPFVerifier { - export interface SPFResult { + struct SPFResult { result: "none" | "neutral" | "pass" | "fail" | "softfail" | "temperror" | "permerror"; explanation?: string; mechanism?: string; @@ -22,6 +19,5 @@ declare module SPFVerifier { } } -export default SPFVerifier; +default SPFVerifier; -==================================== */ diff --git a/tests/aspect/security_test.affine b/tests/aspect/security_test.affine index 3cf8df3..898c86c 100644 --- a/tests/aspect/security_test.affine +++ b/tests/aspect/security_test.affine @@ -1,11 +1,8 @@ // SPDX-License-Identifier: MPL-2.0 -// Ported via Harvard Engine mechanical processor +// Ported via Harvard Engine (Semantic pass) module security_test; -// TODO: Complete semantic implementation - -/* === ORIGINAL TYPESCRIPT CONTEXT === // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Jonathan D.A. Jewell /// @@ -27,7 +24,7 @@ import { assertEquals, assert, assertFalse } from "@std/assert"; /** * Verify a signature. Modified signatures should always fail. */ -function verifySignature( +fn verifySignature( signature: string, expectedSignature: string, ): boolean { @@ -39,14 +36,14 @@ function verifySignature( * Validate DKIM record for injection attacks. * Must start with v=DKIM1 and not contain injected headers. */ -function validateDKIMRecord(record: string): boolean { +fn validateDKIMRecord(record: string): boolean { // Must start with valid version if (!record.startsWith("v=DKIM1")) return false; - // Reject records that contain any CRLF (header injection vector) + // Reject records that contain unknown CRLF (header injection vector) if (record.includes("\r\n")) return false; - // Reject records that contain any standalone newlines + // Reject records that contain unknown standalone newlines if (record.includes("\r") || record.includes("\n")) return false; // Reject obvious injection attempts @@ -61,7 +58,7 @@ function validateDKIMRecord(record: string): boolean { * Verify DNS record authenticity. * In real scenario, would check DNSSEC. */ -function verifyDNSSecurity(_record: string, _signed: boolean): boolean { +fn verifyDNSSecurity(_record: string, _signed: boolean): boolean { // Property: Only signed records are trustworthy // For this test, we simulate that unsigned records return false return _signed; @@ -71,7 +68,7 @@ function verifyDNSSecurity(_record: string, _signed: boolean): boolean { * Sanitize email header values (prevent header injection). * Remove CRLF and null bytes. */ -function sanitizeHeaderValue(value: string): string { +fn sanitizeHeaderValue(value: string): string { return value .replace(/\r\n/g, " ") // CRLF → space .replace(/[\r\n\0]/g, "") // Remove remaining dangerous chars @@ -82,12 +79,12 @@ function sanitizeHeaderValue(value: string): string { * Detect Unicode lookalike characters (homoglyph attacks). * Simple detection: check for mixed scripts in domain. */ -function detectLookalikeDomain(domain: string): { isSuspicious: boolean; reasons: string[] } { +fn detectLookalikeDomain(domain: string): { isSuspicious: boolean; reasons: string[] } { const reasons: string[] = []; // Check for mixed Latin/Cyrillic (common phishing tactic) - const latinCount = (domain.match(/[a-z]/gi) || []).length; - const cyrillicCount = (domain.match(/[а-яё]/gi) || []).length; + let latinCount = (domain.match(/[a-z]/gi) || []).length; + let cyrillicCount = (domain.match(/[а-яё]/gi) || []).length; if (latinCount > 0 && cyrillicCount > 0) { reasons.push("mixed_latin_cyrillic"); @@ -115,31 +112,31 @@ function detectLookalikeDomain(domain: string): { isSuspicious: boolean; reasons /** * Check record size (prevent DoS via oversized records). */ -function isRecordSizeValid(record: string, maxSize: number = 65536): boolean { +fn isRecordSizeValid(record: string, maxSize: number = 65536): boolean { return record.length <= maxSize; } /** * Check for DKIM key size validity (prevent weak keys). */ -function isKeyStrengthValid(keySize: number): boolean { +fn isKeyStrengthValid(keySize: number): boolean { // RSA keys should be at least 1024 bits (minimum safe) // Recommended: 2048 bits or higher return keySize >= 1024; } Deno.test("Security - Signature Malleability Prevention", () => { - const originalSignature = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; + let originalSignature = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; - // Modification at any position should fail verification - const modifications = [ + // Modification at unknown position should fail verification + let modifications = [ "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b854", // Last char changed "d3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", // First char changed "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 ", // Trailing space ]; for (const modified of modifications) { - const result = verifySignature(modified, originalSignature); + let result = verifySignature(modified, originalSignature); assertFalse(result, `Modified signature should fail: ${modified}`); } @@ -148,12 +145,12 @@ Deno.test("Security - Signature Malleability Prevention", () => { }); Deno.test("Security - DKIM Record Injection Prevention", () => { - const validRecord = "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDwIRP"; + let validRecord = "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDwIRP"; assertEquals(validateDKIMRecord(validRecord), true); // Injection attempts should be rejected - const injectionAttempts = [ + let injectionAttempts = [ "v=DKIM1; k=rsa; p=key\r\nFrom: attacker@evil.com", "v=DKIM1; k=rsa; p=key", "v=DKIM1; k=rsa; p=key", @@ -161,13 +158,13 @@ Deno.test("Security - DKIM Record Injection Prevention", () => { ]; for (const injection of injectionAttempts) { - const result = validateDKIMRecord(injection); + let result = validateDKIMRecord(injection); assertFalse(result, `Injection attempt should be rejected: ${injection}`); } }); Deno.test("Security - DNS Spoofing Resilience", () => { - const record = "v=DKIM1; k=rsa; p=MIGfMA0"; + let record = "v=DKIM1; k=rsa; p=MIGfMA0"; // Unsigned records should not be trusted assertEquals(verifyDNSSecurity(record, false), false); @@ -177,14 +174,14 @@ Deno.test("Security - DNS Spoofing Resilience", () => { }); Deno.test("Security - Header Injection Prevention", () => { - const injectionAttempts = [ + let injectionAttempts = [ "From: user@example.com\r\nBcc: attacker@evil.com", "Normal Subject\r\nCc: evil@attacker.com", "Name\nFrom: attacker@evil.com", ]; for (const injection of injectionAttempts) { - const sanitized = sanitizeHeaderValue(injection); + let sanitized = sanitizeHeaderValue(injection); // Should not contain CRLF or LF assertFalse(sanitized.includes("\r\n"), `Should remove CRLF: ${injection}`); @@ -194,37 +191,37 @@ Deno.test("Security - Header Injection Prevention", () => { }); Deno.test("Security - Header Sanitization Preserves Content", () => { - const normalContent = "John Doe "; - const sanitized = sanitizeHeaderValue(normalContent); + let normalContent = "John Doe "; + let sanitized = sanitizeHeaderValue(normalContent); assertEquals(sanitized, normalContent); }); Deno.test("Security - Unicode Lookalike Detection", () => { // Mixed Latin/Cyrillic - const result = detectLookalikeDomain("google.com"); + let result = detectLookalikeDomain("google.com"); assertEquals(result.isSuspicious, false); // This would be suspicious (illustrative) - const suspiciousResult = detectLookalikeDomain("g0ogle.com"); + let suspiciousResult = detectLookalikeDomain("g0ogle.com"); // May or may not flag depending on detection heuristics }); Deno.test("Security - Record Size Validation", () => { - const normalRecord = "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDwIRP"; + let normalRecord = "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDwIRP"; assertEquals(isRecordSizeValid(normalRecord), true); // Oversized record (over 65536 limit): 11 + 65536 = 65547 bytes - const oversizedRecord = "v=DKIM1; p=" + "A".repeat(65536); + let oversizedRecord = "v=DKIM1; p=" + "A".repeat(65536); assertEquals(isRecordSizeValid(oversizedRecord), false); // Edge case: exactly at 65536 (the limit, should pass) - const atLimit = "x".repeat(65536); + let atLimit = "x".repeat(65536); assertEquals(isRecordSizeValid(atLimit), true); // Just over limit (should fail) - const overLimit = "x".repeat(65537); + let overLimit = "x".repeat(65537); assertEquals(isRecordSizeValid(overLimit), false); }); @@ -243,7 +240,7 @@ Deno.test("Security - Key Strength Validation", () => { }); Deno.test("Security - Multiple Injection Vectors", () => { - const vectors = [ + let vectors = [ "v=DKIM1\r\nX-Injected: attack", "v=DKIM1; k=rsa; p=key\r\nBcc: attacker@evil.com", "v=DKIM1", @@ -251,33 +248,32 @@ Deno.test("Security - Multiple Injection Vectors", () => { ]; for (const vector of vectors) { - const valid = validateDKIMRecord(vector); + let valid = validateDKIMRecord(vector); assertFalse(valid, `Should reject injection: ${vector}`); } }); Deno.test("Security - Null Byte Injection", () => { - const nullByteValue = "Subject\0From: attacker@evil.com"; - const sanitized = sanitizeHeaderValue(nullByteValue); + let nullByteValue = "Subject\0From: attacker@evil.com"; + let sanitized = sanitizeHeaderValue(nullByteValue); assertFalse(sanitized.includes("\0"), "Should remove null bytes"); }); Deno.test("Security - Case Sensitivity in Signature Verification", () => { - const sig1 = "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855"; - const sig2 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; + let sig1 = "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855"; + let sig2 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; // Hex strings should match case-insensitively in protocol // But byte-level verification requires exact match - const result = verifySignature(sig1, sig2); + let result = verifySignature(sig1, sig2); assertEquals(result, false, "Case differs, verification should fail"); }); Deno.test("Security - Oversized Record Handling Graceful", () => { - const hugeRecord = "v=DKIM1; p=" + "A".repeat(1000000); + let hugeRecord = "v=DKIM1; p=" + "A".repeat(1000000); // Should not crash, just return false assertEquals(isRecordSizeValid(hugeRecord), false); }); -==================================== */ diff --git a/tests/bench/verification_bench.affine b/tests/bench/verification_bench.affine index 3e51a11..7ed6c70 100644 --- a/tests/bench/verification_bench.affine +++ b/tests/bench/verification_bench.affine @@ -1,11 +1,8 @@ // SPDX-License-Identifier: MPL-2.0 -// Ported via Harvard Engine mechanical processor +// Ported via Harvard Engine (Semantic pass) module verification_bench; -// TODO: Complete semantic implementation - -/* === ORIGINAL TYPESCRIPT CONTEXT === // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Jonathan D.A. Jewell /// @@ -23,13 +20,13 @@ module verification_bench; /** * Parse DKIM TXT record. */ -function parseDKIMRecord(record: string): Record | null { +fn parseDKIMRecord(record: string): Record | null { if (!record.startsWith("v=DKIM1")) { return null; } const tags: Record = {}; - const tagMatches = record.matchAll(/([a-z])=([^;]*)/g); + let tagMatches = record.matchAll(/([a-z])=([^;]*)/g); for (const match of tagMatches) { tags[match[1]] = match[2].trim(); @@ -41,14 +38,14 @@ function parseDKIMRecord(record: string): Record | null { /** * Validate signature format (base64-ish). */ -function validateSignatureFormat(sig: string): boolean { +fn validateSignatureFormat(sig: string): boolean { return /^[A-Za-z0-9+/=]+$/.test(sig); } /** * Evaluate DMARC policy. */ -function evaluateDMARCPolicy( +fn evaluateDMARCPolicy( policy: string, alignmentResult: "pass" | "fail", ): string { @@ -62,7 +59,7 @@ function evaluateDMARCPolicy( /** * Canonicalize domain name. */ -function canonicalizeDomain(domain: string): string { +fn canonicalizeDomain(domain: string): string { return domain.toLowerCase(); } @@ -73,7 +70,7 @@ Deno.bench( group: "parsing", }, () => { - const record = "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDwIRP"; + let record = "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDwIRP"; parseDKIMRecord(record); }, ); @@ -84,7 +81,7 @@ Deno.bench( group: "parsing", }, () => { - const record = + let record = "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAADCBiQKBgQDwIRPUC3SBsEmGqZ9; h=sha256; c=relaxed/relaxed; t=1234567890; x=1234567900"; parseDKIMRecord(record); }, @@ -96,7 +93,7 @@ Deno.bench( group: "parsing", }, () => { - const record = + let record = "v=DKIM1; k=rsa; p=" + "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDwIRPUC3SBsEmGqZ9ZJW3Dkd/Tq4" + "oQcKKOUULSqS9YzKFwqS9YzKFwqS9YzKFwqS9YzKFwqS9YzKFwqS9YzKFwqS9Y5TmJ" + @@ -112,7 +109,7 @@ Deno.bench( group: "validation", }, () => { - const sig = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; + let sig = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; validateSignatureFormat(sig); }, ); @@ -123,7 +120,7 @@ Deno.bench( group: "validation", }, () => { - const sig = "not@valid#signature!"; + let sig = "not@valid#signature!"; validateSignatureFormat(sig); }, ); @@ -134,7 +131,7 @@ Deno.bench( group: "validation", }, () => { - const sig = + let sig = "TIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDwIRPUC3SBsEmGqZ9ZJW3Dkd/TQ=="; validateSignatureFormat(sig); }, @@ -208,10 +205,10 @@ Deno.bench( group: "pipeline", }, () => { - const record = "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDwIRP"; + let record = "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDwIRP"; parseDKIMRecord(record); - const sig = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; + let sig = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; validateSignatureFormat(sig); evaluateDMARCPolicy("reject", "pass"); @@ -224,7 +221,7 @@ Deno.bench( group: "batch", }, () => { - const records = [ + let records = [ "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDwIRP1", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDwIRP2", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDwIRP3", @@ -249,7 +246,7 @@ Deno.bench( group: "batch", }, () => { - const domains = [ + let domains = [ "EXAMPLE.COM", "Example.Com", "MAIL.EXAMPLE.COM", @@ -278,4 +275,3 @@ Deno.bench( }, ); -==================================== */ diff --git a/tests/e2e/verification_pipeline_test.affine b/tests/e2e/verification_pipeline_test.affine index 5723841..63e8dab 100644 --- a/tests/e2e/verification_pipeline_test.affine +++ b/tests/e2e/verification_pipeline_test.affine @@ -1,11 +1,8 @@ // SPDX-License-Identifier: MPL-2.0 -// Ported via Harvard Engine mechanical processor +// Ported via Harvard Engine (Semantic pass) module verification_pipeline_test; -// TODO: Complete semantic implementation - -/* === ORIGINAL TYPESCRIPT CONTEXT === // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Jonathan D.A. Jewell /// @@ -25,7 +22,7 @@ import { assertEquals, assertExists, assertStringIncludes } from "@std/assert"; /** * Simulated DNS response for a DKIM record. */ -interface DNSResponse { +struct DNSResponse { type: "DKIM" | "SPF" | "DMARC" | "ARC"; value: string | null; error?: string; @@ -34,7 +31,7 @@ interface DNSResponse { /** * Verification step result. */ -interface VerificationStepResult { +struct VerificationStepResult { step: string; success: boolean; data?: unknown; @@ -44,7 +41,7 @@ interface VerificationStepResult { /** * Complete verification pipeline result. */ -interface PipelineResult { +struct PipelineResult { status: "pass" | "fail" | "tempfail"; steps: VerificationStepResult[]; finalResult?: string; @@ -53,11 +50,11 @@ interface PipelineResult { /** * Simulate DNS record fetching (would be real DNS in production). */ -async function fetchDNSRecord( +async fn fetchDNSRecord( selector: string, domain: string, type: "DKIM" | "SPF" | "DMARC", -): Promise { +): DNSResponse { // Simulate network call await new Promise((resolve) => setTimeout(resolve, 10)); @@ -69,17 +66,17 @@ async function fetchDNSRecord( }; if (type === "DKIM") { - const key = `${selector}._domainkey.${domain}`; + let key = `${selector}._domainkey.${domain}`; return { type, value: mockRecords[key] || null }; } if (type === "SPF") { - const key = `v=spf1.${domain}`; + let key = `v=spf1.${domain}`; return { type, value: mockRecords[key] || null }; } if (type === "DMARC") { - const key = `_dmarc.${domain}`; + let key = `_dmarc.${domain}`; return { type, value: mockRecords[key] || null }; } @@ -89,15 +86,15 @@ async function fetchDNSRecord( /** * Parse DKIM record and extract public key. */ -function extractDKIMKey(record: string): string | null { - const match = record.match(/p=([^;]+)/); +fn extractDKIMKey(record: string): string | null { + let match = record.match(/p=([^;]+)/); return match ? match[1].trim() : null; } /** * Verify DKIM signature using extracted key. */ -function verifyDKIMSignature( +fn verifyDKIMSignature( signature: string, publicKey: string | null, ): boolean { @@ -111,19 +108,19 @@ function verifyDKIMSignature( /** * Extract DMARC policy from record. */ -function extractDMARCPolicy(record: string): string | null { - const match = record.match(/p=([^;]+)/); +fn extractDMARCPolicy(record: string): string | null { + let match = record.match(/p=([^;]+)/); return match ? match[1].trim() : null; } /** * Full DKIM verification pipeline. */ -async function verifyDKIMPipeline( +async fn verifyDKIMPipeline( signature: string, selector: string, domain: string, -): Promise { +): PipelineResult { const steps: VerificationStepResult[] = []; try { @@ -133,7 +130,7 @@ async function verifyDKIMPipeline( success: true, }); - const dnsResponse = await fetchDNSRecord(selector, domain, "DKIM"); + let dnsResponse = await fetchDNSRecord(selector, domain, "DKIM"); if (!dnsResponse.value) { steps.push({ @@ -156,7 +153,7 @@ async function verifyDKIMPipeline( }); // Step 3: Extract public key - const publicKey = extractDKIMKey(dnsResponse.value); + let publicKey = extractDKIMKey(dnsResponse.value); steps.push({ step: "extract_key", success: publicKey !== null, @@ -172,7 +169,7 @@ async function verifyDKIMPipeline( } // Step 4: Verify signature - const isValid = verifyDKIMSignature(signature, publicKey); + let isValid = verifyDKIMSignature(signature, publicKey); steps.push({ step: "verify_signature", success: isValid, @@ -200,15 +197,15 @@ async function verifyDKIMPipeline( /** * Full DMARC evaluation pipeline. */ -async function evaluateDMARCPipeline( +async fn evaluateDMARCPipeline( domain: string, alignmentResult: "pass" | "fail", -): Promise { +): PipelineResult { const steps: VerificationStepResult[] = []; try { // Step 1: Fetch DMARC record - const dnsResponse = await fetchDNSRecord("_dmarc", domain, "DMARC"); + let dnsResponse = await fetchDNSRecord("_dmarc", domain, "DMARC"); if (!dnsResponse.value) { steps.push({ @@ -229,7 +226,7 @@ async function evaluateDMARCPipeline( }); // Step 2: Extract policy - const policy = extractDMARCPolicy(dnsResponse.value); + let policy = extractDMARCPolicy(dnsResponse.value); steps.push({ step: "extract_policy", success: policy !== null, @@ -284,7 +281,7 @@ async function evaluateDMARCPipeline( } Deno.test("E2E - DKIM Verification Success Pipeline", async () => { - const result = await verifyDKIMPipeline( + let result = await verifyDKIMPipeline( "validSignature123", "default", "valid.com", @@ -301,7 +298,7 @@ Deno.test("E2E - DKIM Verification Success Pipeline", async () => { }); Deno.test("E2E - DKIM Verification Missing Record", async () => { - const result = await verifyDKIMPipeline( + let result = await verifyDKIMPipeline( "signature", "nonexistent", "missing.com", @@ -311,13 +308,13 @@ Deno.test("E2E - DKIM Verification Missing Record", async () => { assertEquals(result.finalResult, "PERMFAIL"); // Should have failed at DNS record step - const dnsStep = result.steps.find((s) => s.step === "parse_dkim_record"); + let dnsStep = result.steps.find((s) => s.step === "parse_dkim_record"); assertExists(dnsStep); assertEquals(dnsStep!.success, false); }); Deno.test("E2E - DKIM Verification Empty Signature", async () => { - const result = await verifyDKIMPipeline( + let result = await verifyDKIMPipeline( "", "default", "valid.com", @@ -328,29 +325,29 @@ Deno.test("E2E - DKIM Verification Empty Signature", async () => { }); Deno.test("E2E - DMARC Evaluation Pass with None Policy", async () => { - const result = await evaluateDMARCPipeline("valid.com", "pass"); + let result = await evaluateDMARCPipeline("valid.com", "pass"); assertEquals(result.status, "pass"); assertExists(result.finalResult); }); Deno.test("E2E - DMARC Evaluation Reject Policy Applied", async () => { - const result = await evaluateDMARCPipeline("valid.com", "fail"); + let result = await evaluateDMARCPipeline("valid.com", "fail"); assertEquals(result.steps.length > 0, true); - const policyStep = result.steps.find((s) => s.step === "extract_policy"); + let policyStep = result.steps.find((s) => s.step === "extract_policy"); assertExists(policyStep); }); Deno.test("E2E - DMARC Missing Record", async () => { - const result = await evaluateDMARCPipeline("nodmarc.com", "pass"); + let result = await evaluateDMARCPipeline("nodmarc.com", "pass"); assertEquals(result.status, "pass"); assertEquals(result.finalResult, "none"); }); Deno.test("E2E - Verification Pipeline Error Handling", async () => { - const result = await verifyDKIMPipeline( + let result = await verifyDKIMPipeline( "validSignature", "default", "valid.com", @@ -362,13 +359,13 @@ Deno.test("E2E - Verification Pipeline Error Handling", async () => { }); Deno.test("E2E - Complete DKIM Flow Steps", async () => { - const result = await verifyDKIMPipeline( + let result = await verifyDKIMPipeline( "validSig", "default", "valid.com", ); - const expectedSteps = [ + let expectedSteps = [ "fetch_dns_record", "parse_dkim_record", "extract_key", @@ -376,9 +373,8 @@ Deno.test("E2E - Complete DKIM Flow Steps", async () => { ]; for (const expectedStep of expectedSteps) { - const hasStep = result.steps.some((s) => s.step === expectedStep); + let hasStep = result.steps.some((s) => s.step === expectedStep); assertEquals(hasStep, true, `Should have step: ${expectedStep}`); } }); -==================================== */ diff --git a/tests/property/verification_properties_test.affine b/tests/property/verification_properties_test.affine index 8729ea8..035a95c 100644 --- a/tests/property/verification_properties_test.affine +++ b/tests/property/verification_properties_test.affine @@ -1,11 +1,8 @@ // SPDX-License-Identifier: MPL-2.0 -// Ported via Harvard Engine mechanical processor +// Ported via Harvard Engine (Semantic pass) module verification_properties_test; -// TODO: Complete semantic implementation - -/* === ORIGINAL TYPESCRIPT CONTEXT === // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Jonathan D.A. Jewell /// @@ -25,7 +22,7 @@ import { assertEquals, assert } from "@std/assert"; /** * Simulate a signature verification result. */ -interface VerificationResult { +struct VerificationResult { isValid: boolean; error?: string; } @@ -34,7 +31,7 @@ interface VerificationResult { * Verify a DKIM signature deterministically. * Property: Given the same signature, always returns same result. */ -function verifySignature( +fn verifySignature( signature: string, publicKey: string, _bodyHash: string, @@ -51,7 +48,7 @@ function verifySignature( } // Deterministic check: signature and key must be non-empty and valid base64-ish - const validBase64 = /^[A-Za-z0-9+/=]+$/.test(signature) && /^[A-Za-z0-9+/=]+$/.test(publicKey); + let validBase64 = /^[A-Za-z0-9+/=]+$/.test(signature) && /^[A-Za-z0-9+/=]+$/.test(publicKey); return { isValid: validBase64, @@ -62,7 +59,7 @@ function verifySignature( * Normalize domain name to lowercase for DNS lookup. * Property: Always produces lowercase ASCII. */ -function normalizeDomain(domain: string): string { +fn normalizeDomain(domain: string): string { return domain.toLowerCase(); } @@ -70,16 +67,16 @@ function normalizeDomain(domain: string): string { * Form a selector/domain DNS label. * Property: Always produces a valid DNS label. */ -function formDNSLabel(selector: string, domain: string): string { - const normalized = normalizeDomain(domain); +fn formDNSLabel(selector: string, domain: string): string { + let normalized = normalizeDomain(domain); return `${selector}._domainkey.${normalized}`; } /** * Validate DNS label format: max 63 chars per label, alphanumeric + hyphen + underscore. */ -function isValidDNSLabel(label: string): boolean { - const parts = label.split("."); +fn isValidDNSLabel(label: string): boolean { + let parts = label.split("."); for (const part of parts) { if (part.length > 63) return false; if (!/^[a-z0-9\-_]+$/i.test(part)) return false; @@ -89,14 +86,14 @@ function isValidDNSLabel(label: string): boolean { } Deno.test("Properties - Signature Verification Determinism", () => { - const signature = "validSignature123456789"; - const publicKey = "validKey987654321"; - const bodyHash = "hash123"; + let signature = "validSignature123456789"; + let publicKey = "validKey987654321"; + let bodyHash = "hash123"; // Verify same input produces same output (determinism) - const result1 = verifySignature(signature, publicKey, bodyHash); - const result2 = verifySignature(signature, publicKey, bodyHash); - const result3 = verifySignature(signature, publicKey, bodyHash); + let result1 = verifySignature(signature, publicKey, bodyHash); + let result2 = verifySignature(signature, publicKey, bodyHash); + let result3 = verifySignature(signature, publicKey, bodyHash); assertEquals(result1.isValid, result2.isValid); assertEquals(result2.isValid, result3.isValid); @@ -104,38 +101,38 @@ Deno.test("Properties - Signature Verification Determinism", () => { }); Deno.test("Properties - Invalid Signatures Always Fail", () => { - const publicKey = "validKey123456"; + let publicKey = "validKey123456"; // Empty signature always fails - const emptyResult = verifySignature("", publicKey, "hash"); + let emptyResult = verifySignature("", publicKey, "hash"); assertEquals(emptyResult.isValid, false); // Empty key always fails - const emptyKeyResult = verifySignature("signature", "", "hash"); + let emptyKeyResult = verifySignature("signature", "", "hash"); assertEquals(emptyKeyResult.isValid, false); // Property: No false positives (invalid never becomes valid) - const invalidSignatures = [ + let invalidSignatures = [ "", "@@@invalid", "", ]; for (const sig of invalidSignatures) { - const result = verifySignature(sig, publicKey, "hash"); + let result = verifySignature(sig, publicKey, "hash"); assertEquals(result.isValid, false, `Signature "${sig}" should always fail`); } }); Deno.test("Properties - Domain Normalization Consistency", () => { - const domains = [ + let domains = [ "EXAMPLE.COM", "Example.Com", "example.com", "ExAmPlE.cOm", ]; - const normalized = domains.map(normalizeDomain); + let normalized = domains.map(normalizeDomain); // All should normalize to the same value for (const norm of normalized) { @@ -144,11 +141,11 @@ Deno.test("Properties - Domain Normalization Consistency", () => { }); Deno.test("Properties - Domain Normalization Idempotent", () => { - const domain = "EXAMPLE.COM"; + let domain = "EXAMPLE.COM"; - const once = normalizeDomain(domain); - const twice = normalizeDomain(once); - const thrice = normalizeDomain(twice); + let once = normalizeDomain(domain); + let twice = normalizeDomain(once); + let thrice = normalizeDomain(twice); // Normalizing multiple times should produce same result assertEquals(once, twice); @@ -156,14 +153,14 @@ Deno.test("Properties - Domain Normalization Idempotent", () => { }); Deno.test("Properties - Selector Domain Forms Valid DNS Label", () => { - const validCases = [ + let validCases = [ { selector: "default", domain: "example.com" }, { selector: "mail1", domain: "test.example.com" }, { selector: "selector-2", domain: "sub.domain.example.com" }, ]; for (const { selector, domain } of validCases) { - const label = formDNSLabel(selector, domain); + let label = formDNSLabel(selector, domain); assert( isValidDNSLabel(label), `Label "${label}" should be valid DNS format`, @@ -173,11 +170,11 @@ Deno.test("Properties - Selector Domain Forms Valid DNS Label", () => { Deno.test("Properties - DNS Label Format Invariant", () => { // Property: DNS labels don't exceed 63 characters per component - const selector = "validSelector"; - const domain = "example.com"; + let selector = "validSelector"; + let domain = "example.com"; - const label = formDNSLabel(selector, domain); - const parts = label.split("."); + let label = formDNSLabel(selector, domain); + let parts = label.split("."); for (const part of parts) { assert( @@ -189,7 +186,7 @@ Deno.test("Properties - DNS Label Format Invariant", () => { Deno.test("Properties - Mixed Case Domain Normalization", () => { // Property: Mixed case domains always normalize identically - const testCases = [ + let testCases = [ ["EXAMPLE.COM", "example.com"], ["Example.Com", "example.com"], ["ExAmPlE.cOm", "example.com"], @@ -202,41 +199,41 @@ Deno.test("Properties - Mixed Case Domain Normalization", () => { }); Deno.test("Properties - Signature Verification Edge Cases", () => { - const publicKey = "validPublicKey"; + let publicKey = "validPublicKey"; // Property: Signatures with only whitespace are invalid - const whitespaceResult = verifySignature(" ", publicKey, "hash"); + let whitespaceResult = verifySignature(" ", publicKey, "hash"); assertEquals(whitespaceResult.isValid, false); // Property: Signatures with binary characters (not base64) are invalid - const binaryResult = verifySignature("sig\x00\x01\x02", publicKey, "hash"); + let binaryResult = verifySignature("sig\x00\x01\x02", publicKey, "hash"); assertEquals(binaryResult.isValid, false); }); Deno.test("Properties - Selector Domain Combination", () => { // Property: Different selectors + same domain always produce distinct labels - const domain = "example.com"; - const selector1 = formDNSLabel("selector1", domain); - const selector2 = formDNSLabel("selector2", domain); + let domain = "example.com"; + let selector1 = formDNSLabel("selector1", domain); + let selector2 = formDNSLabel("selector2", domain); assertEquals(selector1 !== selector2, true); // Property: Same selector + different domains produce distinct labels - const domain1 = formDNSLabel("default", "example.com"); - const domain2 = formDNSLabel("default", "test.com"); + let domain1 = formDNSLabel("default", "example.com"); + let domain2 = formDNSLabel("default", "test.com"); assertEquals(domain1 !== domain2, true); }); Deno.test("Properties - Consistency Under Repetition", () => { // Property: Running verification multiple times on same input yields same result - const testData = { + let testData = { signature: "testSignature123", key: "testKey456", hash: "testHash789", }; - const results = []; + let results = []; for (let i = 0; i < 5; i++) { results.push(verifySignature(testData.signature, testData.key, testData.hash)); } @@ -248,4 +245,3 @@ Deno.test("Properties - Consistency Under Repetition", () => { } }); -==================================== */ diff --git a/tests/unit/crypto_types_test.affine b/tests/unit/crypto_types_test.affine index f13f220..1963514 100644 --- a/tests/unit/crypto_types_test.affine +++ b/tests/unit/crypto_types_test.affine @@ -1,11 +1,8 @@ // SPDX-License-Identifier: MPL-2.0 -// Ported via Harvard Engine mechanical processor +// Ported via Harvard Engine (Semantic pass) module crypto_types_test; -// TODO: Complete semantic implementation - -/* === ORIGINAL TYPESCRIPT CONTEXT === // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Jonathan D.A. Jewell /// @@ -20,12 +17,12 @@ module crypto_types_test; import { assertEquals, assertMatch, assertThrows } from "@std/assert"; // Crypto type contract validators -interface SignatureAlgorithm { +struct SignatureAlgorithm { name: string; hashAlgorithm: string; } -interface DKIMKeyRecord { +struct DKIMKeyRecord { version: string; keyType: string; publicKey: string; @@ -33,7 +30,7 @@ interface DKIMKeyRecord { serviceTypes: string[]; } -interface DKIMSignature { +struct DKIMSignature { version: "1.0" | "1.1"; algorithm: string; bodyCanonicalization: string; @@ -53,15 +50,15 @@ interface DKIMSignature { * Validate signature algorithm name is recognized. * Valid: "rsa-sha1", "rsa-sha256", "ed25519-sha256", etc. */ -function validateAlgorithmName(name: string): boolean { - const validAlgorithms = /^(rsa|ed25519|ecdsa)-(sha1|sha256|sha512)$/i; +fn validateAlgorithmName(name: string): boolean { + let validAlgorithms = /^(rsa|ed25519|ecdsa)-(sha1|sha256|sha512)$/i; return validAlgorithms.test(name); } /** * Validate key ID format: non-empty, ASCII printable. */ -function validateKeyId(keyId: string): boolean { +fn validateKeyId(keyId: string): boolean { if (keyId.length === 0) return false; // Allow alphanumeric, hyphen, underscore return /^[a-z0-9\-_]+$/i.test(keyId); @@ -70,8 +67,8 @@ function validateKeyId(keyId: string): boolean { /** * Validate hash value: hex string, minimum length for SHA256 (64 chars). */ -function validateHashValue(hash: string, algorithmName: string = "sha256"): boolean { - const hexPattern = /^[a-f0-9]+$/i; +fn validateHashValue(hash: string, algorithmName: string = "sha256"): boolean { + let hexPattern = /^[a-f0-9]+$/i; if (!hexPattern.test(hash)) return false; // SHA1: 40 chars, SHA256: 64 chars, SHA512: 128 chars @@ -81,15 +78,15 @@ function validateHashValue(hash: string, algorithmName: string = "sha256"): bool "sha512": 128, }; - const expectedLength = expectedLengths[algorithmName.toLowerCase()] || 64; + let expectedLength = expectedLengths[algorithmName.toLowerCase()] || 64; return hash.length === expectedLength; } /** * Validate DKIM signature has all required fields. */ -function validateDKIMSignature(sig: DKIMSignature): boolean { - const requiredFields = ["version", "algorithm", "bodyCanonicalization", +fn validateDKIMSignature(sig: DKIMSignature): boolean { + let requiredFields = ["version", "algorithm", "bodyCanonicalization", "headerCanonicalization", "signedHeaders", "signature", "bodyHash", "domain"]; for (const field of requiredFields) { @@ -102,7 +99,7 @@ function validateDKIMSignature(sig: DKIMSignature): boolean { /** * Validate DMARC policy value: "none", "quarantine", "reject" only. */ -function validateDMARCPolicy(policy: string): boolean { +fn validateDMARCPolicy(policy: string): boolean { return ["none", "quarantine", "reject"].includes(policy.toLowerCase()); } @@ -165,12 +162,12 @@ Deno.test("Crypto Types - DKIM Signature Fields", () => { assertEquals(validateDKIMSignature(validSig), true); // Missing required field - const incompleteSig = { ...validSig }; - delete (incompleteSig as any).domain; + let incompleteSig = { ...validSig }; + delete (incompleteSig as unknown).domain; assertEquals(validateDKIMSignature(incompleteSig), false); // Empty signed headers - const noHeadersSig = { ...validSig, signedHeaders: [] }; + let noHeadersSig = { ...validSig, signedHeaders: [] }; assertEquals(validateDKIMSignature(noHeadersSig), false); }); @@ -186,7 +183,7 @@ Deno.test("Crypto Types - DMARC Policy Values", () => { }); Deno.test("Crypto Types - Signature Algorithm Enum", () => { - const algorithms = [ + let algorithms = [ { name: "rsa-sha256", hashAlgorithm: "sha256" }, { name: "rsa-sha1", hashAlgorithm: "sha1" }, { name: "ed25519-sha256", hashAlgorithm: "sha256" }, @@ -197,4 +194,3 @@ Deno.test("Crypto Types - Signature Algorithm Enum", () => { } }); -==================================== */ diff --git a/tests/unit/dns_record_test.affine b/tests/unit/dns_record_test.affine index d4f0ff5..52ac602 100644 --- a/tests/unit/dns_record_test.affine +++ b/tests/unit/dns_record_test.affine @@ -1,11 +1,8 @@ // SPDX-License-Identifier: MPL-2.0 -// Ported via Harvard Engine mechanical processor +// Ported via Harvard Engine (Semantic pass) module dns_record_test; -// TODO: Complete semantic implementation - -/* === ORIGINAL TYPESCRIPT CONTEXT === // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Jonathan D.A. Jewell /// @@ -19,7 +16,7 @@ module dns_record_test; import { assertEquals, assertMatch } from "@std/assert"; -interface DNSRecord { +struct DNSRecord { type: "DKIM" | "SPF" | "DMARC"; value: string; tags?: Record; @@ -28,13 +25,13 @@ interface DNSRecord { /** * Parse DKIM TXT record. Must start with "v=DKIM1". */ -function parseDKIMRecord(record: string): DNSRecord | null { +fn parseDKIMRecord(record: string): DNSRecord | null { if (!record.startsWith("v=DKIM1")) { return null; } const tags: Record = {}; - const tagMatches = record.matchAll(/([a-z])=([^;]*)/g); + let tagMatches = record.matchAll(/([a-z])=([^;]*)/g); for (const match of tagMatches) { tags[match[1]] = match[2].trim(); @@ -50,7 +47,7 @@ function parseDKIMRecord(record: string): DNSRecord | null { /** * Parse SPF record. Must start with "v=spf1". */ -function parseSPFRecord(record: string): DNSRecord | null { +fn parseSPFRecord(record: string): DNSRecord | null { if (!record.startsWith("v=spf1")) { return null; } @@ -64,13 +61,13 @@ function parseSPFRecord(record: string): DNSRecord | null { /** * Parse DMARC record. Must start with "v=DMARC1". */ -function parseDMARCRecord(record: string): DNSRecord | null { +fn parseDMARCRecord(record: string): DNSRecord | null { if (!record.startsWith("v=DMARC1")) { return null; } const tags: Record = {}; - const tagMatches = record.matchAll(/([a-z]+)=([^;]*)/g); + let tagMatches = record.matchAll(/([a-z]+)=([^;]*)/g); for (const match of tagMatches) { tags[match[1]] = match[2].trim(); @@ -87,7 +84,7 @@ function parseDMARCRecord(record: string): DNSRecord | null { * Check if record format is valid for forward compatibility. * Unknown tags should be ignored, not cause parsing to fail. */ -function isForwardCompatible(record: string, type: "DKIM" | "DMARC"): boolean { +fn isForwardCompatible(record: string, type: "DKIM" | "DMARC"): boolean { // Both DKIM and DMARC allow unknown tags (forward compatibility) // Only the version tag is mandatory if (type === "DKIM") { @@ -100,8 +97,8 @@ function isForwardCompatible(record: string, type: "DKIM" | "DMARC"): boolean { } Deno.test("DNS Records - DKIM Record Parsing", () => { - const validDKIM = "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDwIRP/UC3SBsEmGqZ9ZJW3/"; - const parsed = parseDKIMRecord(validDKIM); + let validDKIM = "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDwIRP/UC3SBsEmGqZ9ZJW3/"; + let parsed = parseDKIMRecord(validDKIM); assertEquals(parsed !== null, true); assertEquals(parsed?.type, "DKIM"); @@ -110,15 +107,15 @@ Deno.test("DNS Records - DKIM Record Parsing", () => { }); Deno.test("DNS Records - DKIM Invalid Prefix", () => { - const invalidDKIM = "v=DKIM2; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDwIRP/UC3SBsEmGqZ9ZJW3/"; - const parsed = parseDKIMRecord(invalidDKIM); + let invalidDKIM = "v=DKIM2; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDwIRP/UC3SBsEmGqZ9ZJW3/"; + let parsed = parseDKIMRecord(invalidDKIM); assertEquals(parsed, null); }); Deno.test("DNS Records - SPF Record Parsing", () => { - const validSPF = "v=spf1 ip4:192.0.2.0/24 -all"; - const parsed = parseSPFRecord(validSPF); + let validSPF = "v=spf1 ip4:192.0.2.0/24 -all"; + let parsed = parseSPFRecord(validSPF); assertEquals(parsed !== null, true); assertEquals(parsed?.type, "SPF"); @@ -126,15 +123,15 @@ Deno.test("DNS Records - SPF Record Parsing", () => { }); Deno.test("DNS Records - SPF Invalid Prefix", () => { - const invalidSPF = "v=spf2 ip4:192.0.2.0/24 -all"; - const parsed = parseSPFRecord(invalidSPF); + let invalidSPF = "v=spf2 ip4:192.0.2.0/24 -all"; + let parsed = parseSPFRecord(invalidSPF); assertEquals(parsed, null); }); Deno.test("DNS Records - DMARC Record Parsing", () => { - const validDMARC = "v=DMARC1; p=reject; rua=mailto:admin@example.com"; - const parsed = parseDMARCRecord(validDMARC); + let validDMARC = "v=DMARC1; p=reject; rua=mailto:admin@example.com"; + let parsed = parseDMARCRecord(validDMARC); assertEquals(parsed !== null, true); assertEquals(parsed?.type, "DMARC"); @@ -143,8 +140,8 @@ Deno.test("DNS Records - DMARC Record Parsing", () => { }); Deno.test("DNS Records - DMARC Tag Parsing", () => { - const dmarc = "v=DMARC1; p=quarantine; rua=mailto:admin@example.com; ruf=mailto:forensics@example.com; fo=1"; - const parsed = parseDMARCRecord(dmarc); + let dmarc = "v=DMARC1; p=quarantine; rua=mailto:admin@example.com; ruf=mailto:forensics@example.com; fo=1"; + let parsed = parseDMARCRecord(dmarc); assertEquals(parsed?.tags?.p, "quarantine"); assertEquals(parsed?.tags?.rua, "mailto:admin@example.com"); @@ -153,33 +150,33 @@ Deno.test("DNS Records - DMARC Tag Parsing", () => { Deno.test("DNS Records - Forward Compatibility DKIM", () => { // Record with unknown future tag should still parse - const futureDKIM = "v=DKIM1; k=rsa; x-future-tag=value; p=MIGfMA0GCS..."; + let futureDKIM = "v=DKIM1; k=rsa; x-future-tag=value; p=MIGfMA0GCS..."; assertEquals(isForwardCompatible(futureDKIM, "DKIM"), true); - const parsed = parseDKIMRecord(futureDKIM); + let parsed = parseDKIMRecord(futureDKIM); assertEquals(parsed !== null, true); // Unknown tag is ignored but doesn't break parsing }); Deno.test("DNS Records - Forward Compatibility DMARC", () => { // Record with unknown future tag should still parse - const futureDMARC = "v=DMARC1; p=none; x-future-tag=value; rua=mailto:admin@example.com"; + let futureDMARC = "v=DMARC1; p=none; x-future-tag=value; rua=mailto:admin@example.com"; assertEquals(isForwardCompatible(futureDMARC, "DMARC"), true); - const parsed = parseDMARCRecord(futureDMARC); + let parsed = parseDMARCRecord(futureDMARC); assertEquals(parsed !== null, true); }); Deno.test("DNS Records - DKIM Missing Version", () => { - const noVersion = "k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDwIRP/UC3SBsEmGqZ9ZJW3/"; - const parsed = parseDKIMRecord(noVersion); + let noVersion = "k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDwIRP/UC3SBsEmGqZ9ZJW3/"; + let parsed = parseDKIMRecord(noVersion); assertEquals(parsed, null); }); Deno.test("DNS Records - DMARC Missing Version", () => { - const noVersion = "p=reject; rua=mailto:admin@example.com"; - const parsed = parseDMARCRecord(noVersion); + let noVersion = "p=reject; rua=mailto:admin@example.com"; + let parsed = parseDMARCRecord(noVersion); assertEquals(parsed, null); }); @@ -191,10 +188,9 @@ Deno.test("DNS Records - Empty Record", () => { }); Deno.test("DNS Records - Whitespace Handling", () => { - const dkimWithWhitespace = "v=DKIM1 ; k=rsa ; p=test"; - const parsed = parseDKIMRecord(dkimWithWhitespace); + let dkimWithWhitespace = "v=DKIM1 ; k=rsa ; p=test"; + let parsed = parseDKIMRecord(dkimWithWhitespace); // Should handle gracefully (our regex allows whitespace) assertEquals(parsed !== null, true); }); -==================================== */