@1auth/authn 0.0.0-alpha.71 → 0.0.0-alpha.72
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/index.js +364 -299
- package/package.json +53 -53
package/index.js
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
1
|
import { setTimeout } from "node:timers/promises";
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
makeRandomConfigObject,
|
|
4
|
+
symmetricDecryptFields,
|
|
5
|
+
symmetricEncryptFields,
|
|
6
|
+
symmetricGenerateEncryptionKey,
|
|
7
7
|
} from "@1auth/crypto";
|
|
8
8
|
|
|
9
9
|
const id = "authn";
|
|
10
10
|
|
|
11
11
|
export const randomId = ({ prefix = "authn_", ...params } = {}) =>
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
makeRandomConfigObject({
|
|
13
|
+
id,
|
|
14
|
+
prefix,
|
|
15
|
+
...params,
|
|
16
|
+
});
|
|
17
17
|
|
|
18
18
|
const defaults = {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
19
|
+
id,
|
|
20
|
+
log: false,
|
|
21
|
+
store: undefined,
|
|
22
|
+
notify: undefined,
|
|
23
|
+
table: "authentications",
|
|
24
|
+
idGenerate: true,
|
|
25
|
+
randomId: randomId(),
|
|
26
|
+
authenticationDuration: 100, // minimum duration authentication should take (ms)
|
|
27
|
+
usernameExists: [], // hooks to allow what to be used as a username
|
|
28
|
+
encryptedFields: ["value"],
|
|
29
29
|
};
|
|
30
30
|
const options = {};
|
|
31
31
|
export default (opt = {}) => {
|
|
32
|
-
|
|
32
|
+
Object.assign(options, defaults, opt);
|
|
33
33
|
};
|
|
34
34
|
export const getOptions = () => options;
|
|
35
35
|
|
|
@@ -44,321 +44,386 @@ export const getOptions = () => options;
|
|
|
44
44
|
// };
|
|
45
45
|
|
|
46
46
|
export const count = async (credentialOptions, sub) => {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
47
|
+
if (!sub || typeof sub !== "string") {
|
|
48
|
+
throw new Error("401 Unauthorized", { cause: { sub, id } });
|
|
49
|
+
}
|
|
50
|
+
const type = makeType(credentialOptions);
|
|
51
|
+
const credentials = await options.store.selectList(
|
|
52
|
+
options.table,
|
|
53
|
+
{ sub, type },
|
|
54
|
+
["verify", "expire"],
|
|
55
|
+
);
|
|
56
|
+
let count = 0;
|
|
57
|
+
const now = nowInSeconds();
|
|
58
|
+
for (let i = credentials.length; i--; ) {
|
|
59
|
+
const credential = credentials[i];
|
|
60
|
+
if (credential.expire && credential.expire < now) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (!credential.verify) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
count += 1;
|
|
67
|
+
}
|
|
68
|
+
return count;
|
|
66
69
|
};
|
|
67
70
|
|
|
68
71
|
export const list = async (credentialOptions, sub, params, fields) => {
|
|
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
|
-
|
|
72
|
+
if (!sub || typeof sub !== "string") {
|
|
73
|
+
throw new Error("401 Unauthorized", { cause: { sub, id } });
|
|
74
|
+
}
|
|
75
|
+
const type = makeType(credentialOptions);
|
|
76
|
+
const items = await options.store.selectList(
|
|
77
|
+
options.table,
|
|
78
|
+
{
|
|
79
|
+
...params,
|
|
80
|
+
sub,
|
|
81
|
+
type,
|
|
82
|
+
},
|
|
83
|
+
fields,
|
|
84
|
+
);
|
|
85
|
+
// const now = nowInSeconds();
|
|
86
|
+
const list = [];
|
|
87
|
+
for (let i = items.length; i--; ) {
|
|
88
|
+
const item = items[i];
|
|
89
|
+
// TODO need filter for expire
|
|
90
|
+
// if (credential.expire < now) {
|
|
91
|
+
// continue;
|
|
92
|
+
// }
|
|
93
|
+
const { encryptionKey: encryptedKey } = item;
|
|
94
|
+
item.encryptionKey = undefined;
|
|
95
|
+
const decryptedItem = symmetricDecryptFields(
|
|
96
|
+
item,
|
|
97
|
+
{ encryptedKey, sub },
|
|
98
|
+
options.encryptedFields,
|
|
99
|
+
);
|
|
100
|
+
list.push(decryptedItem);
|
|
101
|
+
}
|
|
102
|
+
return list;
|
|
97
103
|
};
|
|
98
104
|
|
|
99
105
|
const createCredential = async (
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
106
|
+
credentialOptions,
|
|
107
|
+
sub,
|
|
108
|
+
{ id, value, ...values },
|
|
103
109
|
) => {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
110
|
+
if (!sub || typeof sub !== "string") {
|
|
111
|
+
throw new Error("401 Unauthorized", { cause: { sub } });
|
|
112
|
+
}
|
|
113
|
+
const now = nowInSeconds();
|
|
114
|
+
const type = makeType(credentialOptions);
|
|
115
|
+
let { otp, expire } = credentialOptions;
|
|
116
|
+
expire &&= now + expire;
|
|
117
|
+
|
|
118
|
+
if (options.idGenerate) {
|
|
119
|
+
id ??= await options.randomId.create(options.idPrefix);
|
|
120
|
+
}
|
|
121
|
+
value ??= credentialOptions.create();
|
|
122
|
+
const encodedValue = await credentialOptions.encode(value);
|
|
123
|
+
|
|
124
|
+
const { encryptionKey, encryptedKey } = symmetricGenerateEncryptionKey(sub);
|
|
125
|
+
const encryptedValues = symmetricEncryptFields(
|
|
126
|
+
{ ...values, value: encodedValue },
|
|
127
|
+
{ encryptionKey, sub },
|
|
128
|
+
options.encryptedFields,
|
|
129
|
+
);
|
|
130
|
+
const params = {
|
|
131
|
+
...encryptedValues,
|
|
132
|
+
sub,
|
|
133
|
+
type,
|
|
134
|
+
otp,
|
|
135
|
+
encryptionKey: encryptedKey,
|
|
136
|
+
create: now,
|
|
137
|
+
update: now,
|
|
138
|
+
};
|
|
139
|
+
if (expire) {
|
|
140
|
+
params.expire = expire;
|
|
141
|
+
}
|
|
142
|
+
if (options.idGenerate) {
|
|
143
|
+
params.id = id;
|
|
144
|
+
}
|
|
145
|
+
return params;
|
|
135
146
|
};
|
|
136
147
|
|
|
137
148
|
export const create = async (credentialOptions, sub, values) => {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
149
|
+
const params = await createCredential(credentialOptions, sub, values);
|
|
150
|
+
const id = await options.store.insert(options.table, params);
|
|
151
|
+
return { ...params, id };
|
|
141
152
|
};
|
|
142
153
|
|
|
143
154
|
export const createList = async (credentialOptions, sub, list) => {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
155
|
+
const rows = await Promise.all(
|
|
156
|
+
list.map((values) => createCredential(credentialOptions, sub, values)),
|
|
157
|
+
);
|
|
158
|
+
const res = await options.store.insertList(options.table, rows);
|
|
159
|
+
const params = rows[0];
|
|
160
|
+
return { ...params, id: res };
|
|
150
161
|
};
|
|
151
162
|
|
|
163
|
+
// Only used by webauthn to update counter within value
|
|
152
164
|
export const update = async (
|
|
153
|
-
|
|
154
|
-
|
|
165
|
+
credentialOptions,
|
|
166
|
+
{ id, sub, encryptionKey, encryptedKey, value, ...values },
|
|
155
167
|
) => {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
168
|
+
// if (!sub || typeof sub !== "string") {
|
|
169
|
+
// throw new Error("401 Unauthorized", { cause: { sub } });
|
|
170
|
+
// }
|
|
171
|
+
const now = nowInSeconds();
|
|
172
|
+
// const type = makeType(credentialOptions);
|
|
173
|
+
|
|
174
|
+
const encodedValue = await credentialOptions.encode(value);
|
|
175
|
+
|
|
176
|
+
const encryptedValues = symmetricEncryptFields(
|
|
177
|
+
{ ...values, value: encodedValue },
|
|
178
|
+
{ encryptionKey, encryptedKey, sub },
|
|
179
|
+
options.encryptedFields,
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
return options.store.update(
|
|
183
|
+
options.table,
|
|
184
|
+
{ sub, id },
|
|
185
|
+
{
|
|
186
|
+
...encryptedValues,
|
|
187
|
+
update: now,
|
|
188
|
+
},
|
|
189
|
+
);
|
|
175
190
|
};
|
|
176
191
|
|
|
177
192
|
export const subject = async (username) => {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
193
|
+
return Promise.all(
|
|
194
|
+
options.usernameExists.map((exists) => {
|
|
195
|
+
return exists(username);
|
|
196
|
+
}),
|
|
197
|
+
).then((identities) => {
|
|
198
|
+
return identities.filter((lookup) => lookup)?.[0];
|
|
199
|
+
});
|
|
185
200
|
};
|
|
186
201
|
|
|
187
202
|
export const authenticate = async (credentialOptions, username, secret) => {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
203
|
+
const timeout = setTimeout(options.authenticationDuration);
|
|
204
|
+
|
|
205
|
+
const sub = await subject(username);
|
|
206
|
+
if (!sub) {
|
|
207
|
+
await timeout;
|
|
208
|
+
throw new Error("401 Unauthorized", { cause: { username } });
|
|
209
|
+
}
|
|
210
|
+
const type = makeType(credentialOptions);
|
|
211
|
+
|
|
212
|
+
const credentials = await options.store.selectList(
|
|
213
|
+
options.table,
|
|
214
|
+
{
|
|
215
|
+
sub,
|
|
216
|
+
type,
|
|
217
|
+
},
|
|
218
|
+
["id", "encryptionKey", "value", "otp", "verify", "expire", "sourceId"],
|
|
219
|
+
);
|
|
220
|
+
const now = nowInSeconds();
|
|
221
|
+
let valid;
|
|
222
|
+
let skipIgnoredCount = 0;
|
|
223
|
+
let skipExpiredCount = 0;
|
|
224
|
+
for (const credential of credentials) {
|
|
225
|
+
// non-opt credentials must be verified before use
|
|
226
|
+
if (!credential.otp && !credential.verify) {
|
|
227
|
+
skipIgnoredCount += 1;
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
// skip expired
|
|
231
|
+
|
|
232
|
+
if (credential.expire && credential.expire < now) {
|
|
233
|
+
skipExpiredCount += 1;
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
const { encryptionKey: encryptedKey } = credential;
|
|
237
|
+
const decryptedCredential = symmetricDecryptFields(
|
|
238
|
+
credential,
|
|
239
|
+
{ encryptedKey, sub },
|
|
240
|
+
options.encryptedFields,
|
|
241
|
+
);
|
|
242
|
+
let { value, ...values } = decryptedCredential;
|
|
243
|
+
value = await credentialOptions.decode(value);
|
|
244
|
+
try {
|
|
245
|
+
valid = await credentialOptions.verify(secret, value, values);
|
|
246
|
+
} catch (e) {
|
|
247
|
+
if (options.log) {
|
|
248
|
+
options.log(e);
|
|
249
|
+
}
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
if (valid) {
|
|
253
|
+
const { id, otp } = credential;
|
|
254
|
+
if (otp) {
|
|
255
|
+
await expire(credentialOptions, sub, id, { lastused: now });
|
|
256
|
+
} else {
|
|
257
|
+
const now = nowInSeconds();
|
|
258
|
+
await options.store.update(
|
|
259
|
+
options.table,
|
|
260
|
+
{ id, sub },
|
|
261
|
+
{ lastused: now },
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (credentialOptions.cleanup) {
|
|
266
|
+
await credentialOptions.cleanup(sub, value, values);
|
|
267
|
+
}
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
await timeout;
|
|
273
|
+
if (!valid) {
|
|
274
|
+
let cause = "invalid";
|
|
275
|
+
const credentialsCount = credentials.length - skipIgnoredCount;
|
|
276
|
+
if (credentialsCount === 0) {
|
|
277
|
+
cause = "missing";
|
|
278
|
+
} else if (skipExpiredCount === credentialsCount) {
|
|
279
|
+
cause = "expired";
|
|
280
|
+
}
|
|
281
|
+
throw new Error("401 Unauthorized", { cause });
|
|
282
|
+
}
|
|
283
|
+
return sub;
|
|
264
284
|
};
|
|
265
285
|
|
|
266
|
-
export const verifySecret = async (
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
286
|
+
export const verifySecret = async (_credentialOptions, sub, id) => {
|
|
287
|
+
if (!sub || typeof sub !== "string") {
|
|
288
|
+
throw new Error("401 Unauthorized", { cause: { sub, id } });
|
|
289
|
+
}
|
|
290
|
+
if (!id || typeof id !== "string") {
|
|
291
|
+
throw new Error("404 Not Found", { cause: { sub, id } });
|
|
292
|
+
}
|
|
293
|
+
// const type = makeType(credentialOptions);
|
|
294
|
+
const now = nowInSeconds();
|
|
295
|
+
await options.store.update(
|
|
296
|
+
options.table,
|
|
297
|
+
{ sub, id },
|
|
298
|
+
{ update: now, verify: now },
|
|
299
|
+
);
|
|
274
300
|
};
|
|
275
301
|
|
|
276
302
|
// TODO add in sourceId as filter for messengers
|
|
277
303
|
export const verify = async (credentialOptions, sub, input) => {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
304
|
+
const timeout = setTimeout(options.authenticationDuration);
|
|
305
|
+
if (!sub || typeof sub !== "string") {
|
|
306
|
+
await timeout;
|
|
307
|
+
throw new Error("401 Unauthorized", { cause: { sub } });
|
|
308
|
+
}
|
|
309
|
+
// Can be string or json (webauthn)
|
|
310
|
+
if (!input) {
|
|
311
|
+
await timeout;
|
|
312
|
+
throw new Error("401 Unauthorized", { cause: { sub, input } });
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const type = makeType(credentialOptions);
|
|
316
|
+
|
|
317
|
+
const credentials = await options.store.selectList(options.table, {
|
|
318
|
+
sub,
|
|
319
|
+
type,
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
const now = nowInSeconds();
|
|
323
|
+
let valid;
|
|
324
|
+
let credential;
|
|
325
|
+
let skipExpiredCount = 0;
|
|
326
|
+
for (credential of credentials) {
|
|
327
|
+
// skip expired
|
|
328
|
+
if (credential.expire < now) {
|
|
329
|
+
skipExpiredCount += 1;
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
const { encryptionKey: encryptedKey } = credential;
|
|
333
|
+
const decryptedCredential = symmetricDecryptFields(
|
|
334
|
+
credential,
|
|
335
|
+
{ encryptedKey, sub },
|
|
336
|
+
options.encryptedFields,
|
|
337
|
+
);
|
|
338
|
+
let { value, ...values } = decryptedCredential;
|
|
339
|
+
value = await credentialOptions.decode(value);
|
|
340
|
+
try {
|
|
341
|
+
valid = await credentialOptions.verify(input, value, values);
|
|
342
|
+
} catch (e) {
|
|
343
|
+
if (options.log) {
|
|
344
|
+
options.log(e);
|
|
345
|
+
}
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
if (valid) {
|
|
349
|
+
const { id, otp } = credential;
|
|
350
|
+
if (otp) {
|
|
351
|
+
await remove(credentialOptions, sub, id);
|
|
352
|
+
}
|
|
353
|
+
break;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
await timeout;
|
|
358
|
+
|
|
359
|
+
if (!valid) {
|
|
360
|
+
let cause = "invalid";
|
|
361
|
+
const credentialsCount = credentials.length;
|
|
362
|
+
if (credentialsCount === 0) {
|
|
363
|
+
cause = "missing";
|
|
364
|
+
} else if (skipExpiredCount === credentialsCount) {
|
|
365
|
+
cause = "expired";
|
|
366
|
+
}
|
|
367
|
+
throw new Error("401 Unauthorized", { cause });
|
|
368
|
+
}
|
|
369
|
+
return { ...credential, ...valid };
|
|
334
370
|
};
|
|
335
371
|
|
|
336
|
-
export const expire = async (
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
372
|
+
export const expire = async (_credentialOptions, sub, id, values = {}) => {
|
|
373
|
+
if (!sub || typeof sub !== "string") {
|
|
374
|
+
throw new Error("401 Unauthorized", { cause: { sub, id } });
|
|
375
|
+
}
|
|
376
|
+
if (!id || typeof id !== "string") {
|
|
377
|
+
throw new Error("404 Not Found", { cause: { sub, id } });
|
|
378
|
+
}
|
|
379
|
+
// const type = makeType(credentialOptions);
|
|
380
|
+
await options.store.update(
|
|
381
|
+
options.table,
|
|
382
|
+
{ sub, id },
|
|
383
|
+
{ ...values, expire: nowInSeconds() - 1 },
|
|
384
|
+
);
|
|
343
385
|
};
|
|
344
386
|
|
|
345
387
|
export const remove = async (credentialOptions, sub, id) => {
|
|
346
|
-
|
|
347
|
-
|
|
388
|
+
if (!sub || typeof sub !== "string") {
|
|
389
|
+
throw new Error("401 Unauthorized", { cause: { sub, id } });
|
|
390
|
+
}
|
|
391
|
+
if (!id || typeof id !== "string") {
|
|
392
|
+
throw new Error("404 Not Found", { cause: { sub, id } });
|
|
393
|
+
}
|
|
394
|
+
const type = makeType(credentialOptions);
|
|
395
|
+
await options.store.remove(options.table, { id, type, sub });
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
export const removeList = async (credentialOptions, sub, id) => {
|
|
399
|
+
if (!sub || typeof sub !== "string") {
|
|
400
|
+
throw new Error("401 Unauthorized", { cause: { sub, id } });
|
|
401
|
+
}
|
|
402
|
+
if (!id || !Array.isArray(id) || !id.length) {
|
|
403
|
+
throw new Error("404 Not Found", { cause: { sub, id } });
|
|
404
|
+
}
|
|
405
|
+
const type = makeType(credentialOptions);
|
|
406
|
+
await options.store.removeList(options.table, { id, type, sub });
|
|
348
407
|
};
|
|
349
408
|
|
|
350
409
|
export const select = async (credentialOptions, sub, id) => {
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
410
|
+
if (!sub || typeof sub !== "string") {
|
|
411
|
+
throw new Error("401 Unauthorized", { cause: { sub, id } });
|
|
412
|
+
}
|
|
413
|
+
if (!id || typeof id !== "string") {
|
|
414
|
+
throw new Error("404 Not Found", { cause: { sub, id } });
|
|
415
|
+
}
|
|
416
|
+
const type = makeType(credentialOptions);
|
|
417
|
+
const item = await options.store.select(options.table, { id, type, sub });
|
|
418
|
+
if (!item) return item;
|
|
419
|
+
const { encryptionKey: encryptedKey } = item;
|
|
420
|
+
item.encryptionKey = undefined;
|
|
421
|
+
const decryptedItem = symmetricDecryptFields(
|
|
422
|
+
item,
|
|
423
|
+
{ encryptedKey, sub },
|
|
424
|
+
options.encryptedFields,
|
|
425
|
+
);
|
|
426
|
+
return decryptedItem;
|
|
362
427
|
};
|
|
363
428
|
|
|
364
429
|
// TODO manage onboard state
|
|
@@ -368,5 +433,5 @@ export const select = async (credentialOptions, sub, id) => {
|
|
|
368
433
|
// TODO authorize management?
|
|
369
434
|
|
|
370
435
|
const makeType = (credentialOptions) =>
|
|
371
|
-
|
|
436
|
+
`${credentialOptions.id}-${credentialOptions.type}`;
|
|
372
437
|
const nowInSeconds = () => Math.floor(Date.now() / 1000);
|
package/package.json
CHANGED
|
@@ -1,55 +1,55 @@
|
|
|
1
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
|
-
|
|
2
|
+
"name": "@1auth/authn",
|
|
3
|
+
"version": "0.0.0-alpha.72",
|
|
4
|
+
"description": "",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=22"
|
|
8
|
+
},
|
|
9
|
+
"engineStrict": true,
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"main": "./index.js",
|
|
14
|
+
"module": "./index.js",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"import": {
|
|
18
|
+
"types": "./index.d.ts",
|
|
19
|
+
"default": "./index.js"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"types": "index.d.ts",
|
|
24
|
+
"files": [
|
|
25
|
+
"index.js",
|
|
26
|
+
"index.d.ts"
|
|
27
|
+
],
|
|
28
|
+
"scripts": {
|
|
29
|
+
"test": "npm run test:unit",
|
|
30
|
+
"test:unit": "node --test"
|
|
31
|
+
},
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"funding": {
|
|
34
|
+
"type": "github",
|
|
35
|
+
"url": "https://github.com/sponsors/willfarrell"
|
|
36
|
+
},
|
|
37
|
+
"keywords": [],
|
|
38
|
+
"author": {
|
|
39
|
+
"name": "1auth contributors",
|
|
40
|
+
"url": "https://github.com/willfarrell/1auth/graphs/contributors"
|
|
41
|
+
},
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "git+https://github.com/willfarrell/1auth.git",
|
|
45
|
+
"directory": "packages/authn"
|
|
46
|
+
},
|
|
47
|
+
"bugs": {
|
|
48
|
+
"url": "https://github.com/willfarrell/1auth/issues"
|
|
49
|
+
},
|
|
50
|
+
"homepage": "https://github.com/willfarrell/1auth",
|
|
51
|
+
"gitHead": "7a6c0fbb8ab71d6a2171e678697de9f237568431",
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@1auth/crypto": "0.0.0-alpha.72"
|
|
54
|
+
}
|
|
55
55
|
}
|