- Android/rust/archy-fips-core: leaf-only fips node as a JNI cdylib (fips pinned to the fips-native fork rev with VpnService fd support), built by gradle via cargo-ndk (arm64), tested on host - ArchyVpnService: split-tunnel VpnService routing only fd00::/8 (MTU 1280, foreground specialUse); FipsManager handles the one-time VPN consent and silent auto-start — no settings surface at all - pairing QR now fully configures the mesh: fnpub/fip/fhost/fudp/ftcp plus fanchors (the node's seed-anchor list, npub@addr/transport) so the phone can rendezvous through public anchors when the LAN endpoint is unreachable - default seed anchors gain the two dual-transport join.fips.network test anchors (23.182.128.74:443/tcp, 217.77.8.91:443/tcp); anchor adverts are Nostr kind-37195 events - device token rides the password field end-to-end: backend accepts tokens wherever it accepts the password, so scan = instant login (WebSocket auth + WebView form injection unchanged); token logins skip TOTP - ServerEntry.meshIp + IPv6-bracketed URLs; WebView retries the mesh address on main-frame errors, auto-login and origin checks honor it - companion v0.5.0 (versionCode 20), arm64 abiFilter; FipsNative.available gates everything so non-arm64 still runs as a plain companion Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
127 lines
3.4 KiB
Rust
127 lines
3.4 KiB
Rust
//! JNI surface for `com.archipelago.app.fips.FipsNative` — JSON over strings,
|
|
//! no codegen (the myco / nostr-vpn embedding pattern). Errors come back as
|
|
//! `{"error": "…"}` so Kotlin never sees a raw exception from native code.
|
|
|
|
use std::sync::Once;
|
|
|
|
use jni::objects::{JClass, JString};
|
|
use jni::sys::{jboolean, jint, jstring};
|
|
use jni::JNIEnv;
|
|
|
|
use crate::mesh;
|
|
|
|
static LOG_INIT: Once = Once::new();
|
|
|
|
fn init_logging() {
|
|
LOG_INIT.call_once(|| {
|
|
use tracing_subscriber::layer::SubscriberExt;
|
|
use tracing_subscriber::util::SubscriberInitExt;
|
|
let _ = tracing_subscriber::registry()
|
|
.with(tracing_subscriber::EnvFilter::new("info"))
|
|
.with(paranoid_android::layer("archy-fips"))
|
|
.try_init();
|
|
});
|
|
}
|
|
|
|
fn jstr(env: &mut JNIEnv, s: &JString) -> String {
|
|
env.get_string(s).map(|s| s.into()).unwrap_or_default()
|
|
}
|
|
|
|
fn out(env: &JNIEnv, s: String) -> jstring {
|
|
env.new_string(s)
|
|
.map(|s| s.into_raw())
|
|
.unwrap_or(std::ptr::null_mut())
|
|
}
|
|
|
|
fn err_json(e: impl std::fmt::Display) -> String {
|
|
serde_json::json!({ "error": e.to_string() }).to_string()
|
|
}
|
|
|
|
fn identity_json(info: &mesh::IdentityInfo) -> String {
|
|
serde_json::json!({
|
|
"secret": info.secret_hex,
|
|
"npub": info.npub,
|
|
"address": info.address,
|
|
})
|
|
.to_string()
|
|
}
|
|
|
|
/// Kotlin: `external fun generateIdentity(): String`
|
|
#[no_mangle]
|
|
pub extern "system" fn Java_com_archipelago_app_fips_FipsNative_generateIdentity(
|
|
env: JNIEnv,
|
|
_class: JClass,
|
|
) -> jstring {
|
|
init_logging();
|
|
let json = match mesh::generate_identity() {
|
|
Ok(info) => identity_json(&info),
|
|
Err(e) => err_json(e),
|
|
};
|
|
out(&env, json)
|
|
}
|
|
|
|
/// Kotlin: `external fun deriveIdentity(secret: String): String`
|
|
#[no_mangle]
|
|
pub extern "system" fn Java_com_archipelago_app_fips_FipsNative_deriveIdentity(
|
|
mut env: JNIEnv,
|
|
_class: JClass,
|
|
secret: JString,
|
|
) -> jstring {
|
|
init_logging();
|
|
let secret = jstr(&mut env, &secret);
|
|
let json = match mesh::derive_identity(&secret) {
|
|
Ok(info) => identity_json(&info),
|
|
Err(e) => err_json(e),
|
|
};
|
|
out(&env, json)
|
|
}
|
|
|
|
/// Kotlin: `external fun start(secret: String, peersJson: String, tunFd: Int): String`
|
|
/// Returns `{"npub": "...", "address": "..."}` or `{"error": "..."}`.
|
|
#[no_mangle]
|
|
pub extern "system" fn Java_com_archipelago_app_fips_FipsNative_start(
|
|
mut env: JNIEnv,
|
|
_class: JClass,
|
|
secret: JString,
|
|
peers_json: JString,
|
|
tun_fd: jint,
|
|
) -> jstring {
|
|
init_logging();
|
|
let secret = jstr(&mut env, &secret);
|
|
let peers = jstr(&mut env, &peers_json);
|
|
let json = match mesh::start(&secret, &peers, tun_fd) {
|
|
Ok((npub, address)) => {
|
|
serde_json::json!({ "npub": npub, "address": address }).to_string()
|
|
}
|
|
Err(e) => err_json(e),
|
|
};
|
|
out(&env, json)
|
|
}
|
|
|
|
/// Kotlin: `external fun stop()`
|
|
#[no_mangle]
|
|
pub extern "system" fn Java_com_archipelago_app_fips_FipsNative_stop(
|
|
_env: JNIEnv,
|
|
_class: JClass,
|
|
) {
|
|
mesh::stop();
|
|
}
|
|
|
|
/// Kotlin: `external fun isRunning(): Boolean`
|
|
#[no_mangle]
|
|
pub extern "system" fn Java_com_archipelago_app_fips_FipsNative_isRunning(
|
|
_env: JNIEnv,
|
|
_class: JClass,
|
|
) -> jboolean {
|
|
mesh::is_running() as jboolean
|
|
}
|
|
|
|
/// Kotlin: `external fun statusJson(): String`
|
|
#[no_mangle]
|
|
pub extern "system" fn Java_com_archipelago_app_fips_FipsNative_statusJson(
|
|
env: JNIEnv,
|
|
_class: JClass,
|
|
) -> jstring {
|
|
out(&env, mesh::status_json())
|
|
}
|