@@ -0,0 +1,312 @@
7+Here we'll look at file permissions.
10+- [Introduction](#introduction)
11+- [%perm](#perm) - Set file permissions.
12+- [%cred](#cred) - Add permission group.
13+- [%crew](#crew) - Get permission groups.
14+- [%crow](#crow) - Get group usage.
18+For each file or directory, there is both a read permission and a write permission. Each may be set separately and is either a whitelist or a blacklist (but not both). The whitelist/blacklist contains a `set` of ships and/or groups which are allowed or banned respectively. If it's an empty whitelist it means all foreign ships are denied. If it's an empty blacklist it means all foreign ships are allowed.
20+If permissions are not set for a particular file, they will be inherited from the directory in which it resides. If *that* directory has no permissions set, they will be inherited from another level up, and so on to the desk's root directory. If the root directory has no permissions set, it will have the default permissions of an empty whitelist, meaning "deny all".
22+A group is called a `crew` and is just a `set` of ships with a `@ta` name.
24+The permissions for each file or directory are a pair of `dict:clay` where the head is read permissions and the tail is write permissions.
26+A `dict:clay` is this structure:
29++$ dict [src=path rul=real] :: effective permission
32+The `src` path is where the permissions were inherited from and the `real` is this structure:
35+ +$ real :: resolved permissions
36+ $: mod=?(%black %white) ::
37+ who=(pair (set ship) (map @ta crew)) ::
41+So if we scry for permissions with a `%p` care, it'll look like:
44+> .^([r=dict:clay w=dict:clay] %cp /===/lib/strandio/hoon)
45+[r=[src=/ rul=[mod=%white who=[p={} q={}]]] w=[src=/ rul=[mod=%white who=[p={} q={}]]]]
48+There are four permission-related tasks which you can pass to clay.
50+A `%perm` task is for setting permissions, and the other three are for managing groups:
52+- `%cred` - add permission group
53+- `%crew` - get permission groups
54+- `%crow` - get group usage
56+We'll look at each of these in turn.
60+This sets permissions for the target file or directory.
62+Note this will replace existing permissions rather than add to them, so if you want to add a ship to an existing whitelist or whatever you'll have to first read the existing permissions, add the ship, then send the whole lot back.
64+A `%perm` tagged `task:clay` looks like:
67+[%perm des=desk pax=path rit=rite] :: change permissions
70+The `pax` path is the file or directory whose permissions you want to change, and the `rite` is this structure:
73++$ rite :: new permissions
74+ $% [%r red=(unit rule)] :: for read
75+ [%w wit=(unit rule)] :: for write
76+ [%rw red=(unit rule) wit=(unit rule)] :: for read and write
79+Where a `rule` is this structure:
82++$ rule [mod=?(%black %white) who=(set whom)] :: node permission
85+...and finally `whom` is this:
88++$ whom (each ship @ta) :: ship or named crew
91+As the comment suggests, the `@ta` is the name of a `crew` (group).
95+Here's a generic thread that just sends the given `task:clay` to clay so we can try a few different things:
97+**`send-clay-task.hoon`**
102+=, strand=strand:spider
107+=/ uarg !< (unit task:clay) arg
109+ (strand-fail:strand %no-arg ~)
111+=/ =card:agent:gall [%pass /foo %arvo %c task]
112+;< ~ bind:m (send-raw-card:strandio card)
116+Save it to `ted/send-clay-task.hoon` and `|commit %home`. Now, let's allow `~nes` to read `/gen/hood/hi/hoon`:
119+> -send-clay-task [%perm %home /gen/hood/hi/hoon %r ~ %white (sy [%.y ~nes]~)]
122+...and we'll do a `%p` scry to see that the permission was set:
125+> .^([r=dict:clay w=dict:clay] %cp /===/gen/hood/hi/hoon)
126+[r=[src=/gen/hood/hi/hoon rul=[mod=%white who=[p={~nes} q={}]]] w=[src=/ rul=[mod=%white who=[p={} q={}]]]]
129+You can see that `~nes` is now in the read whitelist. Next, let's try a write permission:
132+> -send-clay-task [%perm %home /ted %w ~ %white (sy [%.y ~nes]~)]
135+You can see `~nes` can now write to `/ted`:
138+> .^([r=dict:clay w=dict:clay] %cp /===/ted)
139+[r=[src=/ rul=[mod=%white who=[p={} q={}]]] w=[src=/ted rul=[mod=%white who=[p={~nes} q={}]]]]
142+Since we've set it for the whole `/ted` directory, if we check a file inside it we'll see it also has this permission:
145+> .^([r=dict:clay w=dict:clay] %cp /===/ted/aqua/ames/hoon)
146+[r=[src=/ rul=[mod=%white who=[p={} q={}]]] w=[src=/ted rul=[mod=%white who=[p={~nes} q={}]]]]
149+...and you'll notice that `src` tells us it's inherited the rule from `/ted`.
151+Now let's try setting both read and write permissions:
154+> -send-clay-task [%perm %home /gen/help/hoon %rw `[%black (sy [%.y ~nes]~)] `[%white (sy [%.y ~nes]~)]]
158+ .^([r=dict:clay w=dict:clay] %cp /===/gen/help/hoon)
159+[r=[src=/gen/help/hoon rul=[mod=%black who=[p={~nes} q={}]]] w=[src=/gen/help/hoon rul=[mod=%white who=[p={~nes} q={}]]]]
162+Lastly, let's look at deleting a permission rule we've previously set. To do that, we just send a null `(unit rule)` in the `rite`.
164+For example, to remove a read permission (or write if you specify `%w`):
167+> -send-clay-task [%perm %home /gen/help/hoon %r ~]
171+> .^([r=dict:clay w=dict:clay] %cp /===/gen/help/hoon)
172+[r=[src=/ rul=[mod=%white who=[p={} q={}]]] w=[src=/gen/help/hoon rul=[mod=%white who=[p={~nes} q={}]]]]
175+...and to remove both read and write at the same time:
178+> -send-clay-task [%perm %home /gen/help/hoon %rw ~ ~]
182+> .^([r=dict:clay w=dict:clay] %cp /===/gen/help/hoon)
183+[r=[src=/ rul=[mod=%white who=[p={} q={}]]] w=[src=/ rul=[mod=%white who=[p={} q={}]]]]
186+As you can see it's back to the default inherited from `/`.
188+Here's a breakdown of a `%perm` task:
190+
194+This simply creates a permission group. The task looks like this:
197+[%cred nom=@ta cew=crew] :: set permission group
200+The `nom` is a name for the group and the `crew` is just a `(set ship)`:
203++$ crew (set ship) :: permissions group
208+We'll use the same thread from the [%perm](#perm) example. Try:
211+-send-clay-task [%crew 'foo' (sy ~[~zod ~nec ~bud ~wes ~sev])]
214+We'll check it with the next kind of task: [%crew](#crew).
218+This retrieves all permission groups. It looks like:
221+[%crew ~] :: permission groups
224+Clay wil return a sign containing a `gift:clay` with a `%cruz` tag. It looks like:
227+[%cruz cez=(map @ta crew)] :: permission groups
230+The `cez` is just a map from group name to `crew` which is just a `(set ship)`.
234+Here's a generic thread that sends the given `task:clay` and receives a gift which it just prints to the dojo.
236+**`send-task-take-gift.hoon`**
241+=, strand=strand:spider
246+=/ uarg !< (unit task:clay) arg
248+ (strand-fail:strand %no-arg ~)
250+=/ =card:agent:gall [%pass /foo %arvo %c task]
251+;< ~ bind:m (send-raw-card:strandio card)
252+;< res=[wire sign-arvo] bind:m take-sign-arvo:strandio
257+Save the above to `ted/send-task-take-gift.hoon` and `|commit %home`. Now we'll check for the permission group we created in the [%cred](#cred) example:
260+> -send-task-take-gift [%crew ~]
261+[%cruz cez={[p=~.foo q={~nec ~bud ~wes ~zod ~sev}]}]
266+This is the last group task. It retrieves all files and directories in all desks which have permissions set for the group in question. It will not return inherited permissions, only those explicitly set. It looks like:
269+[%crow nom=@ta] :: group usage
272+The `gift:clay` you get back is a `%croz` which looks like:
275+[%croz rus=(map desk [r=regs w=regs])] :: rules for group
278+...where `regs` is this structure:
281++$ regs (map path rule) :: rules for paths
286+First we'll set a couple of permissions for the `foo` group we created in the [%cred](#cred) section using the `send-clay-task.hoon` thread from the [%perm](#perm) section:
289+> -send-clay-task [%perm %home /gen/hood/hi/hoon %w ~ %white (sy [%.n 'foo']~)]
290+> -send-clay-task [%perm %home /ted %w ~ %white (sy [%.n 'foo']~)]
293+Notice we use a `%.n` in the `whom:clay` to indicate a group rather than the `%.y` of a group.
295+Now we'll use the `send-task-take-gift.hoon` thread from the [%crew](#crew) section to try `%crow`:
298+> -send-receive-task [%crow 'foo']
305+ { [p=/gen/hood/hi/hoon q=[mod=%white who={[%.n p=~.foo]}]]
306+ [p=/ted q=[mod=%white who={[%.n p=~.foo]}]]