developer-toolkit
A comprehensive developer toolkit demonstrating advanced Forge extension capabilities.
Overview
This example shows:
- Code signing with
runtime:codesign - File hashing with
runtime:crypto - Process spawning with
runtime:process - System tray and dialogs
- Persistent preferences with
runtime:storage
Features
- File hashing (MD5, SHA-1, SHA-256, SHA-512)
- Code signature verification
- Signing with developer certificates
- Ad-hoc signing for testing
- Binary inspection (file type, architectures)
- System tray quick access
- Preference persistence
Running
forge dev examples/developer-toolkitCapabilities
[capabilities.fs]read = ["**/*"]write = ["**/*"]
[capabilities.process]allow = ["codesign", "signtool", "file", "lipo"]
[capabilities.codesign]allowed = true
[capabilities.crypto]allowed = trueKey Patterns
File Hashing
import { hash } from "runtime:crypto";import { readFile } from "runtime:fs";
const content = await readFile(path);
const [md5, sha1, sha256, sha512] = await Promise.all([ hash("md5", content), hash("sha1", content), hash("sha256", content), hash("sha512", content),]);Code Signing (macOS)
import { sign, signAdhoc, verify, listIdentities, checkCapabilities} from "runtime:codesign";
// Check platform capabilitiesconst caps = checkCapabilities();// { codesign: true, security: true, platform: "macos" }
// List available signing identitiesconst identities = await listIdentities();
// Sign with a specific identityawait sign({ path: "/path/to/app.app", identity: "Developer ID Application: ...", hardenedRuntime: true, deep: true, timestampUrl: "http://timestamp.digicert.com"});
// Or use ad-hoc signing for local testingawait signAdhoc("/path/to/app.app");Signature Verification
const result = await verify("/path/to/signed.app");// { valid: true, signer: "Developer ID...", timestamp: "..." }
// Get entitlements (macOS)const entitlements = await getEntitlements("/path/to/app.app");Binary Inspection
import { spawn } from "runtime:process";
// Get file typeconst proc = await spawn("file", { args: ["-b", path], stdout: "piped"});
let fileType = "";for await (const line of proc.stdout) { fileType += line;}await proc.wait();
// Get architectures (macOS)const lipoProc = await spawn("lipo", { args: ["-archs", path], stdout: "piped"});// Returns: "x86_64 arm64" for universal binariesSystem Notifications
import { notify } from "runtime:sys";
await notify({ title: "Signing Complete", body: `Successfully signed ${filename}`});Platform Support
| Feature | macOS | Windows | Linux |
|---|---|---|---|
| File Hashing | Yes | Yes | Yes |
| Code Signing | codesign | signtool | - |
| Verification | codesign -v | signtool verify | - |
| Identities | security | certutil | - |
Architecture
Developer Toolkit | +-- File Hashing (runtime:crypto) | |-- MD5, SHA-1, SHA-256, SHA-512 | +-- Code Signing (runtime:codesign) | |-- List identities | |-- Sign with certificate | |-- Ad-hoc signing | |-- Verify signatures | +-- Binary Inspection (runtime:process) | |-- file command | |-- lipo (macOS) | +-- UI (runtime:window) |-- Main window |-- System tray |-- File dialogsExtending
Add code signing automation:
// Batch sign all binaries in a directoryimport { readDir } from "runtime:fs";
for await (const entry of readDir("./dist")) { if (entry.isFile && entry.name.endsWith(".app")) { await sign({ path: `./dist/${entry.name}`, identity: selectedIdentity, deep: true }); }}