@assemora/auth 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +69 -0
- package/dist/actors.d.ts +20 -0
- package/dist/actors.d.ts.map +1 -0
- package/dist/actors.js +37 -0
- package/dist/actors.js.map +1 -0
- package/dist/authorization.d.ts +36 -0
- package/dist/authorization.d.ts.map +1 -0
- package/dist/authorization.js +93 -0
- package/dist/authorization.js.map +1 -0
- package/dist/commands.d.ts +232 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +390 -0
- package/dist/commands.js.map +1 -0
- package/dist/credentials.d.ts +16 -0
- package/dist/credentials.d.ts.map +1 -0
- package/dist/credentials.js +43 -0
- package/dist/credentials.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/models.d.ts +136 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +92 -0
- package/dist/models.js.map +1 -0
- package/dist/module.d.ts +39 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +95 -0
- package/dist/module.js.map +1 -0
- package/dist/ownership.d.ts +67 -0
- package/dist/ownership.d.ts.map +1 -0
- package/dist/ownership.js +51 -0
- package/dist/ownership.js.map +1 -0
- package/dist/permissions.d.ts +40 -0
- package/dist/permissions.d.ts.map +1 -0
- package/dist/permissions.js +86 -0
- package/dist/permissions.js.map +1 -0
- package/dist/policies.d.ts +120 -0
- package/dist/policies.d.ts.map +1 -0
- package/dist/policies.js +92 -0
- package/dist/policies.js.map +1 -0
- package/dist/queries.d.ts +166 -0
- package/dist/queries.d.ts.map +1 -0
- package/dist/queries.js +236 -0
- package/dist/queries.js.map +1 -0
- package/dist/sessions.d.ts +40 -0
- package/dist/sessions.d.ts.map +1 -0
- package/dist/sessions.js +39 -0
- package/dist/sessions.js.map +1 -0
- package/dist/tokens.d.ts +40 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +60 -0
- package/dist/tokens.js.map +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
declare module '@assemora/core' {
|
|
2
|
+
interface AssemoraEventPayloads {
|
|
3
|
+
'auth.signed-in': {
|
|
4
|
+
readonly userId: string;
|
|
5
|
+
};
|
|
6
|
+
'auth.signed-out': {
|
|
7
|
+
readonly userId: string | undefined;
|
|
8
|
+
};
|
|
9
|
+
'auth.user-created': {
|
|
10
|
+
readonly userId: string;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The two commands a route has to front (SPEC.md §85).
|
|
16
|
+
*
|
|
17
|
+
* `publicAuthPolicy` authorizes them for everybody, because the caller of a login is
|
|
18
|
+
* nobody yet. That removes the floor every other command stands on — the bus
|
|
19
|
+
* authorizes first, and authorization denies by default — so the checks that make
|
|
20
|
+
* them safe live in the routes written for them: the session leaves as an `httpOnly`
|
|
21
|
+
* cookie rather than as readable JSON, a CSRF token is minted beside it, logging out
|
|
22
|
+
* clears both, and the forensic fields come off the request.
|
|
23
|
+
*
|
|
24
|
+
* A generated `POST /commands/auth.login` or an MCP tool would be the same handler
|
|
25
|
+
* with none of that in front of it — and, since agent permissions never gate a
|
|
26
|
+
* publicly authorized command, an agent token would be a password oracle. Saying it
|
|
27
|
+
* here is what keeps both generators away, instead of a list of names each of them
|
|
28
|
+
* would have to maintain.
|
|
29
|
+
*/
|
|
30
|
+
export declare const SignIn: import("@assemora/core").CommandDefinition<{
|
|
31
|
+
email: import("@assemora/schema").StringSchema;
|
|
32
|
+
password: import("@assemora/schema").StringSchema;
|
|
33
|
+
}, {
|
|
34
|
+
readonly expiresAt: Date;
|
|
35
|
+
readonly token: string;
|
|
36
|
+
readonly userId: string;
|
|
37
|
+
}>;
|
|
38
|
+
export declare const SignOut: import("@assemora/core").CommandDefinition<{
|
|
39
|
+
token: import("@assemora/schema").StringSchema;
|
|
40
|
+
}, {
|
|
41
|
+
readonly ended: boolean;
|
|
42
|
+
}>;
|
|
43
|
+
export declare const CreateUser: import("@assemora/core").CommandDefinition<{
|
|
44
|
+
email: import("@assemora/schema").StringSchema;
|
|
45
|
+
name: import("@assemora/schema").StringSchema;
|
|
46
|
+
password: import("@assemora/schema").StringSchema;
|
|
47
|
+
roles: import("@assemora/schema").OptionalSchema<string[]>;
|
|
48
|
+
}, {
|
|
49
|
+
readonly id: string;
|
|
50
|
+
}>;
|
|
51
|
+
export declare const GrantRole: import("@assemora/core").CommandDefinition<{
|
|
52
|
+
userId: import("@assemora/schema").StringSchema;
|
|
53
|
+
role: import("@assemora/schema").StringSchema;
|
|
54
|
+
}, {
|
|
55
|
+
readonly role: string;
|
|
56
|
+
readonly userId: string;
|
|
57
|
+
}>;
|
|
58
|
+
export declare const CreateApiToken: import("@assemora/core").CommandDefinition<{
|
|
59
|
+
name: import("@assemora/schema").StringSchema;
|
|
60
|
+
permissions: import("@assemora/schema").ArraySchema<import("@assemora/schema").StringSchema>;
|
|
61
|
+
userId: import("@assemora/schema").OptionalSchema<string>;
|
|
62
|
+
expiresAt: import("@assemora/schema").OptionalSchema<Date>;
|
|
63
|
+
}, {
|
|
64
|
+
readonly id: string;
|
|
65
|
+
readonly token: string;
|
|
66
|
+
}>;
|
|
67
|
+
export declare const CreateAgent: import("@assemora/core").CommandDefinition<{
|
|
68
|
+
name: import("@assemora/schema").StringSchema;
|
|
69
|
+
description: import("@assemora/schema").OptionalSchema<string>;
|
|
70
|
+
permissions: import("@assemora/schema").ArraySchema<import("@assemora/schema").StringSchema>;
|
|
71
|
+
}, {
|
|
72
|
+
readonly agentId: string;
|
|
73
|
+
readonly token: string;
|
|
74
|
+
readonly tokenId: string;
|
|
75
|
+
}>;
|
|
76
|
+
export declare const UpdateUser: import("@assemora/core").CommandDefinition<{
|
|
77
|
+
id: import("@assemora/schema").StringSchema;
|
|
78
|
+
expectedVersion: import("@assemora/schema").OptionalSchema<number>;
|
|
79
|
+
name: import("@assemora/schema").OptionalSchema<string>;
|
|
80
|
+
email: import("@assemora/schema").OptionalSchema<string>;
|
|
81
|
+
active: import("@assemora/schema").OptionalSchema<boolean>;
|
|
82
|
+
}, {
|
|
83
|
+
readonly id: string;
|
|
84
|
+
readonly version: number;
|
|
85
|
+
}>;
|
|
86
|
+
export declare const SetPassword: import("@assemora/core").CommandDefinition<{
|
|
87
|
+
id: import("@assemora/schema").StringSchema;
|
|
88
|
+
password: import("@assemora/schema").StringSchema;
|
|
89
|
+
}, {
|
|
90
|
+
readonly id: string;
|
|
91
|
+
}>;
|
|
92
|
+
export declare const RevokeRole: import("@assemora/core").CommandDefinition<{
|
|
93
|
+
userId: import("@assemora/schema").StringSchema;
|
|
94
|
+
role: import("@assemora/schema").StringSchema;
|
|
95
|
+
}, {
|
|
96
|
+
readonly role: string;
|
|
97
|
+
readonly userId: string;
|
|
98
|
+
}>;
|
|
99
|
+
export declare const CreateRole: import("@assemora/core").CommandDefinition<{
|
|
100
|
+
name: import("@assemora/schema").StringSchema;
|
|
101
|
+
label: import("@assemora/schema").StringSchema;
|
|
102
|
+
permissions: import("@assemora/schema").ArraySchema<import("@assemora/schema").StringSchema>;
|
|
103
|
+
}, {
|
|
104
|
+
readonly id: string;
|
|
105
|
+
readonly name: string;
|
|
106
|
+
}>;
|
|
107
|
+
export declare const UpdateRole: import("@assemora/core").CommandDefinition<{
|
|
108
|
+
id: import("@assemora/schema").StringSchema;
|
|
109
|
+
expectedVersion: import("@assemora/schema").OptionalSchema<number>;
|
|
110
|
+
label: import("@assemora/schema").OptionalSchema<string>;
|
|
111
|
+
permissions: import("@assemora/schema").OptionalSchema<string[]>;
|
|
112
|
+
}, {
|
|
113
|
+
readonly id: string;
|
|
114
|
+
readonly version: number;
|
|
115
|
+
}>;
|
|
116
|
+
export declare const DeleteRole: import("@assemora/core").CommandDefinition<{
|
|
117
|
+
id: import("@assemora/schema").StringSchema;
|
|
118
|
+
}, {
|
|
119
|
+
readonly id: string;
|
|
120
|
+
}>;
|
|
121
|
+
export declare const RevokeApiToken: import("@assemora/core").CommandDefinition<{
|
|
122
|
+
id: import("@assemora/schema").StringSchema;
|
|
123
|
+
}, {
|
|
124
|
+
readonly id: string;
|
|
125
|
+
}>;
|
|
126
|
+
export declare const UpdateAgent: import("@assemora/core").CommandDefinition<{
|
|
127
|
+
id: import("@assemora/schema").StringSchema;
|
|
128
|
+
description: import("@assemora/schema").OptionalSchema<string>;
|
|
129
|
+
permissions: import("@assemora/schema").OptionalSchema<string[]>;
|
|
130
|
+
enabled: import("@assemora/schema").OptionalSchema<boolean>;
|
|
131
|
+
}, {
|
|
132
|
+
readonly enabled: boolean;
|
|
133
|
+
readonly id: string;
|
|
134
|
+
}>;
|
|
135
|
+
/**
|
|
136
|
+
* Signing in and signing out are open to anyone; everything else in `auth` needs the
|
|
137
|
+
* matching permission, which is what having no policy for it means.
|
|
138
|
+
*/
|
|
139
|
+
export declare const publicAuthPolicy: import("./policies.js").Policy<Record<string, unknown>>;
|
|
140
|
+
export declare const authCommands: readonly [import("@assemora/core").CommandDefinition<{
|
|
141
|
+
email: import("@assemora/schema").StringSchema;
|
|
142
|
+
password: import("@assemora/schema").StringSchema;
|
|
143
|
+
}, {
|
|
144
|
+
readonly expiresAt: Date;
|
|
145
|
+
readonly token: string;
|
|
146
|
+
readonly userId: string;
|
|
147
|
+
}>, import("@assemora/core").CommandDefinition<{
|
|
148
|
+
token: import("@assemora/schema").StringSchema;
|
|
149
|
+
}, {
|
|
150
|
+
readonly ended: boolean;
|
|
151
|
+
}>, import("@assemora/core").CommandDefinition<{
|
|
152
|
+
email: import("@assemora/schema").StringSchema;
|
|
153
|
+
name: import("@assemora/schema").StringSchema;
|
|
154
|
+
password: import("@assemora/schema").StringSchema;
|
|
155
|
+
roles: import("@assemora/schema").OptionalSchema<string[]>;
|
|
156
|
+
}, {
|
|
157
|
+
readonly id: string;
|
|
158
|
+
}>, import("@assemora/core").CommandDefinition<{
|
|
159
|
+
id: import("@assemora/schema").StringSchema;
|
|
160
|
+
expectedVersion: import("@assemora/schema").OptionalSchema<number>;
|
|
161
|
+
name: import("@assemora/schema").OptionalSchema<string>;
|
|
162
|
+
email: import("@assemora/schema").OptionalSchema<string>;
|
|
163
|
+
active: import("@assemora/schema").OptionalSchema<boolean>;
|
|
164
|
+
}, {
|
|
165
|
+
readonly id: string;
|
|
166
|
+
readonly version: number;
|
|
167
|
+
}>, import("@assemora/core").CommandDefinition<{
|
|
168
|
+
id: import("@assemora/schema").StringSchema;
|
|
169
|
+
password: import("@assemora/schema").StringSchema;
|
|
170
|
+
}, {
|
|
171
|
+
readonly id: string;
|
|
172
|
+
}>, import("@assemora/core").CommandDefinition<{
|
|
173
|
+
userId: import("@assemora/schema").StringSchema;
|
|
174
|
+
role: import("@assemora/schema").StringSchema;
|
|
175
|
+
}, {
|
|
176
|
+
readonly role: string;
|
|
177
|
+
readonly userId: string;
|
|
178
|
+
}>, import("@assemora/core").CommandDefinition<{
|
|
179
|
+
userId: import("@assemora/schema").StringSchema;
|
|
180
|
+
role: import("@assemora/schema").StringSchema;
|
|
181
|
+
}, {
|
|
182
|
+
readonly role: string;
|
|
183
|
+
readonly userId: string;
|
|
184
|
+
}>, import("@assemora/core").CommandDefinition<{
|
|
185
|
+
name: import("@assemora/schema").StringSchema;
|
|
186
|
+
label: import("@assemora/schema").StringSchema;
|
|
187
|
+
permissions: import("@assemora/schema").ArraySchema<import("@assemora/schema").StringSchema>;
|
|
188
|
+
}, {
|
|
189
|
+
readonly id: string;
|
|
190
|
+
readonly name: string;
|
|
191
|
+
}>, import("@assemora/core").CommandDefinition<{
|
|
192
|
+
id: import("@assemora/schema").StringSchema;
|
|
193
|
+
expectedVersion: import("@assemora/schema").OptionalSchema<number>;
|
|
194
|
+
label: import("@assemora/schema").OptionalSchema<string>;
|
|
195
|
+
permissions: import("@assemora/schema").OptionalSchema<string[]>;
|
|
196
|
+
}, {
|
|
197
|
+
readonly id: string;
|
|
198
|
+
readonly version: number;
|
|
199
|
+
}>, import("@assemora/core").CommandDefinition<{
|
|
200
|
+
id: import("@assemora/schema").StringSchema;
|
|
201
|
+
}, {
|
|
202
|
+
readonly id: string;
|
|
203
|
+
}>, import("@assemora/core").CommandDefinition<{
|
|
204
|
+
name: import("@assemora/schema").StringSchema;
|
|
205
|
+
permissions: import("@assemora/schema").ArraySchema<import("@assemora/schema").StringSchema>;
|
|
206
|
+
userId: import("@assemora/schema").OptionalSchema<string>;
|
|
207
|
+
expiresAt: import("@assemora/schema").OptionalSchema<Date>;
|
|
208
|
+
}, {
|
|
209
|
+
readonly id: string;
|
|
210
|
+
readonly token: string;
|
|
211
|
+
}>, import("@assemora/core").CommandDefinition<{
|
|
212
|
+
id: import("@assemora/schema").StringSchema;
|
|
213
|
+
}, {
|
|
214
|
+
readonly id: string;
|
|
215
|
+
}>, import("@assemora/core").CommandDefinition<{
|
|
216
|
+
name: import("@assemora/schema").StringSchema;
|
|
217
|
+
description: import("@assemora/schema").OptionalSchema<string>;
|
|
218
|
+
permissions: import("@assemora/schema").ArraySchema<import("@assemora/schema").StringSchema>;
|
|
219
|
+
}, {
|
|
220
|
+
readonly agentId: string;
|
|
221
|
+
readonly token: string;
|
|
222
|
+
readonly tokenId: string;
|
|
223
|
+
}>, import("@assemora/core").CommandDefinition<{
|
|
224
|
+
id: import("@assemora/schema").StringSchema;
|
|
225
|
+
description: import("@assemora/schema").OptionalSchema<string>;
|
|
226
|
+
permissions: import("@assemora/schema").OptionalSchema<string[]>;
|
|
227
|
+
enabled: import("@assemora/schema").OptionalSchema<boolean>;
|
|
228
|
+
}, {
|
|
229
|
+
readonly enabled: boolean;
|
|
230
|
+
readonly id: string;
|
|
231
|
+
}>];
|
|
232
|
+
//# sourceMappingURL=commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AA+BA,OAAO,QAAQ,gBAAgB,CAAC;IAC9B,UAAU,qBAAqB;QAC7B,gBAAgB,EAAE;YAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAA;QAC7C,iBAAiB,EAAE;YAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;SAAE,CAAA;QAC1D,mBAAmB,EAAE;YAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAA;KACjD;CACF;AAwDD;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,MAAM;;;;;;;EA0BjB,CAAA;AAEF,eAAO,MAAM,OAAO;;;;EAWlB,CAAA;AAEF,eAAO,MAAM,UAAU;;;;;;;EAuCrB,CAAA;AAEF,eAAO,MAAM,SAAS;;;;;;EAiBpB,CAAA;AAEF,eAAO,MAAM,cAAc;;;;;;;;EAmBzB,CAAA;AAEF,eAAO,MAAM,WAAW;;;;;;;;EAatB,CAAA;AAuBF,eAAO,MAAM,UAAU;;;;;;;;;EAgCrB,CAAA;AAEF,eAAO,MAAM,WAAW;;;;;EAiBtB,CAAA;AAEF,eAAO,MAAM,UAAU;;;;;;EAmBrB,CAAA;AAEF,eAAO,MAAM,UAAU;;;;;;;EA0BrB,CAAA;AAEF,eAAO,MAAM,UAAU;;;;;;;;EA6BrB,CAAA;AAEF,eAAO,MAAM,UAAU;;;;EAkBrB,CAAA;AAEF,eAAO,MAAM,cAAc;;;;EAczB,CAAA;AAEF,eAAO,MAAM,WAAW;;;;;;;;EA8BtB,CAAA;AAEF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,yDAG3B,CAAA;AAEF,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAef,CAAA"}
|
package/dist/commands.js
ADDED
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication commands (SPEC.md §14, §49).
|
|
3
|
+
*
|
|
4
|
+
* Signing in changes state — a session is created — so it travels the Command Bus
|
|
5
|
+
* like every other mutation, and is audited like every other mutation.
|
|
6
|
+
*/
|
|
7
|
+
import { AssemoraError, ConflictError, command, ForbiddenError, NotFoundError, } from '@assemora/core';
|
|
8
|
+
import { array, boolean, email as emailSchema, number, string, timestamp, uuid, } from '@assemora/schema';
|
|
9
|
+
import { hashPassword, verifyPassword } from './credentials.js';
|
|
10
|
+
import { Agent, ApiToken, Permission, Role, RolePermission, User, UserRole } from './models.js';
|
|
11
|
+
import { holds, permissionsOf } from './permissions.js';
|
|
12
|
+
import { policy } from './policies.js';
|
|
13
|
+
import { endSession, startSession } from './sessions.js';
|
|
14
|
+
import { createAgent, createApiToken } from './tokens.js';
|
|
15
|
+
/**
|
|
16
|
+
* A hash to verify against when the email is unknown.
|
|
17
|
+
*
|
|
18
|
+
* Without it, a missing user answers faster than a wrong password, and the timing
|
|
19
|
+
* says which emails are registered (SPEC.md §85).
|
|
20
|
+
*/
|
|
21
|
+
const DECOY = await hashPassword('a password nobody has');
|
|
22
|
+
const INVALID = new AssemoraError('INVALID_CREDENTIALS', 'The email or password is wrong', {
|
|
23
|
+
status: 401,
|
|
24
|
+
});
|
|
25
|
+
/**
|
|
26
|
+
* Refuses to hand out more than the giver has (SPEC.md §50, §72).
|
|
27
|
+
*
|
|
28
|
+
* A role, an API token and an agent all carry permissions, and any of the three would
|
|
29
|
+
* otherwise be a way to mint a credential stronger than the actor minting it — an
|
|
30
|
+
* escalation that leaves an ordinary-looking audit trail.
|
|
31
|
+
*/
|
|
32
|
+
const grantable = async (permissions, context) => {
|
|
33
|
+
const held = await permissionsOf(context.actor);
|
|
34
|
+
const beyond = permissions.filter((permission) => !holds(held, permission));
|
|
35
|
+
if (beyond.length > 0) {
|
|
36
|
+
throw new ForbiddenError(`You cannot grant what you do not hold: ${[...new Set(beyond)].sort().join(', ')}`);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Links permission names to a role, recording any that had not been seen before.
|
|
41
|
+
*
|
|
42
|
+
* A permission name is a command name (ADR-0015), so the set of legal ones is
|
|
43
|
+
* whatever the application declares — there is no fixed list to validate against, and
|
|
44
|
+
* inventing one would make a role uneditable the moment a package added a command.
|
|
45
|
+
*/
|
|
46
|
+
const attach = async (roleId, names) => {
|
|
47
|
+
for (const name of names) {
|
|
48
|
+
const permission = (await Permission.where('name', name).first()) ??
|
|
49
|
+
(await Permission.create({ name, description: null }));
|
|
50
|
+
const existing = await RolePermission.where('roleId', roleId)
|
|
51
|
+
.where('permissionId', permission.id)
|
|
52
|
+
.first();
|
|
53
|
+
if (existing === null)
|
|
54
|
+
await RolePermission.create({ roleId, permissionId: permission.id });
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* The two commands a route has to front (SPEC.md §85).
|
|
59
|
+
*
|
|
60
|
+
* `publicAuthPolicy` authorizes them for everybody, because the caller of a login is
|
|
61
|
+
* nobody yet. That removes the floor every other command stands on — the bus
|
|
62
|
+
* authorizes first, and authorization denies by default — so the checks that make
|
|
63
|
+
* them safe live in the routes written for them: the session leaves as an `httpOnly`
|
|
64
|
+
* cookie rather than as readable JSON, a CSRF token is minted beside it, logging out
|
|
65
|
+
* clears both, and the forensic fields come off the request.
|
|
66
|
+
*
|
|
67
|
+
* A generated `POST /commands/auth.login` or an MCP tool would be the same handler
|
|
68
|
+
* with none of that in front of it — and, since agent permissions never gate a
|
|
69
|
+
* publicly authorized command, an agent token would be a password oracle. Saying it
|
|
70
|
+
* here is what keeps both generators away, instead of a list of names each of them
|
|
71
|
+
* would have to maintain.
|
|
72
|
+
*/
|
|
73
|
+
export const SignIn = command('auth.login', {
|
|
74
|
+
description: 'Exchanges an email and a password for a session',
|
|
75
|
+
reachableFrom: 'its own route',
|
|
76
|
+
input: { email: emailSchema(), password: string() },
|
|
77
|
+
output: { token: string(), expiresAt: timestamp(), userId: uuid() },
|
|
78
|
+
handle: async ({ email, password }, context) => {
|
|
79
|
+
const user = await User.where('email', email.toLowerCase()).first();
|
|
80
|
+
const correct = await verifyPassword(user?.passwordHash ?? DECOY, password);
|
|
81
|
+
// The same answer either way: whether the email exists is not something an
|
|
82
|
+
// unauthenticated caller gets to learn.
|
|
83
|
+
if (user === null || !correct || !user.active)
|
|
84
|
+
throw INVALID;
|
|
85
|
+
// Off the context, never out of the input: a caller that names its own user agent
|
|
86
|
+
// is writing the forensic record of its own sign-in. There is no `ipAddress` for
|
|
87
|
+
// the same reason there is none on the context — nothing here knows the client's
|
|
88
|
+
// address without a trusted-proxy policy the HTTP server does not yet offer, and
|
|
89
|
+
// a column holding a claim is worse than a column holding nothing.
|
|
90
|
+
const session = await startSession(user.id, {
|
|
91
|
+
...(context.userAgent === undefined ? {} : { userAgent: context.userAgent }),
|
|
92
|
+
});
|
|
93
|
+
context.emit('auth.signed-in', { userId: user.id });
|
|
94
|
+
return { token: session.token, expiresAt: session.expiresAt, userId: user.id };
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
export const SignOut = command('auth.logout', {
|
|
98
|
+
description: 'Ends a session',
|
|
99
|
+
reachableFrom: 'its own route',
|
|
100
|
+
input: { token: string() },
|
|
101
|
+
output: { ended: boolean() },
|
|
102
|
+
handle: async ({ token }, context) => {
|
|
103
|
+
await endSession(token);
|
|
104
|
+
context.emit('auth.signed-out', { userId: context.actor?.id });
|
|
105
|
+
return { ended: true };
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
export const CreateUser = command('auth.users.create', {
|
|
109
|
+
description: 'Creates a user',
|
|
110
|
+
input: {
|
|
111
|
+
email: emailSchema(),
|
|
112
|
+
name: string(),
|
|
113
|
+
password: string().min(12),
|
|
114
|
+
roles: array(string()).optional(),
|
|
115
|
+
},
|
|
116
|
+
output: { id: uuid() },
|
|
117
|
+
handle: async ({ email, name, password, roles }, context) => {
|
|
118
|
+
const user = await User.create({
|
|
119
|
+
email: email.toLowerCase(),
|
|
120
|
+
name,
|
|
121
|
+
passwordHash: await hashPassword(password),
|
|
122
|
+
active: true,
|
|
123
|
+
});
|
|
124
|
+
for (const roleName of roles ?? []) {
|
|
125
|
+
const role = await Role.where('name', roleName).first();
|
|
126
|
+
if (role === null) {
|
|
127
|
+
throw new AssemoraError('UNKNOWN_ROLE', `There is no role named "${roleName}"`, {
|
|
128
|
+
status: 422,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
await UserRole.create({ userId: user.id, roleId: role.id });
|
|
132
|
+
}
|
|
133
|
+
context.revise({
|
|
134
|
+
entityType: 'assemora_users',
|
|
135
|
+
entityId: user.id,
|
|
136
|
+
before: null,
|
|
137
|
+
after: user.toJSON(),
|
|
138
|
+
});
|
|
139
|
+
context.emit('auth.user-created', { userId: user.id });
|
|
140
|
+
return { id: user.id };
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
export const GrantRole = command('auth.roles.grant', {
|
|
144
|
+
description: 'Gives a user a role',
|
|
145
|
+
input: { userId: uuid(), role: string() },
|
|
146
|
+
output: { userId: uuid(), role: string() },
|
|
147
|
+
handle: async ({ userId, role }) => {
|
|
148
|
+
const found = await Role.where('name', role).first();
|
|
149
|
+
if (found === null) {
|
|
150
|
+
throw new AssemoraError('UNKNOWN_ROLE', `There is no role named "${role}"`, { status: 422 });
|
|
151
|
+
}
|
|
152
|
+
const existing = await UserRole.where('userId', userId).where('roleId', found.id).first();
|
|
153
|
+
if (existing === null)
|
|
154
|
+
await UserRole.create({ userId, roleId: found.id });
|
|
155
|
+
return { userId, role };
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
export const CreateApiToken = command('auth.tokens.create', {
|
|
159
|
+
description: 'Issues an API token. The token is returned once and never again',
|
|
160
|
+
input: {
|
|
161
|
+
name: string(),
|
|
162
|
+
permissions: array(string()),
|
|
163
|
+
userId: uuid().optional(),
|
|
164
|
+
expiresAt: timestamp().optional(),
|
|
165
|
+
},
|
|
166
|
+
output: { token: string(), id: uuid() },
|
|
167
|
+
handle: async (input, context) => {
|
|
168
|
+
await grantable(input.permissions, context);
|
|
169
|
+
return createApiToken({
|
|
170
|
+
name: input.name,
|
|
171
|
+
permissions: input.permissions,
|
|
172
|
+
...(input.userId === undefined ? {} : { userId: input.userId }),
|
|
173
|
+
...(input.expiresAt === undefined ? {} : { expiresAt: input.expiresAt }),
|
|
174
|
+
});
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
export const CreateAgent = command('auth.agents.create', {
|
|
178
|
+
description: 'Creates an agent identity and its first token (SPEC.md §72)',
|
|
179
|
+
input: { name: string(), description: string().optional(), permissions: array(string()) },
|
|
180
|
+
output: { agentId: uuid(), token: string(), tokenId: uuid() },
|
|
181
|
+
handle: async (input, context) => {
|
|
182
|
+
await grantable(input.permissions, context);
|
|
183
|
+
return createAgent({
|
|
184
|
+
name: input.name,
|
|
185
|
+
permissions: input.permissions,
|
|
186
|
+
...(input.description === undefined ? {} : { description: input.description }),
|
|
187
|
+
});
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
/** Reads the row and refuses to go on if someone else has written since (SPEC.md §66). */
|
|
191
|
+
const versioned = async (load, what, id, expectedVersion) => {
|
|
192
|
+
const found = await load();
|
|
193
|
+
if (found === null)
|
|
194
|
+
throw new NotFoundError(what, id);
|
|
195
|
+
if (expectedVersion !== undefined && found.version !== expectedVersion) {
|
|
196
|
+
throw new ConflictError(`This ${what} has changed since it was read`, {
|
|
197
|
+
expectedVersion,
|
|
198
|
+
currentVersion: found.version,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
return found;
|
|
202
|
+
};
|
|
203
|
+
export const UpdateUser = command('auth.users.update', {
|
|
204
|
+
description: 'Changes a user name, email or whether they may sign in',
|
|
205
|
+
input: {
|
|
206
|
+
id: uuid(),
|
|
207
|
+
expectedVersion: number().integer().optional(),
|
|
208
|
+
name: string().min(1).optional(),
|
|
209
|
+
email: emailSchema().optional(),
|
|
210
|
+
active: boolean().optional(),
|
|
211
|
+
},
|
|
212
|
+
output: { id: uuid(), version: number().integer() },
|
|
213
|
+
handle: async ({ id, expectedVersion, name, email, active }, context) => {
|
|
214
|
+
const user = await versioned(() => User.find(id), 'user', id, expectedVersion);
|
|
215
|
+
const before = user.toJSON();
|
|
216
|
+
await context.authorize('auth.users', 'update', before);
|
|
217
|
+
await user.update({
|
|
218
|
+
...(name === undefined ? {} : { name }),
|
|
219
|
+
...(email === undefined ? {} : { email: email.toLowerCase() }),
|
|
220
|
+
...(active === undefined ? {} : { active }),
|
|
221
|
+
version: user.version + 1,
|
|
222
|
+
});
|
|
223
|
+
context.revise({
|
|
224
|
+
entityType: 'assemora_users',
|
|
225
|
+
entityId: id,
|
|
226
|
+
before,
|
|
227
|
+
after: user.toJSON(),
|
|
228
|
+
});
|
|
229
|
+
return { id, version: user.version };
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
export const SetPassword = command('auth.users.password', {
|
|
233
|
+
description: 'Sets a user password. The old one is never read back to check it',
|
|
234
|
+
input: { id: uuid(), password: string().min(12) },
|
|
235
|
+
output: { id: uuid() },
|
|
236
|
+
handle: async ({ id, password }, context) => {
|
|
237
|
+
const user = await User.find(id);
|
|
238
|
+
if (user === null)
|
|
239
|
+
throw new NotFoundError('user', id);
|
|
240
|
+
await context.authorize('auth.users', 'update', user.toJSON());
|
|
241
|
+
await user.update({ passwordHash: await hashPassword(password), version: user.version + 1 });
|
|
242
|
+
// Deliberately no revision: a revision stores before and after, and neither
|
|
243
|
+
// belongs in a table anybody can read (SPEC.md §85).
|
|
244
|
+
return { id };
|
|
245
|
+
},
|
|
246
|
+
});
|
|
247
|
+
export const RevokeRole = command('auth.roles.revoke', {
|
|
248
|
+
description: 'Takes a role away from a user',
|
|
249
|
+
input: { userId: uuid(), role: string() },
|
|
250
|
+
output: { userId: uuid(), role: string() },
|
|
251
|
+
handle: async ({ userId, role }, context) => {
|
|
252
|
+
const found = await Role.where('name', role).first();
|
|
253
|
+
if (found === null) {
|
|
254
|
+
throw new AssemoraError('UNKNOWN_ROLE', `There is no role named "${role}"`, { status: 422 });
|
|
255
|
+
}
|
|
256
|
+
await context.authorize('auth.roles', 'revoke', { userId, role });
|
|
257
|
+
const link = await UserRole.where('userId', userId).where('roleId', found.id).first();
|
|
258
|
+
if (link !== null)
|
|
259
|
+
await link.delete();
|
|
260
|
+
return { userId, role };
|
|
261
|
+
},
|
|
262
|
+
});
|
|
263
|
+
export const CreateRole = command('auth.roles.create', {
|
|
264
|
+
description: 'Creates a role and the permissions it carries',
|
|
265
|
+
input: { name: string().min(1), label: string().min(1), permissions: array(string()) },
|
|
266
|
+
output: { id: uuid(), name: string() },
|
|
267
|
+
handle: async ({ name, label, permissions }, context) => {
|
|
268
|
+
await grantable(permissions, context);
|
|
269
|
+
if ((await Role.where('name', name).first()) !== null) {
|
|
270
|
+
throw new AssemoraError('ROLE_EXISTS', `There is already a role named "${name}"`, {
|
|
271
|
+
status: 409,
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
const role = await Role.create({ name, label, version: 1 });
|
|
275
|
+
await attach(role.id, permissions);
|
|
276
|
+
context.revise({
|
|
277
|
+
entityType: 'assemora_roles',
|
|
278
|
+
entityId: role.id,
|
|
279
|
+
before: null,
|
|
280
|
+
after: role.toJSON(),
|
|
281
|
+
});
|
|
282
|
+
return { id: role.id, name: role.name };
|
|
283
|
+
},
|
|
284
|
+
});
|
|
285
|
+
export const UpdateRole = command('auth.roles.update', {
|
|
286
|
+
description: 'Renames a role or replaces the permissions it carries',
|
|
287
|
+
input: {
|
|
288
|
+
id: uuid(),
|
|
289
|
+
expectedVersion: number().integer().optional(),
|
|
290
|
+
label: string().min(1).optional(),
|
|
291
|
+
permissions: array(string()).optional(),
|
|
292
|
+
},
|
|
293
|
+
output: { id: uuid(), version: number().integer() },
|
|
294
|
+
handle: async ({ id, expectedVersion, label, permissions }, context) => {
|
|
295
|
+
const role = await versioned(() => Role.find(id), 'role', id, expectedVersion);
|
|
296
|
+
const before = role.toJSON();
|
|
297
|
+
await context.authorize('auth.roles', 'update', before);
|
|
298
|
+
if (permissions !== undefined)
|
|
299
|
+
await grantable(permissions, context);
|
|
300
|
+
await role.update({ ...(label === undefined ? {} : { label }), version: role.version + 1 });
|
|
301
|
+
if (permissions !== undefined) {
|
|
302
|
+
for (const link of await RolePermission.where('roleId', id))
|
|
303
|
+
await link.delete();
|
|
304
|
+
await attach(id, permissions);
|
|
305
|
+
}
|
|
306
|
+
context.revise({ entityType: 'assemora_roles', entityId: id, before, after: role.toJSON() });
|
|
307
|
+
return { id, version: role.version };
|
|
308
|
+
},
|
|
309
|
+
});
|
|
310
|
+
export const DeleteRole = command('auth.roles.delete', {
|
|
311
|
+
description: 'Deletes a role, and takes it from everyone who held it',
|
|
312
|
+
input: { id: uuid() },
|
|
313
|
+
output: { id: uuid() },
|
|
314
|
+
handle: async ({ id }, context) => {
|
|
315
|
+
const role = await Role.find(id);
|
|
316
|
+
if (role === null)
|
|
317
|
+
throw new NotFoundError('role', id);
|
|
318
|
+
await context.authorize('auth.roles', 'delete', role.toJSON());
|
|
319
|
+
for (const link of await RolePermission.where('roleId', id))
|
|
320
|
+
await link.delete();
|
|
321
|
+
for (const link of await UserRole.where('roleId', id))
|
|
322
|
+
await link.delete();
|
|
323
|
+
await role.delete();
|
|
324
|
+
return { id };
|
|
325
|
+
},
|
|
326
|
+
});
|
|
327
|
+
export const RevokeApiToken = command('auth.tokens.revoke', {
|
|
328
|
+
description: 'Stops an API token working, at once and for good',
|
|
329
|
+
input: { id: uuid() },
|
|
330
|
+
output: { id: uuid() },
|
|
331
|
+
handle: async ({ id }, context) => {
|
|
332
|
+
const token = await ApiToken.find(id);
|
|
333
|
+
if (token === null)
|
|
334
|
+
throw new NotFoundError('token', id);
|
|
335
|
+
await context.authorize('auth.tokens', 'revoke', { id: token.id, name: token.name });
|
|
336
|
+
await token.delete();
|
|
337
|
+
return { id };
|
|
338
|
+
},
|
|
339
|
+
});
|
|
340
|
+
export const UpdateAgent = command('auth.agents.update', {
|
|
341
|
+
description: 'Changes what an agent may do, or turns it off (SPEC.md §72)',
|
|
342
|
+
input: {
|
|
343
|
+
id: uuid(),
|
|
344
|
+
description: string().optional(),
|
|
345
|
+
permissions: array(string()).optional(),
|
|
346
|
+
enabled: boolean().optional(),
|
|
347
|
+
},
|
|
348
|
+
output: { id: uuid(), enabled: boolean() },
|
|
349
|
+
handle: async ({ id, description, permissions, enabled }, context) => {
|
|
350
|
+
if (permissions !== undefined)
|
|
351
|
+
await grantable(permissions, context);
|
|
352
|
+
const agent = await Agent.find(id);
|
|
353
|
+
if (agent === null)
|
|
354
|
+
throw new NotFoundError('agent', id);
|
|
355
|
+
const before = agent.toJSON();
|
|
356
|
+
await context.authorize('auth.agents', 'update', before);
|
|
357
|
+
await agent.update({
|
|
358
|
+
...(description === undefined ? {} : { description }),
|
|
359
|
+
...(permissions === undefined ? {} : { permissions }),
|
|
360
|
+
...(enabled === undefined ? {} : { enabled }),
|
|
361
|
+
});
|
|
362
|
+
context.revise({ entityType: 'assemora_agents', entityId: id, before, after: agent.toJSON() });
|
|
363
|
+
return { id, enabled: agent.enabled };
|
|
364
|
+
},
|
|
365
|
+
});
|
|
366
|
+
/**
|
|
367
|
+
* Signing in and signing out are open to anyone; everything else in `auth` needs the
|
|
368
|
+
* matching permission, which is what having no policy for it means.
|
|
369
|
+
*/
|
|
370
|
+
export const publicAuthPolicy = policy('auth', {
|
|
371
|
+
login: () => true,
|
|
372
|
+
logout: () => true,
|
|
373
|
+
});
|
|
374
|
+
export const authCommands = [
|
|
375
|
+
SignIn,
|
|
376
|
+
SignOut,
|
|
377
|
+
CreateUser,
|
|
378
|
+
UpdateUser,
|
|
379
|
+
SetPassword,
|
|
380
|
+
GrantRole,
|
|
381
|
+
RevokeRole,
|
|
382
|
+
CreateRole,
|
|
383
|
+
UpdateRole,
|
|
384
|
+
DeleteRole,
|
|
385
|
+
CreateApiToken,
|
|
386
|
+
RevokeApiToken,
|
|
387
|
+
CreateAgent,
|
|
388
|
+
UpdateAgent,
|
|
389
|
+
];
|
|
390
|
+
//# sourceMappingURL=commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"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"}
|