@nxgt/janus 0.19.0 → 0.20.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/README.md +117 -7
- package/dist/auth/email-flows/reset-password.d.ts.map +1 -1
- package/dist/auth/events.d.ts +3 -3
- package/dist/auth/index.d.ts +1 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/magic-link.d.ts +3 -0
- package/dist/auth/magic-link.d.ts.map +1 -1
- package/dist/auth/one-time/issue.d.ts +6 -0
- package/dist/auth/one-time/issue.d.ts.map +1 -1
- package/dist/auth/prepared.d.ts +21 -0
- package/dist/auth/prepared.d.ts.map +1 -0
- package/dist/auth/proven-sign-in.d.ts +22 -0
- package/dist/auth/proven-sign-in.d.ts.map +1 -0
- package/dist/auth/sign-in-code.d.ts +4 -0
- package/dist/auth/sign-in-code.d.ts.map +1 -1
- package/dist/auth/types/email-flows.d.ts +18 -0
- package/dist/auth/types/email-flows.d.ts.map +1 -1
- package/dist/auth/types/index.d.ts +2 -0
- package/dist/auth/types/index.d.ts.map +1 -1
- package/dist/auth/types/janus.d.ts +7 -5
- package/dist/auth/types/janus.d.ts.map +1 -1
- package/dist/auth/types/magic-link.d.ts +11 -0
- package/dist/auth/types/magic-link.d.ts.map +1 -1
- package/dist/auth/types/prepared.d.ts +41 -0
- package/dist/auth/types/prepared.d.ts.map +1 -0
- package/dist/auth/types/proven-sign-in.d.ts +43 -0
- package/dist/auth/types/proven-sign-in.d.ts.map +1 -0
- package/dist/auth/types/sign-in.d.ts +2 -2
- package/dist/auth/users/any-type-api.d.ts +2 -2
- package/dist/auth/users/any-type-api.d.ts.map +1 -1
- package/dist/auth/users/type-api.d.ts +2 -2
- package/dist/auth/users/type-api.d.ts.map +1 -1
- package/dist/index.js +92 -17
- package/dist/index.js.map +11 -9
- package/docs/README.md +1 -1
- package/docs/guide/devices.md +4 -0
- package/docs/guide/email-flows.md +105 -0
- package/docs/guide/errors.md +2 -2
- package/docs/guide/events.md +2 -2
- package/docs/guide/magic-link.md +49 -2
- package/docs/guide/passwords.md +5 -2
- package/docs/guide/second-factor.md +1 -1
- package/docs/guide/sessions.md +94 -1
- package/docs/guide/sign-in-code.md +54 -2
- package/docs/guide/users.md +1 -0
- package/docs/roadmap.md +17 -26
- package/docs/troubleshooting.md +81 -5
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"any-type-api.d.ts","sourceRoot":"","sources":["../../../src/auth/users/any-type-api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EACX,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,YAAY,EACZ,SAAS,EACT,WAAW,EACX,aAAa,EACb,WAAW,EACX,cAAc,EACd,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE1C,mGAAmG;AACnG,MAAM,MAAM,UAAU,GAAG,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,GACnD,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,GAC1D,eAAe,CAAC,OAAO,CAAC,GACxB,aAAa,CAAC,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,GAC7C,YAAY,CAAC,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,GAC5C,SAAS,CAAC,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,GACjE,cAAc,CAAC,OAAO,CAAC,GACvB,gBAAgB,CAAC,OAAO,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"any-type-api.d.ts","sourceRoot":"","sources":["../../../src/auth/users/any-type-api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EACX,YAAY,EACZ,WAAW,EACX,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,YAAY,EACZ,SAAS,EACT,WAAW,EACX,aAAa,EACb,WAAW,EACX,cAAc,EACd,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE1C,mGAAmG;AACnG,MAAM,MAAM,UAAU,GAAG,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,GACnD,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,GAC1D,eAAe,CAAC,OAAO,CAAC,GACxB,eAAe,CAAC,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,GAC/C,aAAa,CAAC,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,GAC7C,YAAY,CAAC,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,GAC5C,SAAS,CAAC,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,GACjE,cAAc,CAAC,OAAO,CAAC,GACvB,gBAAgB,CAAC,OAAO,CAAC,CAAC"}
|
|
@@ -3,8 +3,8 @@ import type { Context } from '../context';
|
|
|
3
3
|
import type { AnyTypeApi } from './any-type-api';
|
|
4
4
|
/**
|
|
5
5
|
* Everything one user type answers, gathered from its flows: its records,
|
|
6
|
-
* its password, its
|
|
7
|
-
* and its e-mails.
|
|
6
|
+
* its password, its sign-in on the application's proof, its second factor,
|
|
7
|
+
* its sign-in code and link, its step-up and its e-mails.
|
|
8
8
|
*/
|
|
9
9
|
export declare function typeApi(context: Context, type: ResolvedType): AnyTypeApi;
|
|
10
10
|
//# sourceMappingURL=type-api.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"type-api.d.ts","sourceRoot":"","sources":["../../../src/auth/users/type-api.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"type-api.d.ts","sourceRoot":"","sources":["../../../src/auth/users/type-api.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAO1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAIjD;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,GAAG,UAAU,CAkBxE"}
|
package/dist/index.js
CHANGED
|
@@ -1153,7 +1153,7 @@ async function issueCode(context, token) {
|
|
|
1153
1153
|
}
|
|
1154
1154
|
async function insertOneTime(context, token, code) {
|
|
1155
1155
|
const now = context.clock.now();
|
|
1156
|
-
const secret = mintSecret();
|
|
1156
|
+
const secret = token.secret ?? mintSecret();
|
|
1157
1157
|
const expiresAt = new Date(now.getTime() + token.ttlMs);
|
|
1158
1158
|
await context.store.tokens.insertToken({
|
|
1159
1159
|
tokenHash: hashSecret(secret),
|
|
@@ -1295,6 +1295,18 @@ async function heldByPassword(context, type, verified, password, result, where)
|
|
|
1295
1295
|
return false;
|
|
1296
1296
|
}
|
|
1297
1297
|
|
|
1298
|
+
// src/auth/prepared.ts
|
|
1299
|
+
function sendOnce(where, issue) {
|
|
1300
|
+
let sent = false;
|
|
1301
|
+
return async () => {
|
|
1302
|
+
if (sent) {
|
|
1303
|
+
throw new TypeError(`${where}(…).send: already called — a prepared request sends once; call ${where} again for another`);
|
|
1304
|
+
}
|
|
1305
|
+
sent = true;
|
|
1306
|
+
return issue();
|
|
1307
|
+
};
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1298
1310
|
// src/auth/email-flows/email-token.ts
|
|
1299
1311
|
async function redeemEmailToken(context, type, kind, secret, where) {
|
|
1300
1312
|
const token = await spendOneTime(context, secret, kind, where, "token");
|
|
@@ -1327,20 +1339,32 @@ function resetPasswordFlows(context, type, at) {
|
|
|
1327
1339
|
return {
|
|
1328
1340
|
async request(email) {
|
|
1329
1341
|
const where = at("resetPassword.request");
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
const issued = await issueEmailToken(context, type, "resetPassword", record, where);
|
|
1336
|
-
await context.store.tokens.spendUserTokens(record.id, "resetPassword", context.clock.now(), hashSecret(issued.token));
|
|
1337
|
-
return { ...issued, user: toUser(record) };
|
|
1342
|
+
return (await prepareReset(context, type, String(email), where)).send();
|
|
1343
|
+
},
|
|
1344
|
+
async prepare(email) {
|
|
1345
|
+
const where = at("resetPassword.prepare");
|
|
1346
|
+
return prepareReset(context, type, String(email), where);
|
|
1338
1347
|
},
|
|
1339
1348
|
async confirm(secret, password) {
|
|
1340
1349
|
return confirmReset(context, type, secret, password, at("resetPassword.confirm"));
|
|
1341
1350
|
}
|
|
1342
1351
|
};
|
|
1343
1352
|
}
|
|
1353
|
+
async function prepareReset(context, type, email, where) {
|
|
1354
|
+
passwordRule(type, where);
|
|
1355
|
+
await countMailByAddress(context, type, "resetPassword", email, where);
|
|
1356
|
+
return Object.freeze({
|
|
1357
|
+
send: sendOnce(where, () => issueReset(context, type, email, where))
|
|
1358
|
+
});
|
|
1359
|
+
}
|
|
1360
|
+
async function issueReset(context, type, email, where) {
|
|
1361
|
+
const record = await holderOfEmail(context, type, email);
|
|
1362
|
+
if (record === null)
|
|
1363
|
+
return null;
|
|
1364
|
+
const issued = await issueEmailToken(context, type, "resetPassword", record, where);
|
|
1365
|
+
await context.store.tokens.spendUserTokens(record.id, "resetPassword", context.clock.now(), hashSecret(issued.token));
|
|
1366
|
+
return { ...issued, user: toUser(record) };
|
|
1367
|
+
}
|
|
1344
1368
|
async function confirmReset(context, type, secret, password, where) {
|
|
1345
1369
|
passwordRule(type, where);
|
|
1346
1370
|
checkPassword(type, password, where);
|
|
@@ -1561,7 +1585,12 @@ async function finishEmailSignIn(context, type, finish, signIn) {
|
|
|
1561
1585
|
function magicLinkFlows(context, type, at, finish) {
|
|
1562
1586
|
return {
|
|
1563
1587
|
async request(email) {
|
|
1564
|
-
|
|
1588
|
+
const where = at("magicLink.request");
|
|
1589
|
+
return (await prepareLink(context, type, String(email), where)).send();
|
|
1590
|
+
},
|
|
1591
|
+
async prepare(email) {
|
|
1592
|
+
const where = at("magicLink.prepare");
|
|
1593
|
+
return prepareLink(context, type, String(email), where);
|
|
1565
1594
|
},
|
|
1566
1595
|
async confirm(token, options) {
|
|
1567
1596
|
const where = at("magicLink.confirm");
|
|
@@ -1570,8 +1599,13 @@ function magicLinkFlows(context, type, at, finish) {
|
|
|
1570
1599
|
}
|
|
1571
1600
|
};
|
|
1572
1601
|
}
|
|
1573
|
-
async function
|
|
1602
|
+
async function prepareLink(context, type, email, where) {
|
|
1574
1603
|
await countMailByAddress(context, type, "magicLink", email, where);
|
|
1604
|
+
return Object.freeze({
|
|
1605
|
+
send: sendOnce(where, () => issueLink(context, type, email))
|
|
1606
|
+
});
|
|
1607
|
+
}
|
|
1608
|
+
async function issueLink(context, type, email) {
|
|
1575
1609
|
const record = await signInHolder(context, type, email);
|
|
1576
1610
|
if (record === null)
|
|
1577
1611
|
return null;
|
|
@@ -1596,6 +1630,32 @@ async function confirmLink(context, type, finish, secret, where, device) {
|
|
|
1596
1630
|
});
|
|
1597
1631
|
}
|
|
1598
1632
|
|
|
1633
|
+
// src/auth/proven-sign-in.ts
|
|
1634
|
+
function provenSignInFlows(context, type, at, finish) {
|
|
1635
|
+
return {
|
|
1636
|
+
async signInProven(user, options) {
|
|
1637
|
+
const where = at("signInProven");
|
|
1638
|
+
const device = deviceHint(context, options, where);
|
|
1639
|
+
const record = await getRecord(context, idOf2(user), type.name, where);
|
|
1640
|
+
if (!record.active) {
|
|
1641
|
+
throw new UserInactiveError2(`${where}: the user is inactive`, {
|
|
1642
|
+
userId: record.id,
|
|
1643
|
+
userType: type.name
|
|
1644
|
+
});
|
|
1645
|
+
}
|
|
1646
|
+
const result = await finish(record, where, device);
|
|
1647
|
+
await reportNewDevice(context, result);
|
|
1648
|
+
return result;
|
|
1649
|
+
}
|
|
1650
|
+
};
|
|
1651
|
+
}
|
|
1652
|
+
function idOf2(user) {
|
|
1653
|
+
if (typeof user === "string")
|
|
1654
|
+
return user;
|
|
1655
|
+
const id = typeof user === "object" && user !== null ? user.id : undefined;
|
|
1656
|
+
return typeof id === "string" ? id : "";
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1599
1659
|
// src/auth/sign-in-attempts.ts
|
|
1600
1660
|
var PURPOSE3 = "janus/sign-in/attempts/v1";
|
|
1601
1661
|
async function countLogin(context, type, login, where) {
|
|
@@ -1974,29 +2034,43 @@ function secondFactorFlows(context, type, at) {
|
|
|
1974
2034
|
function signInCodeFlows(context, type, at, finish) {
|
|
1975
2035
|
return {
|
|
1976
2036
|
async request(email) {
|
|
1977
|
-
|
|
2037
|
+
const where = at("signInCode.request");
|
|
2038
|
+
return (await prepareCode(context, type, String(email), where)).send();
|
|
2039
|
+
},
|
|
2040
|
+
async prepare(email) {
|
|
2041
|
+
const where = at("signInCode.prepare");
|
|
2042
|
+
return prepareCode(context, type, String(email), where);
|
|
1978
2043
|
},
|
|
1979
2044
|
async confirm(challenge, code, options) {
|
|
1980
2045
|
return confirmCode(context, type, finish, { challenge, code, options }, at);
|
|
1981
2046
|
}
|
|
1982
2047
|
};
|
|
1983
2048
|
}
|
|
1984
|
-
async function
|
|
2049
|
+
async function prepareCode(context, type, email, where) {
|
|
1985
2050
|
await countMailByAddress(context, type, "signInCode", email, where);
|
|
2051
|
+
const challenge = mintSecret();
|
|
2052
|
+
return Object.freeze({
|
|
2053
|
+
challenge,
|
|
2054
|
+
send: sendOnce(where, () => issueSignInCode(context, type, email, challenge))
|
|
2055
|
+
});
|
|
2056
|
+
}
|
|
2057
|
+
async function issueSignInCode(context, type, email, challenge) {
|
|
1986
2058
|
const record = await signInHolder(context, type, email);
|
|
1987
2059
|
if (record === null)
|
|
1988
2060
|
return null;
|
|
2061
|
+
const address = String(record.fields[type.email]);
|
|
1989
2062
|
const { secret, code, expiresAt } = await issueCode(context, {
|
|
1990
2063
|
kind: "signInCode",
|
|
1991
2064
|
userId: record.id,
|
|
1992
|
-
address
|
|
1993
|
-
ttlMs: context.config.tokenTtlMs.signInCode
|
|
2065
|
+
address,
|
|
2066
|
+
ttlMs: context.config.tokenTtlMs.signInCode,
|
|
2067
|
+
secret: challenge
|
|
1994
2068
|
});
|
|
1995
2069
|
await keepOnlyLatest(context, record.id, "signInCode", secret);
|
|
1996
2070
|
return {
|
|
1997
2071
|
code,
|
|
1998
2072
|
challenge: secret,
|
|
1999
|
-
email:
|
|
2073
|
+
email: address,
|
|
2000
2074
|
expiresAt,
|
|
2001
2075
|
user: toUser(record)
|
|
2002
2076
|
};
|
|
@@ -2448,6 +2522,7 @@ function typeApi(context, type) {
|
|
|
2448
2522
|
return {
|
|
2449
2523
|
...recordFlows(context, type, at),
|
|
2450
2524
|
...passwordFlows(context, type, at, secondFactor.finish),
|
|
2525
|
+
...provenSignInFlows(context, type, at, secondFactor.finish),
|
|
2451
2526
|
secondFactor: secondFactor.api,
|
|
2452
2527
|
signInCode,
|
|
2453
2528
|
magicLink: magicLinkFlows(context, type, at, secondFactor.finish),
|
|
@@ -2540,5 +2615,5 @@ export {
|
|
|
2540
2615
|
systemClock
|
|
2541
2616
|
};
|
|
2542
2617
|
|
|
2543
|
-
//# debugId=
|
|
2618
|
+
//# debugId=58DD1D230B6CE48B64756E2164756E21
|
|
2544
2619
|
//# sourceMappingURL=index.js.map
|