hololake-system-architecture/product-source/hololake-native-desktop/src-tauri/src/numbered_ipc.rs

1041 lines
34 KiB
Rust

//! HoloLake numbered IPC root.
//!
//! Stable numbers are coordinates, not authority. Every operation first receives a
//! short-lived server-issued grant bound to the exact caller/channel/module/operation/
//! target tuple, protocol version, nonce and canonical payload digest. The grant is
//! consumed once before the internal handler runs. No business handler is registered
//! directly with Tauri.
use base64::Engine;
use ring::{digest, hmac, rand as ring_rand};
use ring_rand::SecureRandom;
use rusqlite::{params, Connection, OptionalExtension};
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
use std::collections::{HashMap, HashSet};
use std::fs;
use std::path::PathBuf;
use std::sync::Mutex;
use std::time::{SystemTime, UNIX_EPOCH};
use tauri::{AppHandle, Manager, State};
use uuid::Uuid;
const EMBEDDED_REGISTRY: &str = include_str!("../../contracts/numbered-ipc-registry.json");
const EXPECTED_SCHEMA: &str = "hololake.numbered-ipc-registry/v1";
const EXPECTED_RECORD_ID: &str = "HLP-NUMBERED-IPC-ROOT-001";
#[derive(Clone, Debug, Deserialize)]
struct NumberedIpcRegistry {
schema: String,
record_id: String,
runtime: RuntimeRules,
payload_contract: PayloadContract,
operations: Vec<OperationRoute>,
}
#[derive(Clone, Debug, Deserialize)]
struct RuntimeRules {
public_tauri_command: String,
caller_number: String,
caller_number_subject_kind: String,
caller_number_grants_persona_binding: bool,
protocol_version: String,
legacy_direct_commands_allowed: bool,
grants_issued_server_side: bool,
grant_single_use: bool,
payload_bound_grants: bool,
authority_binding_issued_server_side: bool,
verified_human_binding_required_for_protected_routes: bool,
persona_binding_claimed: bool,
user_channel_body_binding_stage: String,
maximum_grant_ttl_ms: u64,
unknown_route: String,
mismatched_coordinate: String,
expired_or_replayed_grant: String,
receipt_required: bool,
}
#[derive(Clone, Debug, Deserialize)]
struct PayloadContract {
unknown_or_unclassified_alias: String,
unknown_top_level_field: String,
empty_object_aliases: Vec<String>,
input_wrapper_aliases: Vec<String>,
direct_field_aliases: HashMap<String, Vec<String>>,
}
#[derive(Clone, Debug, Deserialize)]
struct OperationRoute {
operation_number: String,
alias: String,
handler: String,
channel_number: String,
module_number: String,
target_number: String,
admission: String,
effect: String,
payload_schema: String,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
struct NumberedCoordinate {
protocol_version: String,
caller_number: String,
channel_number: String,
module_number: String,
operation_number: String,
target_number: String,
request_nonce: String,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
struct NumberedEnvelope {
#[serde(flatten)]
coordinate: NumberedCoordinate,
#[serde(default = "default_ttl_ms")]
requested_ttl_ms: u64,
#[serde(default)]
payload: Value,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
enum NumberedIpcAction {
IssueGrant,
Execute,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
struct NumberedIpcInput {
action: NumberedIpcAction,
envelope: NumberedEnvelope,
grant: Option<NumberedGrant>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct NumberedGrant {
grant_id: String,
expires_at_unix_ms: u64,
payload_sha256: String,
authority_binding_sha256: String,
signature: String,
}
#[derive(Clone, Debug)]
struct GrantRecord {
coordinate: NumberedCoordinate,
expires_at_unix_ms: u64,
payload_sha256: String,
authority_binding_sha256: String,
signature: String,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct NumberedIpcReceipt {
receipt_id: String,
state: String,
decision: String,
operation_number: String,
payload_sha256: String,
authority_binding_sha256: String,
observed_at_unix_ms: u64,
previous_receipt_hash: String,
receipt_hash: String,
error: Option<String>,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct NumberedIpcResponse {
schema: &'static str,
decision: String,
grant: Option<NumberedGrant>,
result: Option<Value>,
error: Option<String>,
receipt: NumberedIpcReceipt,
}
pub struct NumberedIpcState {
signing_key: hmac::Key,
grants: Mutex<HashMap<String, GrantRecord>>,
ledger: Mutex<()>,
}
impl Default for NumberedIpcState {
fn default() -> Self {
let random = ring_rand::SystemRandom::new();
let mut secret = [0_u8; 32];
random
.fill(&mut secret)
.expect("operating system randomness is required for numbered IPC");
Self {
signing_key: hmac::Key::new(hmac::HMAC_SHA256, &secret),
grants: Mutex::new(HashMap::new()),
ledger: Mutex::new(()),
}
}
}
fn default_ttl_ms() -> u64 {
10_000
}
fn now_unix_ms() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|duration| duration.as_millis() as u64)
.unwrap_or(0)
}
fn sha256_hex(bytes: &[u8]) -> String {
digest::digest(&digest::SHA256, bytes)
.as_ref()
.iter()
.map(|byte| format!("{byte:02x}"))
.collect()
}
fn canonical_value(value: &Value) -> Value {
match value {
Value::Array(values) => Value::Array(values.iter().map(canonical_value).collect()),
Value::Object(object) => {
let mut keys = object.keys().collect::<Vec<_>>();
keys.sort();
let mut canonical = Map::new();
for key in keys {
canonical.insert(key.clone(), canonical_value(&object[key]));
}
Value::Object(canonical)
}
_ => value.clone(),
}
}
fn payload_digest(payload: &Value) -> Result<String, String> {
let bytes = serde_json::to_vec(&canonical_value(payload))
.map_err(|error| format!("HOLOLAKE_NUMBERED_IPC_PAYLOAD_INVALID: {error}"))?;
if bytes.len() > 1_048_576 {
return Err("HOLOLAKE_NUMBERED_IPC_PAYLOAD_TOO_LARGE".into());
}
Ok(sha256_hex(&bytes))
}
fn grant_signing_bytes(
grant_id: &str,
coordinate: &NumberedCoordinate,
expires_at_unix_ms: u64,
payload_sha256: &str,
authority_binding_sha256: &str,
) -> Vec<u8> {
format!(
"HLP-NIPC-GRANT-v1\n{grant_id}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{expires_at_unix_ms}\n{payload_sha256}\n{authority_binding_sha256}",
coordinate.protocol_version,
coordinate.caller_number,
coordinate.channel_number,
coordinate.module_number,
coordinate.operation_number,
coordinate.target_number,
coordinate.request_nonce,
EXPECTED_RECORD_ID,
)
.into_bytes()
}
fn load_registry() -> Result<NumberedIpcRegistry, String> {
let registry: NumberedIpcRegistry = serde_json::from_str(EMBEDDED_REGISTRY)
.map_err(|error| format!("HOLOLAKE_NUMBERED_IPC_REGISTRY_INVALID: {error}"))?;
validate_registry(&registry)?;
Ok(registry)
}
fn validate_registry(registry: &NumberedIpcRegistry) -> Result<(), String> {
let runtime = &registry.runtime;
if registry.schema != EXPECTED_SCHEMA
|| registry.record_id != EXPECTED_RECORD_ID
|| runtime.public_tauri_command != "numbered_ipc"
|| runtime.caller_number_subject_kind != "PHYSICAL_WEBVIEW_ENTRY_NOT_PERSONA_IDENTITY"
|| runtime.caller_number_grants_persona_binding
|| runtime.legacy_direct_commands_allowed
|| !runtime.grants_issued_server_side
|| !runtime.grant_single_use
|| !runtime.payload_bound_grants
|| !runtime.authority_binding_issued_server_side
|| !runtime.verified_human_binding_required_for_protected_routes
|| runtime.persona_binding_claimed
|| runtime.user_channel_body_binding_stage != "SEPARATE_EVIDENCE_LAYER_NOT_YET_CLAIMED"
|| !runtime.receipt_required
|| runtime.maximum_grant_ttl_ms == 0
|| runtime.maximum_grant_ttl_ms > 30_000
|| runtime.unknown_route != "FAIL_CLOSED"
|| runtime.mismatched_coordinate != "FAIL_CLOSED"
|| runtime.expired_or_replayed_grant != "FAIL_CLOSED"
|| registry.operations.len() < 60
{
return Err("HOLOLAKE_NUMBERED_IPC_REGISTRY_BOUNDARY_INVALID".into());
}
if registry.payload_contract.unknown_or_unclassified_alias != "FAIL_CLOSED_BEFORE_GRANT"
|| registry.payload_contract.unknown_top_level_field != "FAIL_CLOSED_BEFORE_GRANT"
{
return Err("HOLOLAKE_NUMBERED_IPC_PAYLOAD_CONTRACT_INVALID".into());
}
let mut operation_numbers = HashSet::new();
let mut aliases = HashSet::new();
let mut coordinates = HashSet::new();
for route in &registry.operations {
let coordinate = format!(
"{}/{}/{}/{}",
route.channel_number, route.module_number, route.operation_number, route.target_number
);
if !operation_numbers.insert(route.operation_number.as_str())
|| !aliases.insert(route.alias.as_str())
|| !coordinates.insert(coordinate)
|| !route.operation_number.starts_with("HLP-NIPC-OP-")
|| !route.module_number.starts_with("HLP-NIPC-MOD-")
|| !route.channel_number.starts_with("HLP-NIPC-CH-")
|| !route.target_number.starts_with("HLP-NIPC-TGT-")
|| !route.handler.contains("::")
|| !matches!(
route.admission.as_str(),
"PREAUTH_SYSTEM_ROUTE" | "VERIFIED_HUMAN_ROUTE"
)
|| !matches!(route.effect.as_str(), "READ_OR_STATUS" | "STATE_CHANGE")
|| !route
.payload_schema
.starts_with("hololake.numbered-ipc.payload/")
{
return Err("HOLOLAKE_NUMBERED_IPC_ROUTE_INVALID".into());
}
}
let mut payload_aliases = HashSet::new();
for alias in registry
.payload_contract
.empty_object_aliases
.iter()
.chain(registry.payload_contract.input_wrapper_aliases.iter())
.chain(registry.payload_contract.direct_field_aliases.keys())
{
if !payload_aliases.insert(alias.as_str()) {
return Err("HOLOLAKE_NUMBERED_IPC_PAYLOAD_ALIAS_DUPLICATED".into());
}
}
if payload_aliases != aliases {
return Err("HOLOLAKE_NUMBERED_IPC_PAYLOAD_COVERAGE_INCOMPLETE".into());
}
Ok(())
}
fn validate_payload_shape(
registry: &NumberedIpcRegistry,
route: &OperationRoute,
payload: &Value,
) -> Result<(), String> {
let object = payload
.as_object()
.ok_or_else(|| "HOLOLAKE_NUMBERED_IPC_PAYLOAD_OBJECT_REQUIRED".to_string())?;
if registry
.payload_contract
.empty_object_aliases
.iter()
.any(|alias| alias == &route.alias)
{
return if object.is_empty() {
Ok(())
} else {
Err("HOLOLAKE_NUMBERED_IPC_PAYLOAD_FIELD_UNKNOWN".into())
};
}
if registry
.payload_contract
.input_wrapper_aliases
.iter()
.any(|alias| alias == &route.alias)
{
return if object.len() == 1 && object.contains_key("input") {
Ok(())
} else {
Err("HOLOLAKE_NUMBERED_IPC_INPUT_WRAPPER_REQUIRED".into())
};
}
if let Some(required_fields) = registry
.payload_contract
.direct_field_aliases
.get(&route.alias)
{
let required = required_fields
.iter()
.map(String::as_str)
.collect::<HashSet<_>>();
let observed = object.keys().map(String::as_str).collect::<HashSet<_>>();
if observed != required
|| required_fields
.iter()
.any(|field| !object.get(field).is_some_and(Value::is_string))
{
return Err("HOLOLAKE_NUMBERED_IPC_DIRECT_FIELDS_INVALID".into());
}
return Ok(());
}
Err("HOLOLAKE_NUMBERED_IPC_PAYLOAD_ALIAS_UNCLASSIFIED".into())
}
fn resolve_route<'a>(
registry: &'a NumberedIpcRegistry,
coordinate: &NumberedCoordinate,
) -> Result<&'a OperationRoute, String> {
if coordinate.protocol_version != registry.runtime.protocol_version
|| coordinate.caller_number != registry.runtime.caller_number
{
return Err("HOLOLAKE_NUMBERED_IPC_CALLER_OR_PROTOCOL_MISMATCH".into());
}
if coordinate.request_nonce.len() < 16
|| coordinate.request_nonce.len() > 128
|| coordinate
.request_nonce
.chars()
.any(|character| character.is_whitespace() || character.is_control())
{
return Err("HOLOLAKE_NUMBERED_IPC_NONCE_INVALID".into());
}
let route = registry
.operations
.iter()
.find(|route| route.operation_number == coordinate.operation_number)
.ok_or_else(|| "HOLOLAKE_NUMBERED_IPC_ROUTE_UNKNOWN".to_string())?;
if route.channel_number != coordinate.channel_number
|| route.module_number != coordinate.module_number
|| route.target_number != coordinate.target_number
{
return Err("HOLOLAKE_NUMBERED_IPC_ROUTE_COORDINATE_MISMATCH".into());
}
Ok(route)
}
fn enforce_admission(app: &AppHandle, route: &OperationRoute) -> Result<String, String> {
if route.admission == "PREAUTH_SYSTEM_ROUTE" {
return Ok("SYSTEM_PHYSICAL_ENTRY:HLP-NIPC-CALLER-MAIN-WEBVIEW-0001".into());
}
let state = app.state::<crate::zero_point::ZeroPointState>();
match crate::zero_point::verified_user_route(&state)? {
Some((human_number, registry_domain)) => {
Ok(format!("VERIFIED_HUMAN:{registry_domain}:{human_number}"))
}
None => Err("HOLOLAKE_NUMBERED_IPC_VERIFIED_HUMAN_REQUIRED".into()),
}
}
fn issue_grant_at(
state: &NumberedIpcState,
registry: &NumberedIpcRegistry,
envelope: &NumberedEnvelope,
authority_binding: &str,
now: u64,
) -> Result<(NumberedGrant, String), String> {
let route = resolve_route(registry, &envelope.coordinate)?;
validate_payload_shape(registry, route, &envelope.payload)?;
if envelope.requested_ttl_ms == 0
|| envelope.requested_ttl_ms > registry.runtime.maximum_grant_ttl_ms
{
return Err("HOLOLAKE_NUMBERED_IPC_GRANT_TTL_INVALID".into());
}
let payload_sha256 = payload_digest(&envelope.payload)?;
let authority_binding_sha256 = sha256_hex(authority_binding.as_bytes());
let grant_id = format!("HLP-NIPC-GRANT-{}", Uuid::new_v4().simple());
let expires_at_unix_ms = now.saturating_add(envelope.requested_ttl_ms);
let signature = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(hmac::sign(
&state.signing_key,
&grant_signing_bytes(
&grant_id,
&envelope.coordinate,
expires_at_unix_ms,
&payload_sha256,
&authority_binding_sha256,
),
));
let record = GrantRecord {
coordinate: envelope.coordinate.clone(),
expires_at_unix_ms,
payload_sha256: payload_sha256.clone(),
authority_binding_sha256: authority_binding_sha256.clone(),
signature: signature.clone(),
};
let mut grants = state
.grants
.lock()
.map_err(|_| "HOLOLAKE_NUMBERED_IPC_GRANT_LOCK_POISONED".to_string())?;
grants.retain(|_, existing| existing.expires_at_unix_ms >= now);
grants.insert(grant_id.clone(), record);
Ok((
NumberedGrant {
grant_id,
expires_at_unix_ms,
payload_sha256: payload_sha256.clone(),
authority_binding_sha256,
signature,
},
payload_sha256,
))
}
fn consume_grant_at(
state: &NumberedIpcState,
registry: &NumberedIpcRegistry,
envelope: &NumberedEnvelope,
grant: &NumberedGrant,
authority_binding: &str,
now: u64,
) -> Result<String, String> {
let route = resolve_route(registry, &envelope.coordinate)?;
validate_payload_shape(registry, route, &envelope.payload)?;
let payload_sha256 = payload_digest(&envelope.payload)?;
let authority_binding_sha256 = sha256_hex(authority_binding.as_bytes());
let record = state
.grants
.lock()
.map_err(|_| "HOLOLAKE_NUMBERED_IPC_GRANT_LOCK_POISONED".to_string())?
.remove(&grant.grant_id)
.ok_or_else(|| "HOLOLAKE_NUMBERED_IPC_GRANT_UNKNOWN_OR_REPLAYED".to_string())?;
if now > record.expires_at_unix_ms
|| grant.expires_at_unix_ms != record.expires_at_unix_ms
|| grant.payload_sha256 != record.payload_sha256
|| payload_sha256 != record.payload_sha256
|| grant.authority_binding_sha256 != record.authority_binding_sha256
|| authority_binding_sha256 != record.authority_binding_sha256
|| grant.signature != record.signature
|| envelope.coordinate != record.coordinate
{
return Err("HOLOLAKE_NUMBERED_IPC_GRANT_MISMATCH_OR_EXPIRED".into());
}
let signature = base64::engine::general_purpose::URL_SAFE_NO_PAD
.decode(&grant.signature)
.map_err(|_| "HOLOLAKE_NUMBERED_IPC_GRANT_SIGNATURE_INVALID".to_string())?;
hmac::verify(
&state.signing_key,
&grant_signing_bytes(
&grant.grant_id,
&envelope.coordinate,
grant.expires_at_unix_ms,
&grant.payload_sha256,
&grant.authority_binding_sha256,
),
&signature,
)
.map_err(|_| "HOLOLAKE_NUMBERED_IPC_GRANT_SIGNATURE_INVALID".to_string())?;
Ok(payload_sha256)
}
fn ledger_path(app: &AppHandle) -> Result<PathBuf, String> {
let root = app
.path()
.app_data_dir()
.map_err(|error| format!("HOLOLAKE_NUMBERED_IPC_HOME_FAILED: {error}"))?
.join("numbered-ipc-v1");
fs::create_dir_all(&root)
.map_err(|error| format!("HOLOLAKE_NUMBERED_IPC_HOME_CREATE_FAILED: {error}"))?;
Ok(root.join("receipts.sqlite3"))
}
fn open_ledger(app: &AppHandle) -> Result<Connection, String> {
let connection = Connection::open(ledger_path(app)?)
.map_err(|error| format!("HOLOLAKE_NUMBERED_IPC_LEDGER_OPEN_FAILED: {error}"))?;
connection
.execute_batch(
"PRAGMA journal_mode=WAL;
PRAGMA busy_timeout=5000;
CREATE TABLE IF NOT EXISTS receipts(
sequence INTEGER PRIMARY KEY AUTOINCREMENT,
receipt_id TEXT NOT NULL UNIQUE,
state TEXT NOT NULL,
decision TEXT NOT NULL,
operation_number TEXT NOT NULL,
payload_sha256 TEXT NOT NULL,
authority_binding_sha256 TEXT NOT NULL DEFAULT '',
observed_at_unix_ms INTEGER NOT NULL,
previous_receipt_hash TEXT NOT NULL,
receipt_hash TEXT NOT NULL UNIQUE,
error TEXT
);",
)
.map_err(|error| format!("HOLOLAKE_NUMBERED_IPC_LEDGER_SCHEMA_FAILED: {error}"))?;
let has_authority_binding = {
let mut statement = connection
.prepare("PRAGMA table_info(receipts)")
.map_err(|error| format!("HOLOLAKE_NUMBERED_IPC_LEDGER_SCHEMA_READ_FAILED: {error}"))?;
let columns = statement
.query_map([], |row| row.get::<_, String>(1))
.map_err(|error| format!("HOLOLAKE_NUMBERED_IPC_LEDGER_SCHEMA_READ_FAILED: {error}"))?;
let mut found = false;
for column in columns {
if column.map_err(|error| {
format!("HOLOLAKE_NUMBERED_IPC_LEDGER_SCHEMA_READ_FAILED: {error}")
})? == "authority_binding_sha256"
{
found = true;
}
}
found
};
if !has_authority_binding {
connection
.execute(
"ALTER TABLE receipts ADD COLUMN authority_binding_sha256 TEXT NOT NULL DEFAULT ''",
[],
)
.map_err(|error| {
format!("HOLOLAKE_NUMBERED_IPC_LEDGER_SCHEMA_MIGRATION_FAILED: {error}")
})?;
}
Ok(connection)
}
#[allow(clippy::too_many_arguments)]
fn append_receipt(
app: &AppHandle,
state: &NumberedIpcState,
event_state: &str,
decision: &str,
operation_number: &str,
payload_sha256: &str,
authority_binding_sha256: &str,
error: Option<String>,
now: u64,
) -> Result<NumberedIpcReceipt, String> {
let _guard = state
.ledger
.lock()
.map_err(|_| "HOLOLAKE_NUMBERED_IPC_LEDGER_LOCK_POISONED".to_string())?;
let connection = open_ledger(app)?;
let previous_receipt_hash = connection
.query_row(
"SELECT receipt_hash FROM receipts ORDER BY sequence DESC LIMIT 1",
[],
|row| row.get::<_, String>(0),
)
.optional()
.map_err(|error| format!("HOLOLAKE_NUMBERED_IPC_LEDGER_READ_FAILED: {error}"))?
.unwrap_or_else(|| "0".repeat(64));
let receipt_id = format!("HLP-NIPC-RECEIPT-{}", Uuid::new_v4().simple());
let receipt_hash = sha256_hex(
format!(
"HLP-NIPC-RECEIPT-v1\n{previous_receipt_hash}\n{receipt_id}\n{event_state}\n{decision}\n{operation_number}\n{payload_sha256}\n{authority_binding_sha256}\n{now}\n{}",
error.as_deref().unwrap_or("")
)
.as_bytes(),
);
connection
.execute(
"INSERT INTO receipts(receipt_id,state,decision,operation_number,payload_sha256,
authority_binding_sha256,observed_at_unix_ms,previous_receipt_hash,receipt_hash,error)
VALUES(?1,?2,?3,?4,?5,?6,?7,?8,?9,?10)",
params![
receipt_id,
event_state,
decision,
operation_number,
payload_sha256,
authority_binding_sha256,
now,
previous_receipt_hash,
receipt_hash,
error,
],
)
.map_err(|error| format!("HOLOLAKE_NUMBERED_IPC_LEDGER_APPEND_FAILED: {error}"))?;
Ok(NumberedIpcReceipt {
receipt_id,
state: event_state.into(),
decision: decision.into(),
operation_number: operation_number.into(),
payload_sha256: payload_sha256.into(),
authority_binding_sha256: authority_binding_sha256.into(),
observed_at_unix_ms: now,
previous_receipt_hash,
receipt_hash,
error,
})
}
#[allow(clippy::too_many_arguments)]
fn response(
app: &AppHandle,
state: &NumberedIpcState,
event_state: &str,
decision: &str,
operation_number: &str,
payload_sha256: &str,
grant: Option<NumberedGrant>,
result: Option<Value>,
error: Option<String>,
now: u64,
) -> Result<NumberedIpcResponse, String> {
let receipt = append_receipt(
app,
state,
event_state,
decision,
operation_number,
payload_sha256,
&sha256_hex(b"UNBOUND_AUTHORITY"),
error.clone(),
now,
)?;
Ok(NumberedIpcResponse {
schema: "hololake.numbered-ipc-response/v1",
decision: decision.into(),
grant,
result,
error,
receipt,
})
}
#[allow(clippy::too_many_arguments)]
fn bound_response(
app: &AppHandle,
state: &NumberedIpcState,
authority_binding: &str,
event_state: &str,
decision: &str,
operation_number: &str,
payload_sha256: &str,
grant: Option<NumberedGrant>,
result: Option<Value>,
error: Option<String>,
now: u64,
) -> Result<NumberedIpcResponse, String> {
let receipt = append_receipt(
app,
state,
event_state,
decision,
operation_number,
payload_sha256,
&sha256_hex(authority_binding.as_bytes()),
error.clone(),
now,
)?;
Ok(NumberedIpcResponse {
schema: "hololake.numbered-ipc-response/v1",
decision: decision.into(),
grant,
result,
error,
receipt,
})
}
pub(crate) fn start_on_application_open(app: &AppHandle) -> Result<(), String> {
let _ = load_registry()?;
let _ = open_ledger(app)?;
Ok(())
}
#[tauri::command]
pub async fn numbered_ipc(
app: AppHandle,
state: State<'_, NumberedIpcState>,
input: Value,
) -> Result<NumberedIpcResponse, String> {
let now = now_unix_ms();
let request: NumberedIpcInput = serde_json::from_value(input)
.map_err(|error| format!("HOLOLAKE_NUMBERED_IPC_ENVELOPE_INVALID: {error}"))?;
let registry = load_registry()?;
let operation_number = request.envelope.coordinate.operation_number.clone();
let digest = payload_digest(&request.envelope.payload).unwrap_or_default();
let route = match resolve_route(&registry, &request.envelope.coordinate) {
Ok(route) => route,
Err(error) => {
return response(
&app,
&state,
"ROUTE_REJECTED",
"DENY",
&operation_number,
&digest,
None,
None,
Some(error),
now,
)
}
};
let authority_binding = match enforce_admission(&app, route) {
Ok(binding) => binding,
Err(error) => {
return response(
&app,
&state,
"ADMISSION_REJECTED",
"DENY",
&operation_number,
&digest,
None,
None,
Some(error),
now,
)
}
};
match request.action {
NumberedIpcAction::IssueGrant => {
if request.grant.is_some() {
return bound_response(
&app,
&state,
&authority_binding,
"GRANT_REJECTED",
"DENY",
&operation_number,
&digest,
None,
None,
Some("HOLOLAKE_NUMBERED_IPC_UNEXPECTED_GRANT".into()),
now,
);
}
match issue_grant_at(
&state,
&registry,
&request.envelope,
&authority_binding,
now,
) {
Ok((grant, payload_sha256)) => bound_response(
&app,
&state,
&authority_binding,
"GRANT_ISSUED",
"ALLOW",
&operation_number,
&payload_sha256,
Some(grant),
None,
None,
now,
),
Err(error) => bound_response(
&app,
&state,
&authority_binding,
"GRANT_REJECTED",
"DENY",
&operation_number,
&digest,
None,
None,
Some(error),
now,
),
}
}
NumberedIpcAction::Execute => {
let Some(grant) = request.grant.as_ref() else {
return bound_response(
&app,
&state,
&authority_binding,
"EXECUTION_REJECTED",
"DENY",
&operation_number,
&digest,
None,
None,
Some("HOLOLAKE_NUMBERED_IPC_GRANT_REQUIRED".into()),
now,
);
};
let payload_sha256 = match consume_grant_at(
&state,
&registry,
&request.envelope,
grant,
&authority_binding,
now,
) {
Ok(payload_sha256) => payload_sha256,
Err(error) => {
return bound_response(
&app,
&state,
&authority_binding,
"EXECUTION_REJECTED",
"DENY",
&operation_number,
&digest,
None,
None,
Some(error),
now,
)
}
};
match crate::numbered_ipc_dispatch::dispatch(
app.clone(),
&route.handler,
request.envelope.payload,
)
.await
{
Ok(result) => bound_response(
&app,
&state,
&authority_binding,
"EXECUTED",
"ALLOW",
&operation_number,
&payload_sha256,
None,
Some(result),
None,
now_unix_ms(),
),
Err(error) => bound_response(
&app,
&state,
&authority_binding,
"HANDLER_REJECTED",
"DENY",
&operation_number,
&payload_sha256,
None,
None,
Some(error),
now_unix_ms(),
),
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn envelope_for(route: &OperationRoute, payload: Value) -> NumberedEnvelope {
NumberedEnvelope {
coordinate: NumberedCoordinate {
protocol_version: "HLP-NIPC-v1".into(),
caller_number: "HLP-NIPC-CALLER-MAIN-WEBVIEW-0001".into(),
channel_number: route.channel_number.clone(),
module_number: route.module_number.clone(),
operation_number: route.operation_number.clone(),
target_number: route.target_number.clone(),
request_nonce: format!("test-{}", Uuid::new_v4().simple()),
},
requested_ttl_ms: 1_000,
payload,
}
}
#[test]
fn registry_is_closed_and_contains_every_migrated_command() {
let registry = load_registry().unwrap();
assert_eq!(registry.operations.len(), 147);
assert!(!registry.runtime.legacy_direct_commands_allowed);
}
#[test]
fn route_coordinates_cannot_be_mixed() {
let registry = load_registry().unwrap();
let mut envelope = envelope_for(&registry.operations[0], Value::Null);
envelope.coordinate.target_number = registry.operations[1].target_number.clone();
assert_eq!(
resolve_route(&registry, &envelope.coordinate).unwrap_err(),
"HOLOLAKE_NUMBERED_IPC_ROUTE_COORDINATE_MISMATCH"
);
}
#[test]
fn grant_is_payload_bound_single_use_and_expires() {
let registry = load_registry().unwrap();
let state = NumberedIpcState::default();
let route = registry
.operations
.iter()
.find(|route| route.alias == "confirm_hololake_update_install")
.unwrap();
let envelope = envelope_for(route, serde_json::json!({"input": {"a": 1}}));
let authority = "VERIFIED_HUMAN:ICE_GL:test-user";
let (grant, _) = issue_grant_at(&state, &registry, &envelope, authority, 100).unwrap();
assert!(consume_grant_at(&state, &registry, &envelope, &grant, authority, 101).is_ok());
assert_eq!(
consume_grant_at(&state, &registry, &envelope, &grant, authority, 102).unwrap_err(),
"HOLOLAKE_NUMBERED_IPC_GRANT_UNKNOWN_OR_REPLAYED"
);
let (expired, _) = issue_grant_at(&state, &registry, &envelope, authority, 200).unwrap();
assert_eq!(
consume_grant_at(&state, &registry, &envelope, &expired, authority, 1_201,)
.unwrap_err(),
"HOLOLAKE_NUMBERED_IPC_GRANT_MISMATCH_OR_EXPIRED"
);
let changed = envelope_for(route, serde_json::json!({"input": {"a": 2}}));
let (bound, _) = issue_grant_at(&state, &registry, &changed, authority, 300).unwrap();
let mut tampered = changed.clone();
tampered.payload = serde_json::json!({"input": {"a": 3}});
assert_eq!(
consume_grant_at(&state, &registry, &tampered, &bound, authority, 301).unwrap_err(),
"HOLOLAKE_NUMBERED_IPC_GRANT_MISMATCH_OR_EXPIRED"
);
let (rebound, _) = issue_grant_at(&state, &registry, &envelope, authority, 400).unwrap();
assert_eq!(
consume_grant_at(
&state,
&registry,
&envelope,
&rebound,
"VERIFIED_HUMAN:TCS_GL:other-user",
401,
)
.unwrap_err(),
"HOLOLAKE_NUMBERED_IPC_GRANT_MISMATCH_OR_EXPIRED"
);
}
#[test]
fn payload_outer_shape_is_closed_before_a_grant_is_issued() {
let registry = load_registry().unwrap();
let empty_route = registry
.operations
.iter()
.find(|route| route.alias == "get_hololake_home_status")
.unwrap();
assert!(validate_payload_shape(&registry, empty_route, &serde_json::json!({})).is_ok());
assert_eq!(
validate_payload_shape(
&registry,
empty_route,
&serde_json::json!({"unexpected": true}),
)
.unwrap_err(),
"HOLOLAKE_NUMBERED_IPC_PAYLOAD_FIELD_UNKNOWN"
);
let direct_route = registry
.operations
.iter()
.find(|route| route.alias == "perform_code_repo_login")
.unwrap();
assert!(validate_payload_shape(
&registry,
direct_route,
&serde_json::json!({"username": "u", "password": "p"}),
)
.is_ok());
assert_eq!(
validate_payload_shape(
&registry,
direct_route,
&serde_json::json!({"username": "u", "password": "p", "role": "admin"}),
)
.unwrap_err(),
"HOLOLAKE_NUMBERED_IPC_DIRECT_FIELDS_INVALID"
);
}
}