Skip to content

PrivacySafe/ios-skeleton

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PrivacySafe iOS Platform

iOS port of the PrivacySafe 3NWeb platform layer, structured for incremental implementation by developers working from the Android reference source (android-platform-poc-main) and the core protocol library (core-3nweb-client-lib).


Architecture overview

The Android app (android-platform-poc-main) runs two structurally different JS hosts:

  1. web-gui components — visible app UI (Chat, Contacts, Treasure, etc.) run in android.webkit.WebView, one per GenericAppActivity.
  2. deno components and the platform core itself — headless service scripts and the core library run in androidx.javascriptengine.JavaScriptSandbox / JavaScriptIsolate: a bare, no-DOM V8 isolate with nothing pre-installed except what the host explicitly injects.

The iOS mapping:

Android iOS Notes
WebView per web-gui component WKWebView per component Both are real browser-engine DOM contexts. WKWebView supports MessageChannel natively.
JavaScriptSandbox/JavaScriptIsolate per core/deno component JSContext (JavaScriptCore) per component Both are bare, no-DOM JS engines populated entirely by host-injected globals. JSContext runs in-process (no separate-process isolation), which is why the named-port machinery in IpcIntoJSEngine.kt simplifies to direct Swift closures here.
CoreRunnerService (START_STICKY foreground service) CoreSession (in-process singleton) iOS has no always-on foreground service concept. The core runs while the app is in the foreground. Background messaging notifications require a separate BGProcessingTask or push-notification-wakeup path — not yet implemented in this skeleton.
addJavascriptInterface(_, "_ipc_") WKScriptMessageHandler + injected w3n-shim.js WKWebView cannot expose synchronously-callable native methods. The shim presents the same window._ipc_ surface the real setup-w3n.bundle.js expects, via async postMessage round-trips.
js.createMessageChannel(portName, executor) Direct Swift closure exported into JSContext via JSValue JSContext runs in-process; there is no process-isolation reason for named ports. The full fn-calls.proto protobuf wire format is preserved.
common-preload.js (polyfills URL, self, setTimeout) Resources/JSEngine/common-preload.js Same polyfill contract. setTimeout routes through a native Swift call instead of Android's delay port round-trip, since JSContext supports direct synchronous function export.
core-load.js Resources/JSEngine/core-load.js Same wiring shape. Loads core-3nweb-client-lib bundle, passes native function references for crypto/FS/network.
app-preload.js Resources/JSEngine/app-preload.js Same wiring shape. Wires a deno component's globalThis.w3n and the core-ipc channel.
KeyStoreOps.kt — AndroidKeyStore AES-128-GCM, IV prepended Core/DeviceKeyCrypto.swift — Keychain, CryptoKit AES-GCM, same wire format Byte-compatible.
RandomFn.ktjava.security.SecureRandom SecRandomCopyBytes in Core/CoreInjectedFns.swift Direct equivalence.
RequestFn.kt — OkHttp, port name http_request URLSession in Core/CoreInjectedFns.swift Same proto shape (request.proto). Also handles WebSocket open (ws_open).
FsOps.kt / FhOps — POSIX-style FS + file-descriptor layer Core/FsInjectedFns.swift Full port. All 21 port names preserved exactly.
ecma-nacl-cryptors WASM crypto Same WASM bundle in JSContext No native crypto code needed. WASM runs natively in JavaScriptCore.

Repository layout

ios-skeleton/
├── README.md
├── LICENSE                            # GNU AGPLv3
├── NOTICE                             # Third-party copyright notices
├── BUILDING.md                        # Build pipeline for core-3nweb-client-lib bundle
├── Package.swift                      # SPM package (SwiftProtobuf dependency)
├── docs/                              # Technical documentation
│   ├── 00-index.md
│   ├── 01-architecture.md
│   ├── 02-ipc-transport.md
│   ├── 03-native-capabilities.md
│   ├── 04-lifecycle.md
│   └── 05-resource-serving.md
└── PrivacySafeiOS/
    ├── Protos/                        # Verbatim .proto files from android-platform-poc-main
    │   ├── fn-calls.proto             # Core IPC message shapes
    │   ├── fs-op.proto                # Filesystem op arg/result shapes
    │   ├── request.proto              # HTTP/WebSocket shapes
    │   ├── keystore-op.proto
    │   ├── random-op.proto
    │   ├── delay-op.proto
    │   ├── connectivity.proto
    │   ├── components.proto
    │   └── init.proto
    ├── Core/
    │   ├── Bundled.swift              # App domain constants, mirrors utils.kt's Bundled companion
    │   ├── CoreSession.swift          # In-process core singleton, mirrors CoreRunnerService
    │   ├── CoreInjectedFns.swift      # Native handlers: random, connectivity, HTTP, WS, keystore
    │   ├── FsInjectedFns.swift        # Native handlers: all FS and file-descriptor ops
    │   ├── DeviceKeyCrypto.swift      # AES-GCM device-key wrap, mirrors KeyStoreOps.kt
    │   └── WebSocketManager.swift     # URLSessionWebSocketTask lifecycle, mirrors WebSockets.kt
    ├── JSBridge/
    │   ├── JSEngineHost.swift         # JSContext wrapper, mirrors IpcIntoJSEngine.kt
    │   ├── CoreHost.swift             # Core isolate, mirrors CoreRunner.kt
    │   ├── DenoComponentHost.swift    # Headless component isolate, mirrors AppComponentRunner.kt
    │   └── IpcBridge.swift            # WKWebView _ipc_ bridge, mirrors IpcIntoWebView.kt
    ├── GUI/
    │   ├── RootViewController.swift   # Navigation shell; permissions; app entry point
    │   └── AppWebViewController.swift # WKWebView host per GUI component, mirrors GenericAppActivity.kt
    └── Resources/
        ├── w3n-shim.js               # Injected into WKWebView at document start
        └── JSEngine/
            ├── common-preload.js     # Polyfills for JSContext (no DOM, no timers)
            ├── core-load.js          # Wires core-3nweb-client-lib into JSContext
            └── app-preload.js        # Wires a deno component's w3n + core-ipc port

Dependencies

Swift Package Manager

SwiftProtobuf is declared in Package.swift and fetched automatically:

.package(url: "https://github.com/apple/swift-protobuf.git", from: "1.28.0"),

SwiftProtobuf is copyright Apple Inc. and contributors, licensed under the Apache License 2.0.

Generated protobuf Swift types

Run protoc against each .proto file in Protos/ to generate Swift types:

protoc --swift_out=PrivacySafeiOS/Generated \
  --proto_path=PrivacySafeiOS/Protos \
  fn-calls.proto fs-op.proto request.proto \
  keystore-op.proto random-op.proto delay-op.proto \
  connectivity.proto components.proto init.proto

Generated files go in PrivacySafeiOS/Generated/ (not tracked in this repository — they are build artifacts).

core-3nweb-client-lib bundle

See BUILDING.md for the complete build pipeline. The compiled bundle and WASM files are generated artifacts and are not tracked in this repository. Add the following to .gitignore:

PrivacySafeiOS/Resources/JSEngine/core-3nweb-client-lib.bundle.js
PrivacySafeiOS/Resources/JSEngine/*.wasm
PrivacySafeiOS/Generated/

What you must provide before this compiles

1. The core-3nweb-client-lib compiled JS bundle.

Build from source following BUILDING.md, or obtain from the PrivacySafe release distribution. Place as PrivacySafeiOS/Resources/JSEngine/core-3nweb-client-lib.bundle.js.

2. WASM files.

Produced as part of the same build step (see BUILDING.md). Place *.wasm files in PrivacySafeiOS/Resources/JSEngine/.

3. Generated protobuf Swift files.

Run protoc as described above. Place generated files in PrivacySafeiOS/Generated/.


listObjPath synchrony gap

The real setup-w3n.bundle.js runtime-ipc calls window._ipc_.listObjPath(...) synchronously — it is a plain function call with a return value, not a Promise. WKScriptMessageHandler cannot fulfil a synchronous native call; every JS→native communication is fire-and-forget.

Two viable approaches, neither pre-decided here:

Option A — Patch the bundle. In the platform-ts build, change the one call site in runtime-ipc.ts that calls androidIPC.listObjPath to be async/await and propagate async upward. This is a one-line change in that file and a small ripple into makeClientSideConnector. This gives a correct iOS-specific bundle.

Option B — Pre-warm cache. Before loading the page in WKWebView, make the listObjPath result for ['w3n', ...] available synchronously by fetching it from the core (via CoreSession) and storing it in the shim's closure scope before the page script runs.

w3n-shim.js currently returns an empty array with a console warning for this call. See docs/05-resource-serving.md §5 for full analysis.


Background services / launchOnSystemStartup

Many app manifests declare launchOnSystemStartup components (background-instance.mjs for Chat, contactDenoServices.js for Contacts, treasureDenoServices.js for Treasure). Android starts these as CoreRunnerService deno components on boot via InitOnBoot.

iOS has no equivalent always-on service. Three strategies are available (see docs/04-lifecycle.md §6 for full discussion):

  • Foreground-only — run in-process, stop when app is backgrounded.
  • Push notifications — for Chat, pair with a push notification gateway.
  • BGProcessingTask — for periodic background sync (Contacts, Treasure).

None are implemented in this skeleton.


Known remaining work

  • SwiftUI root view / launcher shell — RootViewController is UIKit-based. A SwiftUI app shell using UIViewControllerRepresentable is possible but not yet provided.
  • BGProcessingTask / push wakeup for background deno components — see docs/04-lifecycle.md §6 for the three available strategies. None are implemented.
  • listObjPath synchrony gap — see the section above and docs/05-resource-serving.md §5.

Technical documentation

Detailed specifications for every layer of the platform are in docs/:


License

Copyright (C) 2026 Ivy Cyber LLC

This project is licensed under the GNU Affero General Public License version 3.0 or later. See LICENSE for the full license text.

This project is derived in part from upstream works by 3NSoft Inc., licensed under the GNU General Public License version 3.0 or later. The Protocol Buffer schema files in PrivacySafeiOS/Protos/ are verbatim copies from android-platform-poc-main by 3NSoft Inc. The compiled core-3nweb-client-lib bundle (generated; see BUILDING.md) is derived from core-3nweb-client-lib by 3NSoft Inc., also GPL-3.0-or-later.

The GNU General Public License version 3.0 is compatible with the GNU Affero General Public License version 3.0 under AGPL-3.0 §13.

See NOTICE for the complete list of third-party components and their copyright notices.

About

iOS app for PrivacySafe

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors