Skip to content

Commit d520726

Browse files
committed
docs: TrUAPI host permission requirements and compliance audits
Add docs/host-permission-requirements.md covering every TrUAPI method with its authentication, prompt, and permission requirements across four tiers. Add per-host compliance audits (dotli, polkadot-desktop, android, iOS) and a cross-host recap matrix comparing permission enforcement.
1 parent eee5380 commit d520726

6 files changed

Lines changed: 562 additions & 0 deletions
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
# TrUAPI Host Permission Requirements
2+
3+
Every TrUAPI method falls into one of four permission tiers. Hosts **must** enforce the requirements listed below before executing each call.
4+
5+
## Legend
6+
7+
| Column | Meaning |
8+
|--------|---------|
9+
| **Auth** | User must be logged in (`NotConnected` error if not) |
10+
| **Prompt** | Host must show a user-facing confirmation UI before proceeding |
11+
| **Permission type** | Which permission system governs the prompt |
12+
13+
---
14+
15+
## 1. No permission required
16+
17+
These methods work without login and without any user prompt.
18+
19+
| Method | Notes |
20+
|--------|-------|
21+
| `host_handshake` | Protocol negotiation |
22+
| `host_feature_supported` | Capability query |
23+
| `host_local_storage_read` | Product-scoped storage |
24+
| `host_local_storage_write` | Product-scoped storage |
25+
| `host_local_storage_clear` | Product-scoped storage |
26+
| `host_theme_subscribe` | UI theming |
27+
| `host_account_connection_status_subscribe` | Read-only status |
28+
| `host_request_login` | Presents login UI (user controls outcome) |
29+
| `remote_chain_head_follow_subscribe` | Read-only chain data |
30+
| `remote_chain_head_header` | Read-only chain data |
31+
| `remote_chain_head_body` | Read-only chain data |
32+
| `remote_chain_head_storage` | Read-only chain data |
33+
| `remote_chain_head_call` | Read-only chain data |
34+
| `remote_chain_head_unpin` | Read-only chain data |
35+
| `remote_chain_head_continue` | Read-only chain data |
36+
| `remote_chain_head_stop_operation` | Read-only chain data |
37+
| `remote_chain_spec_genesis_hash` | Read-only chain data |
38+
| `remote_chain_spec_chain_name` | Read-only chain data |
39+
| `remote_chain_spec_properties` | Read-only chain data |
40+
| `remote_statement_store_subscribe` | Read-only statement data |
41+
| `remote_preimage_lookup_subscribe` | Read-only preimage data |
42+
43+
---
44+
45+
## 2. Authentication required (no additional prompt)
46+
47+
User must be logged in. The host does **not** show a separate permission prompt — access is granted to any authenticated product.
48+
49+
| Method | Error on no auth |
50+
|--------|------------------|
51+
| `host_account_get` | `NotConnected` / `Rejected` |
52+
| `host_account_get_alias` | `NotConnected` / `Rejected` |
53+
| `host_account_create_proof` | `NotConnected` / `Rejected` |
54+
| `host_derive_entropy` | `Unknown` |
55+
| `host_get_legacy_accounts` | `Rejected` |
56+
| `host_chat_list_subscribe` | Requires active session |
57+
| `host_chat_action_subscribe` | Requires active session |
58+
| `product_chat_custom_message_render_subscribe` | Requires active session |
59+
| `host_payment_status_subscribe` | `PaymentNotFound` |
60+
61+
---
62+
63+
## 3. Authentication + user confirmation prompt
64+
65+
These methods require login **and** an explicit user-facing prompt before proceeding. The host must present a confirmation UI and return `Rejected` / `PermissionDenied` / `Denied` if the user declines.
66+
67+
### 3a. Signing & transaction confirmation
68+
69+
The host shows the user what is being signed or submitted, and the user approves or rejects.
70+
71+
| Method | Prompt trigger | Error on denial |
72+
|--------|---------------|-----------------|
73+
| `host_create_transaction` | Always — user reviews transaction details | `Rejected` / `PermissionDenied` |
74+
| `host_create_transaction_with_legacy_account` | Always — user reviews transaction details | `Rejected` / `PermissionDenied` |
75+
| `host_sign_raw` | Always — user reviews payload | `Rejected` / `PermissionDenied` |
76+
| `host_sign_payload` | Always — user reviews extrinsic payload | `Rejected` / `PermissionDenied` |
77+
| `host_sign_raw_with_legacy_account` | Always — user reviews payload | `Rejected` / `PermissionDenied` |
78+
| `host_sign_payload_with_legacy_account` | Always — user reviews extrinsic payload | `Rejected` / `PermissionDenied` |
79+
80+
### 3b. Identity disclosure
81+
82+
| Method | Prompt trigger | Error on denial |
83+
|--------|---------------|-----------------|
84+
| `host_get_user_id` | Always — user approves revealing their primary DotNS name to the product | `PermissionDenied` |
85+
86+
### 3c. Payment confirmation
87+
88+
| Method | Prompt trigger | Error on denial |
89+
|--------|---------------|-----------------|
90+
| `host_payment_balance_subscribe` | First call — user approves balance disclosure | `PermissionDenied` |
91+
| `host_payment_request` | Always — user approves spend | `Rejected` |
92+
| `host_payment_top_up` | Depends on source — host may prompt for `ProductAccount` source | `InsufficientFunds` / `InvalidSource` |
93+
94+
### 3d. Chat room & bot registration
95+
96+
| Method | Prompt trigger | Error on denial |
97+
|--------|---------------|-----------------|
98+
| `host_chat_create_room` | Host may prompt on first room creation | `PermissionDenied` |
99+
| `host_chat_register_bot` | Host may prompt on first bot registration | `PermissionDenied` |
100+
| `host_chat_post_message` | No prompt (already authorized by room creation) | `MessageTooLarge` |
101+
102+
### 3e. Statement store proof creation
103+
104+
| Method | Prompt trigger | Error on denial |
105+
|--------|---------------|-----------------|
106+
| ~~`remote_statement_store_create_proof`~~ | **Deprecated** — use `create_proof_authorized` instead ||
107+
| `remote_statement_store_create_proof_authorized` | No per-call prompt — uses pre-allocated `AutoSigning` allowance from `host_request_resource_allocation` | `UnableToSign` |
108+
109+
---
110+
111+
## 4. Device & remote permissions (RFC 0002)
112+
113+
These permissions use the RFC 0002 permission model: the host prompts once, persists the user's decision indefinitely, and does not re-prompt on subsequent requests.
114+
115+
### 4a. Explicit permission requests
116+
117+
Products may pre-request permissions; the host shows a one-time prompt.
118+
119+
| Method | Permission |
120+
|--------|------------|
121+
| `host_device_permission` | Requests one `DevicePermission` variant |
122+
| `remote_permission` | Requests one `RemotePermission` variant |
123+
124+
**`DevicePermission` variants:** `Notifications`, `Camera`, `Microphone`, `Bluetooth`, `NFC`, `Location`, `Clipboard`, `OpenUrl`, `Biometrics`
125+
126+
**`RemotePermission` variants:** `Remote { domains }`, `WebRtc`, `ChainSubmit`, `PreimageSubmit`, `StatementSubmit`
127+
128+
### 4b. Implicit permission triggers
129+
130+
These business methods **automatically trigger** a remote permission prompt if the corresponding permission has not been granted yet. The host should prompt for the permission before executing the call.
131+
132+
| Method | Implicitly requires | Error on denial |
133+
|--------|-------------------|-----------------|
134+
| `host_navigate_to` | `DevicePermission::OpenUrl` | `PermissionDenied` |
135+
| `host_push_notification` | `DevicePermission::Notifications` | `Unknown` |
136+
| `host_push_notification_cancel` | `DevicePermission::Notifications` (same grant) | `Unknown` |
137+
| `remote_chain_transaction_broadcast` | `RemotePermission::ChainSubmit` | `GenericError` |
138+
| `remote_chain_transaction_stop` | `RemotePermission::ChainSubmit` (same grant) | `GenericError` |
139+
| `remote_preimage_submit` | `RemotePermission::PreimageSubmit` | `GenericError` |
140+
| `remote_statement_store_submit` | `RemotePermission::StatementSubmit` | `GenericError` |
141+
142+
### 4c. Resource allocation
143+
144+
Pre-allocates capabilities that relax per-call prompts for subsequent operations.
145+
146+
| Method | Notes |
147+
|--------|-------|
148+
| `host_request_resource_allocation` | User approves each `AllocatableResource`. Grants like `AutoSigning` enable `create_proof_authorized` without per-call prompts. Per-resource outcome: `Allocated` / `Rejected` / `NotAvailable`. |
149+
150+
**`AllocatableResource` variants:** `StatementStoreAllowance`, `BulletinAllowance`, `SmartContractAllowance`, `AutoSigning`
151+
152+
---
153+
154+
## Quick reference matrix
155+
156+
| Method | Auth | Prompt | Permission type |
157+
|--------|:----:|:------:|----------------|
158+
| `host_handshake` | | ||
159+
| `host_feature_supported` | | ||
160+
| `host_push_notification` | | | DevicePermission::Notifications |
161+
| `host_push_notification_cancel` | | | DevicePermission::Notifications |
162+
| `host_navigate_to` | | | DevicePermission::OpenUrl |
163+
| `host_device_permission` | | | Explicit prompt |
164+
| `remote_permission` | | | Explicit prompt |
165+
| `host_local_storage_read` | | ||
166+
| `host_local_storage_write` | | ||
167+
| `host_local_storage_clear` | | ||
168+
| `host_account_connection_status_subscribe` | | ||
169+
| `host_account_get` | * | ||
170+
| `host_account_get_alias` | * | ||
171+
| `host_account_create_proof` | * | ||
172+
| `host_get_legacy_accounts` | * | ||
173+
| `host_create_transaction` | * | * | Signing confirmation |
174+
| `host_create_transaction_with_legacy_account` | * | * | Signing confirmation |
175+
| `host_sign_raw_with_legacy_account` | * | * | Signing confirmation |
176+
| `host_sign_payload_with_legacy_account` | * | * | Signing confirmation |
177+
| `host_chat_create_room` | * | * | Chat registration |
178+
| `host_chat_register_bot` | * | * | Chat registration |
179+
| `host_chat_list_subscribe` | * | ||
180+
| `host_chat_post_message` | * | ||
181+
| `host_chat_action_subscribe` | * | ||
182+
| `product_chat_custom_message_render_subscribe` | * | ||
183+
| `remote_statement_store_subscribe` | | ||
184+
| ~~`remote_statement_store_create_proof`~~ | * | * | **Deprecated** |
185+
| `remote_statement_store_create_proof_authorized` | * | | Pre-allocated allowance |
186+
| `remote_statement_store_submit` | | | RemotePermission::StatementSubmit |
187+
| `remote_preimage_lookup_subscribe` | | ||
188+
| `remote_preimage_submit` | | | RemotePermission::PreimageSubmit |
189+
| `remote_chain_head_follow_subscribe` | | ||
190+
| `remote_chain_head_header` | | ||
191+
| `remote_chain_head_body` | | ||
192+
| `remote_chain_head_storage` | | ||
193+
| `remote_chain_head_call` | | ||
194+
| `remote_chain_head_unpin` | | ||
195+
| `remote_chain_head_continue` | | ||
196+
| `remote_chain_head_stop_operation` | | ||
197+
| `remote_chain_spec_genesis_hash` | | ||
198+
| `remote_chain_spec_chain_name` | | ||
199+
| `remote_chain_spec_properties` | | ||
200+
| `remote_chain_transaction_broadcast` | | | RemotePermission::ChainSubmit |
201+
| `remote_chain_transaction_stop` | | | RemotePermission::ChainSubmit |
202+
| `host_theme_subscribe` | | ||
203+
| `host_derive_entropy` | * | ||
204+
| `host_get_user_id` | * | * | Identity disclosure |
205+
| `host_request_login` | | | — (presents login UI) |
206+
| `host_sign_raw` | * | * | Signing confirmation |
207+
| `host_sign_payload` | * | * | Signing confirmation |
208+
| `host_payment_balance_subscribe` | * | * | Balance disclosure |
209+
| `host_payment_top_up` | * | | Source-dependent |
210+
| `host_payment_request` | * | * | Payment confirmation |
211+
| `host_payment_status_subscribe` | * | ||
212+
| `host_request_resource_allocation` | * | * | Per-resource prompt |

dotli-permission-audit.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Dotli Permission Compliance Audit
2+
3+
Comparison of dotli's TrUAPI handler implementations against the [host permission requirements](docs/host-permission-requirements.md).
4+
5+
## Bugs
6+
7+
| Method | Spec requires | Dotli does | Severity |
8+
|--------|--------------|------------|----------|
9+
| `host_navigate_to` | `DevicePermission::OpenUrl` prompt | Auto-granted, no prompt | Medium |
10+
11+
## Auto-granted permissions (documented trade-offs)
12+
13+
These are intentional deviations from the spec, documented in `packages/ui/src/permissions.ts`:
14+
15+
| Permission | Spec requires | Dotli behavior | Reason |
16+
|------------|--------------|----------------|--------|
17+
| `RemotePermission::Remote` | User prompt | Auto-granted | Browser cannot intercept fetch/XHR from inside an iframe |
18+
| `RemotePermission::WebRtc` | User prompt | Auto-granted | Already gated by iframe `allow` attribute |
19+
| `DevicePermission::OpenUrl` | User prompt | Auto-granted | Cross-origin navigation cannot be blocked by the host |
20+
21+
## Correctly implemented
22+
23+
| Method | Auth | Permission | Modal |
24+
|--------|:----:|:----------:|:-----:|
25+
| `host_account_get` | * | | |
26+
| `host_account_get_alias` | * | * | * |
27+
| `host_account_create_proof` | * | | |
28+
| `host_get_user_id` | * | * | |
29+
| `host_create_transaction` | * | * | * |
30+
| `host_create_transaction_with_legacy_account` | * | * | * |
31+
| `host_sign_payload` | * | * | * |
32+
| `host_sign_payload_with_legacy_account` | * | * | * |
33+
| `host_sign_raw` | * | | * |
34+
| `host_sign_raw_with_legacy_account` | * | | * |
35+
| `host_derive_entropy` | * | | |
36+
| `host_request_resource_allocation` | * | | * |
37+
| `host_device_permission` | | * | * |
38+
| `remote_permission` | | * | * |
39+
| `host_request_login` | | | * |
40+
| `host_local_storage_read` | | | |
41+
| `host_local_storage_write` | | | |
42+
| `host_local_storage_clear` | | | |
43+
| `host_theme_subscribe` | | | |
44+
| `host_preimage_lookup_subscribe` | | | |
45+
| `host_push_notification` | | * | |
46+
| `host_push_notification_cancel` | | * | |
47+
| `host_preimage_submit` | | | * |
48+
49+
## Suggested fixes
50+
51+
### 1. `host_navigate_to` auto-granted (Medium)
52+
53+
Auto-granted due to browser limitations (documented trade-off).

0 commit comments

Comments
 (0)