2 - Granting, Checking and Revoking
The Actual Work: Grant, Check, Revoke
Once a store exists (see 1 - Setting Up A Permission Store), everything is done against a requester ID (the identifier XRUIOS.Manager issued to the app) and a permission name like "Edit Camera Footage".
Permissions are integer levels, not just on/off. A grant stores a number; a check asks "is the stored number at least requiredLevel?" This lets you model tiers (e.g. 1 = view, 5 = edit, 10 = delete) on a single permission name.
var requester = managerIssuedRequesterId; // SecureData from XRUIOS.Manager
var permName = "Edit Camera Footage".ToSecureData();
"Edit Camera Footage". The auto-gating layer in 3 - Auto-Gating Functions (The Attribute) fills both of these in for you.Grant (or overwrite) a permission
The permission value is an int, wrapped in SecureData as its bytes:
var level = new SecureData(BitConverter.GetBytes(5)); // grant at level 5
await handler.HandlePermission(saveDir, permClass, permName, requester, level, appKey);
HandlePermission is an upsert, AKA if the requester doesn't exist yet it's added; if the permission already exists it's overwritten. After it writes, it refreshes the cache with the value it actually wrote (see 1 - How Caching and Rate Limiting Work), so the next check sees the new number immediately.
Check a permission
bool canEdit = await handler.CheckPermission(
saveDir, permClass, permName, requester, appKey,
requiredLevel: 5);
- Stored level
>= requiredLevel→true. - Requester or permission absent →
false. - Store missing / wrong key / corrupted →
false(fail closed), and the error is pushed toHandler.OnStoreErrorso you can tell a real denial apart from a broken store.
requiredLevel defaults to 0. Calling CheckPermission(...) with no level asks "do they have this permission at all (>= 0)?"The important part: because the cache stores the value, checking the same permission at a higher level later is compared honestly. A true at level 3 can not be replayed as a true at level 10.
Change a permission
ChangePermission is a thin, clearly-named wrapper over `HandlePermission; it reads better at call sites where you're deliberately downgrading/upgrading:
var newLevel = new SecureData(BitConverter.GetBytes(1)); // drop to level 1
await handler.ChangePermission(saveDir, permClass, permName, requester, appKey, newLevel);
The next CheckPermission reflects the new value right away — there's no stale "granted" left in the cache.
Remove a single permission
await handler.RemovePermission(saveDir, permClass, permName, requester, appKey);
Throws KeyNotFoundException if the requester or that specific permission doesn't exist, and evicts just that one cache entry.
Remove a requester entirely
Drops the app/requester and all its permissions in one go:
await handler.RemoveRequester(saveDir, permClass, requester, appKey);
RemoveRequester does not take a permission name — it removes the whole requester. (Older code took an unused permission-name argument; it's gone.) It also precisely evicts every cache entry belonging to that requester, not the whole cache.Quick reference
| Call | Effect |
|---|---|
SetupPermFile |
Create the store (once) |
PermissionFileExists |
Does the store exist? |
HandlePermission |
Grant / overwrite a permission (upsert) |
ChangePermission |
Same as above, named for intent |
CheckPermission |
Is requester allowed at requiredLevel? |
RemovePermission |
Remove one permission from one requester |
RemoveRequester |
Remove a requester and all its permissions |