Attenuate authority in secure chat

This commit is contained in:
Tony Garnock-Jones 2021-04-16 22:36:34 +02:00
parent 8b460a2f1c
commit a865a2dddd
4 changed files with 247 additions and 20 deletions

View File

@ -26,8 +26,10 @@ CDict = <dict>.
Lit = <lit @value any>.
Pattern = PDiscard / PBind / PAnd / PNot / Lit / PCompound .
Pattern = PDiscard / PAtom / PPointer / PBind / PAnd / PNot / Lit / PCompound .
PDiscard = <_>.
PAtom = =Boolean / =Float / =Double / =SignedInteger / =String / =ByteString / =Symbol .
PPointer = =Pointer .
PBind = <bind @name symbol @pattern Pattern>.
PAnd = <and [@patterns Pattern ...]>.
PNot = <not @pattern Pattern>.

View File

@ -1,6 +1,14 @@
import * as _ from "@preserves/core";
import * as _i_Actor from "../actor";
export const $Boolean = Symbol.for("Boolean");
export const $ByteString = Symbol.for("ByteString");
export const $Double = Symbol.for("Double");
export const $Float = Symbol.for("Float");
export const $Pointer = Symbol.for("Pointer");
export const $SignedInteger = Symbol.for("SignedInteger");
export const $String = Symbol.for("String");
export const $Symbol = Symbol.for("Symbol");
export const $_ = Symbol.for("_");
export const $and = Symbol.for("and");
export const $arr = Symbol.for("arr");
@ -50,6 +58,8 @@ export type Lit = {"value": _val};
export type Pattern = (
{"_variant": "PDiscard", "value": PDiscard} |
{"_variant": "PAtom", "value": PAtom} |
{"_variant": "PPointer", "value": PPointer} |
{"_variant": "PBind", "value": PBind} |
{"_variant": "PAnd", "value": PAnd} |
{"_variant": "PNot", "value": PNot} |
@ -59,6 +69,18 @@ export type Pattern = (
export type PDiscard = null;
export type PAtom = (
{"_variant": "Boolean"} |
{"_variant": "Float"} |
{"_variant": "Double"} |
{"_variant": "SignedInteger"} |
{"_variant": "String"} |
{"_variant": "ByteString"} |
{"_variant": "Symbol"}
);
export type PPointer = null;
export type PBind = {"name": symbol, "pattern": Pattern};
export type PAnd = {"patterns": Array<Pattern>};
@ -117,6 +139,8 @@ export function Lit(value: _val): Lit {return {"value": value};}
export namespace Pattern {
export function PDiscard(value: PDiscard): Pattern {return {"_variant": "PDiscard", "value": value};};
export function PAtom(value: PAtom): Pattern {return {"_variant": "PAtom", "value": value};};
export function PPointer(value: PPointer): Pattern {return {"_variant": "PPointer", "value": value};};
export function PBind(value: PBind): Pattern {return {"_variant": "PBind", "value": value};};
export function PAnd(value: PAnd): Pattern {return {"_variant": "PAnd", "value": value};};
export function PNot(value: PNot): Pattern {return {"_variant": "PNot", "value": value};};
@ -126,6 +150,18 @@ export namespace Pattern {
export function PDiscard(): PDiscard {return null;}
export namespace PAtom {
export function Boolean(): PAtom {return {"_variant": "Boolean"};};
export function Float(): PAtom {return {"_variant": "Float"};};
export function Double(): PAtom {return {"_variant": "Double"};};
export function SignedInteger(): PAtom {return {"_variant": "SignedInteger"};};
export function String(): PAtom {return {"_variant": "String"};};
export function ByteString(): PAtom {return {"_variant": "ByteString"};};
export function Symbol(): PAtom {return {"_variant": "Symbol"};};
}
export function PPointer(): PPointer {return null;}
export function PBind({name, pattern}: {name: symbol, pattern: Pattern}): PBind {return {"name": name, "pattern": pattern};}
export function PAnd(patterns: Array<Pattern>): PAnd {return {"patterns": patterns};}
@ -465,25 +501,35 @@ export function toPattern(v: _val): undefined | Pattern {
_tmp0 = toPDiscard(v);
if (_tmp0 !== void 0) {result = {"_variant": "PDiscard", "value": _tmp0};};
if (result === void 0) {
let _tmp1: (PBind) | undefined;
_tmp1 = toPBind(v);
if (_tmp1 !== void 0) {result = {"_variant": "PBind", "value": _tmp1};};
let _tmp1: (PAtom) | undefined;
_tmp1 = toPAtom(v);
if (_tmp1 !== void 0) {result = {"_variant": "PAtom", "value": _tmp1};};
if (result === void 0) {
let _tmp2: (PAnd) | undefined;
_tmp2 = toPAnd(v);
if (_tmp2 !== void 0) {result = {"_variant": "PAnd", "value": _tmp2};};
let _tmp2: (PPointer) | undefined;
_tmp2 = toPPointer(v);
if (_tmp2 !== void 0) {result = {"_variant": "PPointer", "value": _tmp2};};
if (result === void 0) {
let _tmp3: (PNot) | undefined;
_tmp3 = toPNot(v);
if (_tmp3 !== void 0) {result = {"_variant": "PNot", "value": _tmp3};};
let _tmp3: (PBind) | undefined;
_tmp3 = toPBind(v);
if (_tmp3 !== void 0) {result = {"_variant": "PBind", "value": _tmp3};};
if (result === void 0) {
let _tmp4: (Lit) | undefined;
_tmp4 = toLit(v);
if (_tmp4 !== void 0) {result = {"_variant": "Lit", "value": _tmp4};};
let _tmp4: (PAnd) | undefined;
_tmp4 = toPAnd(v);
if (_tmp4 !== void 0) {result = {"_variant": "PAnd", "value": _tmp4};};
if (result === void 0) {
let _tmp5: (PCompound) | undefined;
_tmp5 = toPCompound(v);
if (_tmp5 !== void 0) {result = {"_variant": "PCompound", "value": _tmp5};};
let _tmp5: (PNot) | undefined;
_tmp5 = toPNot(v);
if (_tmp5 !== void 0) {result = {"_variant": "PNot", "value": _tmp5};};
if (result === void 0) {
let _tmp6: (Lit) | undefined;
_tmp6 = toLit(v);
if (_tmp6 !== void 0) {result = {"_variant": "Lit", "value": _tmp6};};
if (result === void 0) {
let _tmp7: (PCompound) | undefined;
_tmp7 = toPCompound(v);
if (_tmp7 !== void 0) {result = {"_variant": "PCompound", "value": _tmp7};};
};
};
};
};
};
@ -495,6 +541,8 @@ export function toPattern(v: _val): undefined | Pattern {
export function fromPattern(_v: Pattern): _val {
switch (_v._variant) {
case "PDiscard": {return fromPDiscard(_v.value);};
case "PAtom": {return fromPAtom(_v.value);};
case "PPointer": {return fromPPointer(_v.value);};
case "PBind": {return fromPBind(_v.value);};
case "PAnd": {return fromPAnd(_v.value);};
case "PNot": {return fromPNot(_v.value);};
@ -521,6 +569,78 @@ export function toPDiscard(v: _val): undefined | PDiscard {
export function fromPDiscard(_v: PDiscard): _val {return _.Record($_, []);}
export function asPAtom(v: _val): PAtom {
let result = toPAtom(v);
if (result === void 0) throw new TypeError(`Invalid PAtom: ${_.stringify(v)}`);
return result;
}
export function toPAtom(v: _val): undefined | PAtom {
let _tmp0: (null) | undefined;
let result: undefined | PAtom;
_tmp0 = _.is(v, $Boolean) ? null : void 0;
if (_tmp0 !== void 0) {result = {"_variant": "Boolean"};};
if (result === void 0) {
let _tmp1: (null) | undefined;
_tmp1 = _.is(v, $Float) ? null : void 0;
if (_tmp1 !== void 0) {result = {"_variant": "Float"};};
if (result === void 0) {
let _tmp2: (null) | undefined;
_tmp2 = _.is(v, $Double) ? null : void 0;
if (_tmp2 !== void 0) {result = {"_variant": "Double"};};
if (result === void 0) {
let _tmp3: (null) | undefined;
_tmp3 = _.is(v, $SignedInteger) ? null : void 0;
if (_tmp3 !== void 0) {result = {"_variant": "SignedInteger"};};
if (result === void 0) {
let _tmp4: (null) | undefined;
_tmp4 = _.is(v, $String) ? null : void 0;
if (_tmp4 !== void 0) {result = {"_variant": "String"};};
if (result === void 0) {
let _tmp5: (null) | undefined;
_tmp5 = _.is(v, $ByteString) ? null : void 0;
if (_tmp5 !== void 0) {result = {"_variant": "ByteString"};};
if (result === void 0) {
let _tmp6: (null) | undefined;
_tmp6 = _.is(v, $Symbol) ? null : void 0;
if (_tmp6 !== void 0) {result = {"_variant": "Symbol"};};
};
};
};
};
};
};
return result;
}
export function fromPAtom(_v: PAtom): _val {
switch (_v._variant) {
case "Boolean": {return $Boolean;};
case "Float": {return $Float;};
case "Double": {return $Double;};
case "SignedInteger": {return $SignedInteger;};
case "String": {return $String;};
case "ByteString": {return $ByteString;};
case "Symbol": {return $Symbol;};
};
}
export function asPPointer(v: _val): PPointer {
let result = toPPointer(v);
if (result === void 0) throw new TypeError(`Invalid PPointer: ${_.stringify(v)}`);
return result;
}
export function toPPointer(v: _val): undefined | PPointer {
let _tmp0: (null) | undefined;
let result: undefined | PPointer;
_tmp0 = _.is(v, $Pointer) ? null : void 0;
if (_tmp0 !== void 0) {result = _tmp0;};
return result;
}
export function fromPPointer(_v: PPointer): _val {return $Pointer;}
export function asPBind(v: _val): PBind {
let result = toPBind(v);
if (result === void 0) throw new TypeError(`Invalid PBind: ${_.stringify(v)}`);

View File

@ -1,7 +1,7 @@
import type { Assertion, Handle, Ref, Turn } from "./actor.js";
import { Dictionary, IdentityMap, is, Record, Tuple } from "@preserves/core";
import { Bytes, Dictionary, DoubleFloat, IdentityMap, is, isPointer, Record, SingleFloat, Tuple } from "@preserves/core";
import { Alts, Attenuation, Caveat, PBind, Pattern, Rewrite, TRef, Template } from './gen/sturdy.js';
import { Alts, Attenuation, Caveat, PBind, Pattern, Rewrite, TRef, Template, _val, PCompound, ConstructorSpec, CRec, PCompoundMembers, Lit, PPointer, PAtom, CArr, CDict, PNot, PAnd } from './gen/sturdy.js';
export * from './gen/sturdy.js';
export type Bindings = { [name: string]: Assertion };
@ -13,6 +13,18 @@ export function match(p: Pattern, v: Assertion): Bindings | null {
switch (p._variant) {
case 'PDiscard':
return true;
case 'PAtom':
switch (p.value._variant) {
case 'Boolean': return typeof v === 'boolean';
case 'ByteString': return Bytes.isBytes(v);
case 'Double': return DoubleFloat.isDouble(v);
case 'Float': return SingleFloat.isSingle(v);
case 'SignedInteger': return typeof v === 'number';
case 'String': return typeof v === 'string';
case 'Symbol': return typeof v === 'symbol';
}
case 'PPointer':
return isPointer(v);
case 'PBind':
if (walk(p.value.pattern, v)) {
bindings[p.value.name.asPreservesText()] = v;
@ -65,6 +77,9 @@ export function match(p: Pattern, v: Assertion): Bindings | null {
return true;
}
}
default:
((_p : never) => {})(p);
return false;
}
}
@ -158,6 +173,7 @@ export function rfilter(... patterns: Pattern[]): Caveat {
}
export function attenuate(ref: Ref, ... a: Attenuation): Ref {
if (a.length === 0) return ref;
return { ... ref, attenuation: [... a, ... (ref.attenuation ?? [])] };
}
@ -191,3 +207,71 @@ export function forwarder(t: Turn, ref: Ref): { proxy: Ref, revoker: Ref } {
});
return { proxy, revoker };
}
export function pRec(label: _val, ... members: Array<Pattern>): Pattern {
return Pattern.PCompound(PCompound({
ctor: ConstructorSpec.CRec(CRec({ label: label, arity: members.length })),
members: PCompoundMembers(new Dictionary<Ref, Pattern>(
members.map((p, i) => [i, p] as const).filter(e => e[1]._variant !== 'PDiscard')))}));
}
export function pArr(... members: Array<Pattern>): Pattern {
return Pattern.PCompound(PCompound({
ctor: ConstructorSpec.CArr(CArr(members.length)),
members: PCompoundMembers(new Dictionary<Ref, Pattern>(
members.map((p, i) => [i, p] as const).filter(e => e[1]._variant !== 'PDiscard')))}));
}
export function pDict(... entries: [_val, Pattern][]): Pattern {
return Pattern.PCompound(PCompound({
ctor: ConstructorSpec.CDict(CDict()),
members: PCompoundMembers(new Dictionary<Ref, Pattern>(entries))}));
}
export function pLit(value: _val): Pattern {
return Pattern.Lit(Lit(value));
}
export function pNot(p: Pattern): Pattern {
return Pattern.PNot(PNot(p));
}
export function pAnd(... ps: Pattern[]): Pattern {
return Pattern.PAnd(PAnd(ps));
}
export function pBind(name: symbol, pattern: Pattern): Pattern {
return Pattern.PBind(PBind({ name, pattern }));
}
export function pPointer(): Pattern {
return Pattern.PPointer(PPointer());
}
export function pSymbol(): Pattern {
return Pattern.PAtom(PAtom.Symbol());
}
export function pByteString(): Pattern {
return Pattern.PAtom(PAtom.ByteString());
}
export function pString(): Pattern {
return Pattern.PAtom(PAtom.String());
}
export function pSignedInteger(): Pattern {
return Pattern.PAtom(PAtom.SignedInteger());
}
export function pDouble(): Pattern {
return Pattern.PAtom(PAtom.Double());
}
export function pFloat(): Pattern {
return Pattern.PAtom(PAtom.Float());
}
export function pBoolean(): Pattern {
return Pattern.PAtom(PAtom.Boolean());
}

View File

@ -1,6 +1,20 @@
import { $claimNick, $joinedUser, asNickClaim, fromJoin, fromNickConflict, fromUserInfo, Join, NickConflict, UserId, UserInfo } from "./gen/secure-chat-protocol.js";
import {
$claimNick,
$joinedUser,
$says,
$user,
Join,
NickConflict,
UserId,
UserInfo,
asNickClaim,
fromJoin,
fromNickConflict,
fromUserInfo,
} from "./gen/secure-chat-protocol.js";
import { Assertion, Handle, Ref, Turn } from "./actor.js";
import { observe, during, $Observe, asObserve } from "./dataspace.js";
import { attenuate, rfilter, pRec, pPointer, pString, pLit } from "./rewrite.js";
export default function (t: Turn, ds: Ref) {
let nextUserId: UserId = 0;
@ -13,7 +27,14 @@ export default function (t: Turn, ds: Ref) {
const uid: UserId = nextUserId++;
const f = t.facet(t => {
t.assert(o.observer, fromJoin(Join({ uid, handle: ds })));
t.assert(o.observer, fromJoin(Join({
uid,
handle: attenuate(ds, rfilter(
pRec($Observe, pLit($user), pPointer()),
pRec($Observe, pLit($says), pPointer()),
pRec($claimNick, pLit(uid), pString(), pPointer()),
pRec($says, pLit(uid), pString()))),
})));
let infoHandle: Handle | undefined;
let nick: string | undefined;
observe(t, ds, $claimNick, {