Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 8 additions & 12 deletions scripts/build.affine
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
// SPDX-License-Identifier: MPL-2.0
// Ported via Harvard Engine mechanical processor
// Ported via Harvard Engine (Semantic pass)

module build;

// TODO: Complete semantic implementation

/* === ORIGINAL TYPESCRIPT CONTEXT ===
// SPDX-License-Identifier: MPL-2.0
// Build script for DoubleTrack Browser extension
// Uses Deno for file operations

import { copy, ensureDir } from "https://deno.land/std@0.220.1/fs/mod.ts";
import { join } from "https://deno.land/std@0.220.1/path/mod.ts";

const SRC_DIR = "src";
const DIST_DIR = "dist";
const RUST_PKG_DIR = "rust_core/pkg";
let SRC_DIR = "src";
let DIST_DIR = "dist";
let RUST_PKG_DIR = "rust_core/pkg";

async function build() {
async fn build() {
console.log("📦 Building DoubleTrack Browser extension...");

// Create dist directory
Expand All @@ -31,7 +28,7 @@ async function build() {
console.log(" ✓ Copied manifest.json");

// Copy HTML files
const htmlFiles = [
let htmlFiles = [
{ src: "popup/popup.html", dest: "popup.html" },
{ src: "options/options.html", dest: "options.html" },
{ src: "dashboard/dashboard.html", dest: "dashboard.html" },
Expand All @@ -46,7 +43,7 @@ async function build() {
}

// Copy CSS files
const cssFiles = [
let cssFiles = [
{ src: "popup/popup.css", dest: "popup.css" },
{ src: "options/options.css", dest: "options.css" },
{ src: "dashboard/dashboard.css", dest: "dashboard.css" },
Expand All @@ -61,7 +58,7 @@ async function build() {
}

// Copy compiled ReScript JS files
const jsFiles = [
let jsFiles = [
{ src: "background/Background.res.js", dest: "background.js" },
{ src: "content/Content.res.js", dest: "content.js" },
{ src: "popup/Popup.res.js", dest: "popup.js" },
Expand Down Expand Up @@ -105,4 +102,3 @@ if (import.meta.main) {
await build();
}

==================================== */
6 changes: 1 addition & 5 deletions tests/affine/driver.affine
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
// SPDX-License-Identifier: MPL-2.0
// Ported via Harvard Engine mechanical processor
// Ported via Harvard Engine (Semantic pass)

module driver;

// TODO: Complete semantic implementation

/* === ORIGINAL TYPESCRIPT CONTEXT ===
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
//
Expand All @@ -24,4 +21,3 @@ import { runAll } from "@hyperpolymath/affinescript-deno-test";

await runAll(new URL("./", import.meta.url).pathname);

==================================== */
58 changes: 27 additions & 31 deletions tests/aspect/security_test.affine
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
// 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
// Security aspect tests for DoubleTrack browser extension

import { assertEquals, assertStringIncludes } from "jsr:@std/assert";

Deno.test("Security: XSS prevention in URL display", () => {
const sanitizeUrl = (url: string): string => {
let sanitizeUrl = (url: string): string => {
// In real implementation, this would escape HTML special chars
return url.replace(/[<>"]/g, (char) => {
const escapeMap: Record<string, string> = {
Expand All @@ -24,15 +21,15 @@ Deno.test("Security: XSS prevention in URL display", () => {
});
};

const maliciousUrl = '<script>alert("xss")</script>';
const sanitized = sanitizeUrl(maliciousUrl);
let maliciousUrl = '<script>alert("xss")</script>';
let sanitized = sanitizeUrl(maliciousUrl);

assertEquals(sanitized.includes("<script>"), false);
assertEquals(sanitized.includes("&lt;script&gt;"), true);
});

Deno.test("Security: content isolation", () => {
interface IsolatedContent {
struct IsolatedContent {
isSandboxed: boolean;
allowedOrigins: string[];
}
Expand All @@ -50,7 +47,7 @@ Deno.test("Security: content isolation", () => {
});

Deno.test("Security: HTTPS enforcement", () => {
const isHttpsUrl = (url: string): boolean => {
let isHttpsUrl = (url: string): boolean => {
return url.startsWith("https://");
};

Expand All @@ -60,29 +57,29 @@ Deno.test("Security: HTTPS enforcement", () => {
});

Deno.test("Security: message validation", () => {
interface ValidatedMessage {
struct ValidatedMessage {
type: string;
source: string;
timestamp: number;
}

const validateMessage = (msg: unknown): msg is ValidatedMessage => {
let validateMessage = (msg: unknown): msg is ValidatedMessage => {
if (typeof msg !== "object" || msg === null) return false;
const m = msg as Record<string, unknown>;
let m = msg as Record<string, unknown>;
return (
typeof m.type === "string" &&
typeof m.source === "string" &&
typeof m.timestamp === "number"
);
};

const validMsg = {
let validMsg = {
type: "PROFILE_UPDATE",
source: "background",
timestamp: Date.now(),
};

const invalidMsg = {
let invalidMsg = {
type: "PROFILE_UPDATE",
source: "background",
// Missing timestamp
Expand All @@ -93,19 +90,19 @@ Deno.test("Security: message validation", () => {
});

Deno.test("Security: origin verification", () => {
const verifyOrigin = (
let verifyOrigin = (
origin: string,
allowedOrigins: string[]
): boolean => {
try {
const url = new URL(origin);
let url = new URL(origin);
return allowedOrigins.includes(url.origin);
} catch {
return false;
}
};

const allowed = ["https://example.com", "https://test.com"];
let allowed = ["https://example.com", "https://test.com"];

assertEquals(
verifyOrigin("https://example.com/page", allowed),
Expand All @@ -118,15 +115,15 @@ Deno.test("Security: origin verification", () => {
});

Deno.test("Security: no plain HTTP for sensitive operations", () => {
const isSensitiveOperation = (operation: string): boolean => {
let isSensitiveOperation = (operation: string): boolean => {
return [
"PROFILE_SAVE",
"PROFILE_LOAD",
"SETTINGS_UPDATE",
].includes(operation);
};

const performSecureRequest = (
let performSecureRequest = (
operation: string,
protocol: string
): boolean => {
Expand All @@ -142,8 +139,8 @@ Deno.test("Security: no plain HTTP for sensitive operations", () => {
});

Deno.test("Security: no sensitive data in logs", () => {
const containsSensitiveData = (logMessage: string): boolean => {
const sensitivePatterns = [
let containsSensitiveData = (logMessage: string): boolean => {
let sensitivePatterns = [
/password/i,
/token/i,
/secret/i,
Expand All @@ -163,7 +160,7 @@ Deno.test("Security: no sensitive data in logs", () => {
});

Deno.test("Security: CSP headers enforcement", () => {
interface ContentSecurityPolicy {
struct ContentSecurityPolicy {
scriptSrc: string[];
styleSrc: string[];
imgSrc: string[];
Expand All @@ -180,18 +177,18 @@ Deno.test("Security: CSP headers enforcement", () => {
});

Deno.test("Security: timestamp validation", () => {
const isValidTimestamp = (ts: number): boolean => {
let isValidTimestamp = (ts: number): boolean => {
// Timestamp should be within last/next 5 years
const now = Date.now();
const fiveYears = 5 * 365 * 24 * 60 * 60 * 1000;
let now = Date.now();
let fiveYears = 5 * 365 * 24 * 60 * 60 * 1000;

return Math.abs(now - ts) < fiveYears;
};

const recentTs = Date.now();
const futureTs = Date.now() + 365 * 24 * 60 * 60 * 1000; // 1 year in future
const pastTs = Date.now() - 365 * 24 * 60 * 60 * 1000; // 1 year in past
const wayOldTs = 1000; // Year 1970
let recentTs = Date.now();
let futureTs = Date.now() + 365 * 24 * 60 * 60 * 1000; // 1 year in future
let pastTs = Date.now() - 365 * 24 * 60 * 60 * 1000; // 1 year in past
let wayOldTs = 1000; // Year 1970

assertEquals(isValidTimestamp(recentTs), true);
assertEquals(isValidTimestamp(futureTs), true);
Expand All @@ -200,7 +197,7 @@ Deno.test("Security: timestamp validation", () => {
});

Deno.test("Security: permission boundaries", () => {
interface Permissions {
struct Permissions {
storage: boolean;
tabs: boolean;
webRequest: boolean;
Expand All @@ -220,4 +217,3 @@ Deno.test("Security: permission boundaries", () => {
assertEquals(extensionPerms.webRequest, false);
});

==================================== */
16 changes: 6 additions & 10 deletions tests/e2e/extension_lifecycle_test.affine
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
// SPDX-License-Identifier: MPL-2.0
// Ported via Harvard Engine mechanical processor
// Ported via Harvard Engine (Semantic pass)

module extension_lifecycle_test;

// TODO: Complete semantic implementation

/* === ORIGINAL TYPESCRIPT CONTEXT ===
// SPDX-License-Identifier: MPL-2.0
// End-to-end tests for DoubleTrack extension lifecycle

import { assertEquals, assertExists } from "jsr:@std/assert";

interface ExtensionState {
struct ExtensionState {
isInitialized: boolean;
profile?: { id: string; name: string };
activities: Array<{ url: string; timestamp: number }>;
Expand Down Expand Up @@ -79,7 +76,7 @@ Deno.test("Extension lifecycle: activity accumulation", () => {
};

// Simulate adding multiple activities
const urls = [
let urls = [
"https://example.com",
"https://google.com",
"https://github.com",
Expand Down Expand Up @@ -113,7 +110,7 @@ Deno.test("Extension lifecycle: pause and resume", () => {
});

Deno.test("Extension lifecycle: configuration persistence", () => {
interface ExtensionConfig {
struct ExtensionConfig {
noiseLevel: number;
profileId: string;
enabled: boolean;
Expand All @@ -126,7 +123,7 @@ Deno.test("Extension lifecycle: configuration persistence", () => {
};

// Simulate saving and loading
const savedConfig = JSON.stringify(config);
let savedConfig = JSON.stringify(config);
const loadedConfig: ExtensionConfig = JSON.parse(savedConfig);

assertEquals(loadedConfig.noiseLevel, 0.5);
Expand Down Expand Up @@ -168,7 +165,7 @@ Deno.test("Extension lifecycle: state serialization", () => {
};

// Serialize
const serialized = JSON.stringify(initialState);
let serialized = JSON.stringify(initialState);

// Deserialize
const deserialized: ExtensionState = JSON.parse(serialized);
Expand All @@ -195,4 +192,3 @@ Deno.test("Extension lifecycle: profile switching", () => {
assertEquals(state.activities.length, 0);
});

==================================== */
Loading
Loading