GizStack
View .mdOpen in ChatGPTOpen in Claude

gizlang:security

Shared identity, session proof and authorization decisions. Protocols adapt credentials and persistence; they do not define a second permission system.

gizlang
import * as Security from "gizlang:security";

Types

Signed

gizlang
type Signed = { who: string; issued: i64; }

A signed claim: who it names and when it was issued (ms since 1970).

  • who: string
  • issued: i64

Identity

gizlang
type Identity = { identity: string; tenant: string; role: string; secret: bytes; }

A registered identity: its name, tenant, role and secret.

  • identity: string
  • tenant: string
  • role: string
  • secret: bytes

Registration

gizlang
type Registration = { principal: Identity; enabled: bool; revokedBefore: i64; revision: i64; }

The registration of an identity: whether it is enabled, the time before which its sessions are void, and its revision.

  • principal: gizlang_security.Identity
  • enabled: bool
  • revokedBefore: i64
  • revision: i64

Authority

gizlang
type Authority

Share this authority across DB, HTTP and Agent entrypoints. Registry edits are immediately visible to every holder; authenticated sessions pin a revision.

Opaque: create and use it through this module's functions.

ResourceRef

gizlang
type ResourceRef = { space: string; type: string; key: string; }

One reference to any record: its Space, the stable declaration of its record type and its key. Trusted adapters supply the target and all its ancestors, including itself. Its one text form is SPACE/TYPE/KEY (see ResourceRef.text).

  • space: string
  • type: string
  • key: string

Role

gizlang
type Role = | { kind: "none"; } | { kind: "viewer"; } | { kind: "commenter"; } | { kind: "editor"; } | { kind: "manager"; } | { kind: "owner"; }

A role, from none to owner, in the order none < viewer < commenter < editor < manager < owner.

  • none
  • viewer
  • commenter
  • editor
  • manager
  • owner

Principal

gizlang
type Principal = | { kind: "person"; id: string; } | { kind: "agent"; id: string; ceiling: Role; onBehalf: string; } | { kind: "group"; team: ResourceRef; } | { kind: "link"; digest: bytes; } | { kind: "public"; }

Who acts or holds a grant. A group holds grants and never acts: a person who holds a role on the group's reference (type group) is a member of it.

  • person
  • agent
  • group
  • link
  • public

Grant

gizlang
type Grant = { principal: Principal; target: ResourceRef; role: Role; expires: i64; }

A grant of a role on a record to a principal, until expires (0 never).

  • principal: gizlang_security.Principal
  • target: gizlang_security.ResourceRef
  • role: gizlang_security.Role
  • expires: i64

Decision

gizlang
type Decision = { allowed: bool; role: Role; reason: string; }

The answer of a Policy decision: whether it is allowed, the role that the actor holds, and the reason.

  • allowed: bool
  • role: gizlang_security.Role
  • reason: string

Capability

gizlang
type Capability = { principal: Principal; target: ResourceRef; role: Role; expires: i64; revision: i64; }

A signed, short-lived permission: principal holds role on target until expires, as decided at policy revision. A holder of the key verifies it with no lookup, so HTTP, S3, the mount and a CDN decide alike.

  • principal: gizlang_security.Principal
  • target: gizlang_security.ResourceRef
  • role: gizlang_security.Role
  • expires: i64
  • revision: i64

Functions

authority

gizlang
function authority(): Authority

An authority with no principals.

Effects: fail, write.

token

gizlang
function token(secret: bytes, principal: string, issued: i64): string

A session token for PRINCIPAL issued at ISSUED (milliseconds), signed with SECRET (HMAC-SHA-256).

Effects: fail.

verified

gizlang
function verified(secret: bytes, text: string, now: i64): Option<Signed>

The principal and issue time of the token TEXT when its signature with SECRET is valid, else none.

Effects: fail.

validSession

gizlang
function validSession(signed: Signed, enabled: bool, revokedBefore: i64, now: i64): bool

Whether the session SIGNED is valid at NOW: the principal is enabled, the token is newer than REVOKEDBEFORE, and its age is within the session life.

Effects: fail.

parseResourceRef

gizlang
function parseResourceRef(text: string): ResourceRef throws string

The reference of the text SPACE/TYPE/KEY (ResourceRef.text). It fails on any other form.

Effects: fail.

rank

gizlang
function rank(role: Role): i64 effects {}

The only role order: none < viewer < commenter < editor < manager < owner. An Operation names the least role that it needs; viewer marks a read.

roleText

gizlang
function roleText(role: Role): string effects {}

The one text of a role: its kind.

parseRole

gizlang
function parseRole(text: string): Role throws string

The role of its text ("none", "viewer", "commenter", "editor", "manager", "owner"). It fails on any other text.

Effects: fail.

principalText

gizlang
function principalText(p: Principal): string

The one text of a grantee: person:ID, agent:ID, group:SPACE/group/KEY, link:HEX or public. An agent's text names the agent only: its ceiling and its person come from the actor, never from a grant.

Effects: fail.

parsePrincipal

gizlang
function parsePrincipal(text: string): Principal throws string

The principal of its text ("public", "person:ID", "agent:ID", "group:REF" or "link:HEX"). It fails on any other text.

Effects: fail.

decide

gizlang
function decide(actor: Principal, ancestry: Vec<ResourceRef>, grants: Vec<Grant>, needed: Role, now: i64): Decision effects { fail }

Total, pure authorization: whether actor holds at least needed on the first reference of ancestry, through grants on it or on its ancestors. Grants only add; there is no deny. Public and link grants match only that actor. A person also holds the grants of its groups (the membership grants are in grants). Agents need their own grant and their person's grant, under their ceiling. A grant never supplies an agent's trusted ceiling or delegation identity. A group never acts. The compiler marks bounded Vec iteration as fail; no state or IO is used.

Effects: fail.

capability

gizlang
function capability(key: bytes, granted: Capability, now: i64): string throws string

The token of a capability that decide admitted: HEX(body).HEX(HMAC-SHA256).

Effects: fail.

admitCapability

gizlang
function admitCapability(key: bytes, token: string, now: i64): Capability throws string

The capability of a token that key signed and that is still live at now.

Effects: fail.

policyDigest

gizlang
function policyDigest(domain: string, definitions: Vec<string>): bytes

General policy identity; adapters provide canonical observed facts.

Effects: fail.

digest

gizlang
function digest(data: bytes): string

The SHA-256 of data in lowercase hex: the one content digest of tokens, keys and cache names.

Effects: fail.

passwordHash

gizlang
function passwordHash(password: string, salt: string): string

A password's stored hash under salt: PBKDF2-SHA-256, 32 bytes, in lowercase hex.

Effects: fail.

Methods

Authority.register

gizlang
function Authority.register(self: Authority, principal: Identity): bool throws string

Adds PRINCIPAL. It fails when the principal is not valid or its identity is already registered.

Effects: fail, read, write.

Authority.lookup

gizlang
function Authority.lookup(self: Authority, identity: string): Option<Registration>

The registration of IDENTITY, or none.

Effects: fail, read.

Authority.authenticate

gizlang
function Authority.authenticate(self: Authority, identity: string, credential: bytes): Option<Registration>

The registration of IDENTITY when CREDENTIAL (32 bytes) matches its secret and it is enabled, else none.

Effects: fail, read.

Authority.replace

gizlang
function Authority.replace(self: Authority, principal: Identity, enabled: bool, revokedBefore: i64): bool throws string

Revocation/change occurs at the trusted authority, not in client claims.

Effects: fail, read, write.

Authority.current

gizlang
function Authority.current(self: Authority, evidence: Registration): bool

Whether EVIDENCE is still the current revision of an enabled registration.

Effects: fail, read.

Authority.resolve

gizlang
function Authority.resolve(self: Authority, signed: Signed, now: i64): Option<Registration>

The registration of the session SIGNED when it is valid at NOW, else none.

Effects: fail, read.

ResourceRef.text

gizlang
function ResourceRef.text(self: ResourceRef): string

SPACE/TYPE/KEY: SPACE and TYPE are 1 to 64 of a-z 0-9 _ . - and KEY is the percent-encoded UTF-8 key (Http.encode). At most 512 bytes. Equal texts are equal references: parseResourceRef accepts only this form.

Effects: fail.

Constants

SESSION_LIFE

gizlang
const SESSION_LIFE = 2592000000

How long a session lasts, in milliseconds (30 days).

CAPABILITY_LIFE

gizlang
const CAPABILITY_LIFE = 300000

The longest life of a capability: the revocation bound of reads that check no grant.

PASSWORD_ROUNDS

gizlang
const PASSWORD_ROUNDS = 120000

How many rounds a password hash takes.