feat: admit signed mobile sync bridge module

This commit is contained in:
冰朔 2026-08-19 04:14:58 +08:00
commit 292889f934
21 changed files with 1891 additions and 15 deletions

View file

@ -1558,6 +1558,7 @@ dependencies = [
"futures-util",
"interprocess",
"minisign-verify",
"qrcode",
"quick-xml 0.31.0",
"regex",
"reqwest",
@ -3043,6 +3044,12 @@ dependencies = [
"psl-types",
]
[[package]]
name = "qrcode"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d68782463e408eb1e668cf6152704bd856c78c5b6417adaee3203d8f4c1fc9ec"
[[package]]
name = "quick-xml"
version = "0.31.0"

View file

@ -41,6 +41,7 @@ zip = { version = "=0.6.6", default-features = false, features = ["deflate"] }
tokio = { version = "1", features = ["time"] }
futures-util = "0.3"
minisign-verify = "0.2.5"
qrcode = { version = "0.14", default-features = false, features = ["svg"] }
[target.'cfg(windows)'.dependencies]
widestring = "1"

View file

@ -18,6 +18,7 @@ mod home_status;
mod knowledge_base;
mod local_development_bridge;
mod metacognitive_zero_layer;
mod mobile_sync;
mod module_package_runtime;
mod native_composition;
mod number_coordinate_tree;
@ -53,6 +54,7 @@ pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_dialog::init())
.manage(numbered_ipc::NumberedIpcState::default())
.manage(mobile_sync::MobileSyncState::default())
.invoke_handler(tauri::generate_handler![numbered_ipc::numbered_ipc,])
.setup(|app| {
// GLS 是 HoloLake 产品内核,不是开发机旁路服务。合同、依赖闭包、

File diff suppressed because it is too large Load diff

View file

@ -87,6 +87,12 @@ const WEB_NOVEL_DELIVERY_PACKAGE: &[u8] = include_bytes!(
const WEB_NOVEL_DELIVERY_SIGNATURE: &str = include_str!(
"../../fixtures/module-packages/HLP-MOD-OFFICIAL-WEB-NOVEL-DELIVERY-0001-0.1.0.ghmod.sig"
);
const MOBILE_SYNC_NUMBER: &str = "HLP-MOD-OFFICIAL-MOBILE-SYNC-0001";
const MOBILE_SYNC_PACKAGE: &[u8] =
include_bytes!("../../fixtures/module-packages/HLP-MOD-OFFICIAL-MOBILE-SYNC-0001-0.1.0.ghmod");
const MOBILE_SYNC_SIGNATURE: &str = include_str!(
"../../fixtures/module-packages/HLP-MOD-OFFICIAL-MOBILE-SYNC-0001-0.1.0.ghmod.sig"
);
struct BundledModuleSource {
module_number: &'static str,
@ -140,6 +146,11 @@ const BUNDLED_MODULES: &[BundledModuleSource] = &[
package: WEB_NOVEL_DELIVERY_PACKAGE,
signature: WEB_NOVEL_DELIVERY_SIGNATURE,
},
BundledModuleSource {
module_number: MOBILE_SYNC_NUMBER,
package: MOBILE_SYNC_PACKAGE,
signature: MOBILE_SYNC_SIGNATURE,
},
];
#[derive(Debug, Deserialize)]
@ -1209,6 +1220,9 @@ pub async fn unmount_module(
app: AppHandle,
input: ModuleNumberInput,
) -> Result<ModuleMutationReceipt, String> {
if input.module_number == MOBILE_SYNC_NUMBER {
crate::mobile_sync::stop_for_unmount(&app)?;
}
transition(
&runtime_root(&app)?,
&input.module_number,
@ -1585,7 +1599,7 @@ mod tests {
assert_eq!(package.manifest.adapter, "channel-workbench-v1");
assert_eq!(package.manifest.permissions.len(), 4);
assert!(is_sha256(&digest));
assert_eq!(BUNDLED_MODULES.len(), 9);
assert_eq!(BUNDLED_MODULES.len(), 10);
}
#[test]
@ -1670,6 +1684,29 @@ mod tests {
}
}
#[test]
fn bundled_mobile_sync_is_signed_and_keeps_the_desktop_as_root_node() {
let (_, package, digest) = read_verified_package_bytes(
MOBILE_SYNC_PACKAGE,
MOBILE_SYNC_SIGNATURE,
RELEASE_TRUST_RAW,
)
.unwrap();
assert_eq!(package.manifest.module_number, MOBILE_SYNC_NUMBER);
assert_eq!(package.manifest.registration_class, "OFFICIAL_LIGHTHOUSE");
assert_eq!(package.manifest.adapter, "mobile-sync-v1");
assert_eq!(package.manifest.permissions.len(), 5);
assert_eq!(
package.payload["adapterConfig"]["desktopRole"],
"USER_LOCAL_COMPUTER_TERMINAL_ROOT_NODE"
);
assert_eq!(
package.payload["adapterConfig"]["iosClientPackaging"],
"PENDING_SEPARATE_ADMISSION"
);
assert!(is_sha256(&digest));
}
#[cfg(unix)]
#[test]
fn symlinked_package_input_is_rejected_before_signature_processing() {

View file

@ -53,7 +53,7 @@ fn validate_tree() -> Result<(), String> {
|| tree.record_id != "HLP-UNIFIED-NUMBER-TREE-001"
|| tree.state != "MACHINE_COMPILED_STARTUP_ENFORCED"
|| tree.root_number != "HLP-NUMBER-WORLD-ROOT-001"
|| tree.route_count != 162
|| tree.route_count != 168
|| tree.routes.len() != tree.route_count
|| !tree.invariants.number_is_stable_coordinate_not_authority
|| !tree.invariants.path_is_unique_navigation

View file

@ -934,7 +934,7 @@ mod tests {
#[test]
fn registry_is_closed_and_contains_every_migrated_command() {
let registry = load_registry().unwrap();
assert_eq!(registry.operations.len(), 140);
assert_eq!(registry.operations.len(), 146);
assert!(!registry.runtime.legacy_direct_commands_allowed);
}

View file

@ -126,6 +126,20 @@ pub(crate) async fn dispatch(
"module_package_runtime::activate_bundled_module" => json(
crate::module_package_runtime::activate_bundled_module(app, input(&payload)?).await?,
),
"mobile_sync::start_mobile_sync" => json(crate::mobile_sync::start_mobile_sync(app)?),
"mobile_sync::get_mobile_sync_status" => {
json(crate::mobile_sync::get_mobile_sync_status(app)?)
}
"mobile_sync::rotate_mobile_pairing" => {
json(crate::mobile_sync::rotate_mobile_pairing(app)?)
}
"mobile_sync::stop_mobile_sync" => json(crate::mobile_sync::stop_mobile_sync(app)?),
"mobile_sync::revoke_mobile_sync_device" => json(
crate::mobile_sync::revoke_mobile_sync_device(app, input(&payload)?)?,
),
"mobile_sync::get_mobile_sync_snapshot" => {
json(crate::mobile_sync::get_mobile_sync_snapshot(app)?)
}
"native_composition::get_native_composition_module_registry" => {
json(crate::native_composition::get_native_composition_module_registry())
}