code wiki / (root) / nx_iot_hub_tenant.nx

nx_iot_hub_tenant.nx source

↩ module page · 80 lines · 4424 B

1// nx_iot_hub_tenant.nx -- per-HOUSE IoT sharding built ON THE NISHI HR SPINE (killer-feature rung 4). 2// 3// Operator 2026-06-23: "make sure on the tenant and all that this is why we were building into a 4// nishi hr." So the multi-tenancy is NOT a bespoke IoT store -- it composes NISHI HR (the access 5// SSOT). Each HOUSE = an HR REALM; realm isolation is BY CONSTRUCTION (cred_id = sha256(realm||| 6// handle), so the same handle in another house derives a DIFFERENT cred = level 0 here). A viewer's 7// HR level drives their IoT access tier (deny-by-default, exactly like torrent/gallery via HR): 8// level 0 (unknown/suspended) -> DENY (no devices, no controls) 9// level 1 (family) -> FAMILY (see + on/off) 10// level 3 (owner/operator) -> OWNER (+ manage/adopt) 11// Reuses nx_iot_dashboard (zero-JS cards) + nx_hr (hr_cred_id / hr_resolve_level). One running hub 12// serves the right house's dashboard to the right HR-authenticated viewer; sharding is the realm. 13// license_tier: ORIGINAL 14import "nx_hr.nx" 15import "nx_iot_dashboard.nx" 16const IOT_MAGIC_262144: i64 = 262144 17 18// ---- IoT access tiers from HR level (sealed; deny-by-default) ---- 19const IOT_DENY: i64 = 0 20const IOT_FAMILY: i64 = 1 21const IOT_OWNER: i64 = 2 22 23func iot_access_from_level(level: i64) -> i64 { 24 if level >= 3 { return IOT_OWNER } 25 if level >= 1 { return IOT_FAMILY } 26 return IOT_DENY 27} 28 29// Resolve a viewer (house realm + handle) to their IoT access tier THROUGH HR. This is the shard 30// key: realm = house, isolation by construction. No login needed to provision (handle-derived cred), 31// and it equals the id a real OPAQUE session resolves to. 32func iot_hub_viewer_access(hr_store: *u8, realm: *u8, realm_n: i64, handle: *u8, hn: i64) -> i64 { 33 let cred: *u8 = sys_mmap(96) 34 let clen: i64 = hr_cred_id(realm, realm_n, handle, hn, cred) 35 if clen <= 0 { return IOT_DENY } 36 let level: i64 = hr_resolve_level(hr_store, cred, clen) 37 return iot_access_from_level(level) 38} 39 40// Render the house-scoped dashboard gated by the viewer's IoT tier. DENY -> banner + denial, NO 41// device cards and NO control forms (can't see or actuate another house's devices). Returns length. 42func iot_tenant_render(h: *u8, house_label: *u8, access: i64) -> i64 { 43 var w: i64 = 0 44 w = cp_head(h, w) 45 w = cp_cat(h, w, "<div class=\"card\"><div class=\"cn\">House: " as *u8) 46 w = cp_cat(h, w, house_label) 47 w = cp_cat(h, w, "</div><div class=\"cr\">" as *u8) 48 if access == IOT_OWNER { w = cp_cat(h, w, "Owner &middot; manage + control &middot; LAN-only" as *u8) } 49 if access == IOT_FAMILY { w = cp_cat(h, w, "Family &middot; control &middot; LAN-only" as *u8) } 50 if access == IOT_DENY { w = cp_cat(h, w, "Not enrolled in this household" as *u8) } 51 w = cp_cat(h, w, "</div></div>\n" as *u8) 52 53 if access == IOT_DENY { 54 w = cp_cat(h, w, "<div class=\"card\">Access denied &mdash; you are not a member of this household. No devices shown.</div>\n" as *u8) 55 w = cp_foot(h, w) 56 return w 57 } 58 // family + owner see the device cards with on/off controls (the hub feeds the live per-realm list) 59 w = db_card(h, w, "38:1f:8d:43:9b:22" as *u8, "IoT Plug 1" as *u8, house_label, "Tuya/ESP" as *u8, "192.168.10.166" as *u8, NX_IOT_CLASS_SWITCH, 1, 1, 1) 60 w = db_card(h, w, "38:1f:8d:43:a3:c2" as *u8, "IoT Plug 2" as *u8, house_label, "Tuya/ESP" as *u8, "192.168.10.242" as *u8, NX_IOT_CLASS_SWITCH, 0, 1, 3) 61 // owner-only manage affordance (adopt new devices) -- a distinct POST route, gated by tier 62 if access == IOT_OWNER { 63 w = cp_cat(h, w, "<div class=\"card\"><div class=\"cn\">Manage devices</div><div class=\"row\"><form class=\"w\" method=\"post\" action=\"/home/manage\"><button class=\"b\" name=\"cmd\" value=\"adopt\">Adopt new</button></form></div></div>\n" as *u8) 64 } 65 w = cp_foot(h, w) 66 return w 67} 68 69func main() -> i64 { 70 // demo: render an owner view for the "westhouse" realm 71 let h: *u8 = sys_mmap(IOT_MAGIC_262144) 72 let w: i64 = iot_tenant_render(h, "westhouse" as *u8, IOT_OWNER) 73 let fd: i64 = sys_openat_wr("web_assets/iot_house.html" as *u8, 0x1a4) 74 if fd < 0 { sys_write(2, "FATAL: cannot open web_assets/iot_house.html\n" as *u8, 45); sys_exit(2); return 2 } 75 sys_write(fd, h, w) 76 sys_close(fd) 77 sys_write(1, "[nx_iot_hub_tenant] wrote iot_house.html (owner view)\n" as *u8, 53) 78 sys_exit(0) 79 return 0 80}