nx_share_consent.nx source
↩ module page · 134 lines · 7104 B
1// nx_share_consent.nx -- PRIVACY / CONSENT ON SHARES (sharing ring rung 3; frontier momentum 170). The ACL
2// discipline applied to the share plane, DENY-BY-DEFAULT:
3// SHARE-CONSENT: a share lands ONLY if the recipient consented -- by PERSON ("Dana may share anything with me"),
4// by CONTEXT ("professional contacts may share jobs"), or wildcard -- SCOPED by item type, with explicit BLOCKS
5// OUTRANKING every allow. No record = DENY (privacy by default, the exact inverse of every social feed).
6// INTRO-CONSENT: an intro exposes a THIRD party -- introducing Priya shares Priya. So intros ALSO require the
7// SUBJECT's own standing consent to be introduced. Both sides must say yes or nothing moves.
8// Consent policy = additive records (person | from-or-"ctx:<context>"-or-* | allow/block | scope-itype-or-*) --
9// data, not code; the share layer (nx_share/serve) MUST call sc_check (+ sc_intro_ok for intros) BEFORE sh_save.
10// Pure logic + selftest gate (argless): a 7-check matrix incl. block-outranks-context and third-party intro consent.
11// license_tier: ORIGINAL expect_exit: 0
12import "nx_syscalls.nx"
13
14func slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
15func p(s: *u8) -> i64 { sys_write(1, s, slen(s)); return 0 }
16func pn(v: i64) -> i64 {
17 var m: i64 = v; if m < 0 { p("-" as *u8); m = 0 - m }
18 let t: *u8 = sys_mmap(24); var k: i64 = 0; if m == 0 { t[0] = 48 as u8; k = 1 }
19 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
20 let o: *u8 = sys_mmap(24); var i: i64 = 0; while i < k { o[i] = t[k-1-i]; i = i + 1 } sys_write(1, o, k); return 0
21}
22func seq(a: *u8, b: *u8) -> i64 {
23 var i: i64 = 0
24 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 }
25 if b[i] != (0 as u8) { return 0 }
26 return 1
27}
28// does the from-pattern match? pat = exact person | "ctx:<context>" | "*"
29func sc_from_match(pat: *u8, from: *u8, fromctx: *u8) -> i64 {
30 if seq(pat, "*" as *u8) == 1 { return 1 }
31 if seq(pat, from) == 1 { return 1 }
32 // "ctx:" prefix?
33 if pat[0] == (99 as u8) { if pat[1] == (116 as u8) { if pat[2] == (120 as u8) { if pat[3] == (58 as u8) {
34 let sub: *u8 = (pat as i64 + 4) as *u8
35 if seq(sub, fromctx) == 1 { return 1 }
36 } } } }
37 return 0
38}
39// policy ctx bundle: [0]=cw persons *i64, [1]=cf from-patterns *i64, [2]=ck kinds *i64 (1 allow/0 block),
40// [3]=cs scopes *i64, [4]=n
41// DENY-BY-DEFAULT; explicit BLOCK on (from) outranks every allow.
42func sc_check(pol: *i64, from: *u8, to: *u8, itype: *u8, fromctx: *u8) -> i64 {
43 let cw: *i64 = pol[0] as *i64
44 let cf: *i64 = pol[1] as *i64
45 let ck: *i64 = pol[2] as *i64
46 let cs: *i64 = pol[3] as *i64
47 let n: i64 = pol[4]
48 // pass 1: blocks outrank
49 var i: i64 = 0
50 while i < n {
51 if seq(cw[i] as *u8, to) == 1 {
52 if ck[i] == 0 { if sc_from_match(cf[i] as *u8, from, fromctx) == 1 { return 0 } }
53 }
54 i = i + 1
55 }
56 // pass 2: any covering allow
57 i = 0
58 while i < n {
59 if seq(cw[i] as *u8, to) == 1 {
60 if ck[i] == 1 {
61 if sc_from_match(cf[i] as *u8, from, fromctx) == 1 {
62 let sc: *u8 = cs[i] as *u8
63 if seq(sc, "*" as *u8) == 1 { return 1 }
64 if seq(sc, itype) == 1 { return 1 }
65 }
66 }
67 }
68 i = i + 1
69 }
70 // deny by default
71 return 0
72}
73// intro third-party consent: the SUBJECT must hold a standing allow with scope "intro"
74func sc_intro_ok(pol: *i64, subject: *u8) -> i64 {
75 let cw: *i64 = pol[0] as *i64
76 let ck: *i64 = pol[2] as *i64
77 let cs: *i64 = pol[3] as *i64
78 let n: i64 = pol[4]
79 var i: i64 = 0
80 while i < n {
81 if seq(cw[i] as *u8, subject) == 1 {
82 if ck[i] == 1 { if seq(cs[i] as *u8, "intro" as *u8) == 1 { return 1 } }
83 }
84 i = i + 1
85 }
86 return 0
87}
88func sc_say(label: *u8, got: i64, want: i64) -> i64 {
89 p(" SHARE-CONSENT " as *u8); p(label)
90 if got == 1 { p(" -> ALLOW" as *u8) } else { p(" -> DENY" as *u8) }
91 if got == want { p("\n" as *u8); return 1 }
92 p(" (WRONG)\n" as *u8)
93 return 0
94}
95
96func main() -> i64 {
97 p("=== NX-SHARE-CONSENT SELFTEST (deny-by-default; blocks outrank; scoped; INTRO needs the SUBJECT's consent) ===\n" as *u8)
98 var ok: i64 = 1
99 // Emma's policy: professional contacts may share JOBS; Dana may share anything; Spam Sam is blocked.
100 // Priya starts WITHOUT intro consent.
101 let cw: *i64 = sys_mmap(8 * 8) as *i64
102 let cf: *i64 = sys_mmap(8 * 8) as *i64
103 let ck: *i64 = sys_mmap(8 * 8) as *i64
104 let cs: *i64 = sys_mmap(8 * 8) as *i64
105 cw[0]="Emma" as *u8 as i64; cf[0]="ctx:professional" as *u8 as i64; ck[0]=1; cs[0]="job" as *u8 as i64
106 cw[1]="Emma" as *u8 as i64; cf[1]="Dana" as *u8 as i64; ck[1]=1; cs[1]="*" as *u8 as i64
107 cw[2]="Emma" as *u8 as i64; cf[2]="Spam Sam" as *u8 as i64; ck[2]=0; cs[2]="*" as *u8 as i64
108 let pol: *i64 = sys_mmap(8 * 8) as *i64
109 pol[0]=cw as i64; pol[1]=cf as i64; pol[2]=ck as i64; pol[3]=cs as i64; pol[4]=3
110
111 if sc_say("Marcus(professional) shares JOB to Emma" as *u8, sc_check(pol, "Marcus" as *u8, "Emma" as *u8, "job" as *u8, "professional" as *u8), 1) == 0 { ok = 0 }
112 if sc_say("Marcus(professional) shares RESOURCE (scope=job only)" as *u8, sc_check(pol, "Marcus" as *u8, "Emma" as *u8, "resource" as *u8, "professional" as *u8), 0) == 0 { ok = 0 }
113 if sc_say("Dana shares RESOURCE (person-allow, scope *)" as *u8, sc_check(pol, "Dana" as *u8, "Emma" as *u8, "resource" as *u8, "personal" as *u8), 1) == 0 { ok = 0 }
114 if sc_say("Spam Sam(professional) shares JOB -- BLOCK outranks context-allow" as *u8, sc_check(pol, "Spam Sam" as *u8, "Emma" as *u8, "job" as *u8, "professional" as *u8), 0) == 0 { ok = 0 }
115 if sc_say("stranger Zed(community), no record -- default" as *u8, sc_check(pol, "Zed" as *u8, "Emma" as *u8, "job" as *u8, "community" as *u8), 0) == 0 { ok = 0 }
116
117 // intro: recipient consent (Dana->Emma ok) is NOT enough -- Priya (the subject) must consent too
118 let rec_ok: i64 = sc_check(pol, "Dana" as *u8, "Emma" as *u8, "intro" as *u8, "personal" as *u8)
119 let sub1: i64 = sc_intro_ok(pol, "Priya" as *u8)
120 p(" SHARE-CONSENT intro Dana->Emma about Priya: recipient=" as *u8); pn(rec_ok); p(" subject-consent=" as *u8); pn(sub1); p(" -> DENY (third party has not consented)\n" as *u8)
121 if rec_ok != 1 { ok = 0 }
122 if sub1 != 0 { ok = 0 }
123 // Priya grants standing intro consent -> now both sides say yes
124 cw[3]="Priya" as *u8 as i64; cf[3]="*" as *u8 as i64; ck[3]=1; cs[3]="intro" as *u8 as i64
125 pol[4]=4
126 let sub2: i64 = sc_intro_ok(pol, "Priya" as *u8)
127 p(" SHARE-CONSENT after Priya's standing intro-consent: subject-consent=" as *u8); pn(sub2); p(" -> ALLOW\n" as *u8)
128 if sub2 != 1 { ok = 0 }
129
130 p("NX-SHARE-CONSENT-SELFTEST checks=7 " as *u8)
131 if ok == 1 { p("verdict=GREEN (privacy by default: no consent, no share; intros need BOTH sides)\n" as *u8); return 0 }
132 p("verdict=RED\n" as *u8)
133 return 1
134}