-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnext.cjs
More file actions
120 lines (104 loc) · 4.87 KB
/
Copy pathnext.cjs
File metadata and controls
120 lines (104 loc) · 4.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
'use strict';
// PolySec auth machine — UC-3, the authentication & privilege state machine
// (docs/polysec-spec.md §2 UC-3). The TLS-lineage classic, generalized: no
// privileged action before the authenticating transition, and an ORDERING
// invariant — the handshake must complete before application data is accepted
// (the SKIP-TLS shape lives here).
//
// This is the MEDIATED (positive-control) variant. Every acceptor whose success
// would enter a forbidden region is DEFAULT-DENY — it reject()s with a
// contract-anchored reason BEFORE any model write. Unlike the sandbox trifecta,
// recovery here is genuinely REVERSIBLE: TEARDOWN returns the session to the
// unauthenticated start (restoration is available — no external damage, §2 UC-3),
// a deliberate contrast with the trifecta's containment-not-restoration.
//
// SAM v2 strict profile, authored in the shape of the OMS order machine.
//
// State (all booleans):
// handshake — the handshake has completed
// authenticated — the authenticating transition has fired (the gate for privilege)
// appData — application data has been accepted (must follow handshake)
// privileged — a privileged effect has been performed (must follow auth)
// peerClosed — the peer/adversary signalled a close (environment fact)
const { createInstance } = require('@cognitive-fab/sam-pattern');
const instance = createInstance({ strict: true, hasAsyncActions: false });
const INITIAL_STATE = {
handshake: false,
authenticated: false,
appData: false,
privileged: false,
peerClosed: false,
};
const modelShape = {
handshake: { type: 'boolean' },
authenticated: { type: 'boolean' },
appData: { type: 'boolean' },
privileged: { type: 'boolean' },
peerClosed: { type: 'boolean' },
};
const componentActions = {
COMPLETE_HANDSHAKE: { action: (d = {}) => ({ ...d }), schema: {}, domain: [{}] },
AUTHENTICATE: { action: (d = {}) => ({ ...d }), schema: {}, domain: [{}] },
ACCEPT_APP_DATA: { action: (d = {}) => ({ ...d }), schema: {}, domain: [{}] },
DO_PRIVILEGED: { action: (d = {}) => ({ ...d }), schema: {}, domain: [{}] },
PEER_CLOSE: { action: (d = {}) => ({ ...d }), schema: {}, domain: [{}] },
TEARDOWN: { action: (d = {}) => ({ ...d }), schema: {}, domain: [{}] },
};
const acceptors = {
COMPLETE_HANDSHAKE: (model) => (_p, { reject, next, unchanged }) => {
if (model.handshake) return reject('already-handshaked');
next.handshake = true; unchanged('*');
},
// The AUTHENTICATING transition — the gate for privilege. Ordering: it may
// only fire after the handshake completes.
AUTHENTICATE: (model) => (_p, { reject, next, unchanged }) => {
if (!model.handshake) return reject('handshake-required');
if (model.authenticated) return reject('already-authenticated');
next.authenticated = true; unchanged('*');
},
// Application data may only be accepted after the handshake (the ordering
// invariant handshake ≺ appData).
ACCEPT_APP_DATA: (model) => (_p, { reject, next, unchanged }) => {
if (!model.handshake) return reject('handshake-required');
next.appData = true; unchanged('*');
},
// The privileged effect — default-deny: rejected in every pre-auth state.
DO_PRIVILEGED: (model) => (_p, { reject, next, unchanged }) => {
if (!model.authenticated) return reject('auth-required');
next.privileged = true; unchanged('*');
},
// Environment fact: the peer signalled a close (a coupling signal a runtime
// guard could act on; carried in state, not a gate).
PEER_CLOSE: (model) => (_p, { reject, next, unchanged }) => {
if (model.peerClosed) return reject('already-closed');
next.peerClosed = true; unchanged('*');
},
// Corrective nap. REVERSIBLE recovery (restoration is available for UC-3): tear
// the session back down to the unauthenticated start.
TEARDOWN: (model) => (_p, { reject, next, unchanged }) => {
if (!model.handshake && !model.authenticated && !model.appData && !model.privileged && !model.peerClosed) {
return reject('nothing-to-tear-down');
}
next.handshake = false;
next.authenticated = false;
next.appData = false;
next.privileged = false;
next.peerClosed = false; unchanged('*');
},
};
const { intents } = instance({
component: { modelShape, actions: componentActions, acceptors },
initialState: INITIAL_STATE,
});
const getState = () => instance({}).getState();
const setState = (snapshot) => instance({}).setState(snapshot);
const init = () => setState(INITIAL_STATE);
const actions = {
COMPLETE_HANDSHAKE: (d = {}) => intents.COMPLETE_HANDSHAKE(d),
AUTHENTICATE: (d = {}) => intents.AUTHENTICATE(d),
ACCEPT_APP_DATA: (d = {}) => intents.ACCEPT_APP_DATA(d),
DO_PRIVILEGED: (d = {}) => intents.DO_PRIVILEGED(d),
PEER_CLOSE: (d = {}) => intents.PEER_CLOSE(d),
TEARDOWN: (d = {}) => intents.TEARDOWN(d),
};
module.exports = { instance, init, actions, getState, setState };