@absolutejs/auth 0.36.0-beta.0 → 0.37.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/dist/client/index.d.ts +1 -0
- package/dist/client/index.js +555 -1
- package/dist/client/index.js.map +20 -4
- package/dist/client/passkeyHelpers.d.ts +19 -0
- package/dist/client/react.d.ts +25 -0
- package/dist/client/react.js +610 -1
- package/dist/client/react.js.map +20 -4
- package/dist/client/solid.d.ts +25 -0
- package/dist/client/solid.js +611 -1
- package/dist/client/solid.js.map +20 -4
- package/dist/client/svelte.d.ts +25 -0
- package/dist/client/svelte.js +600 -1
- package/dist/client/svelte.js.map +20 -4
- package/dist/client/vue.d.ts +27 -0
- package/dist/client/vue.js +627 -1
- package/dist/client/vue.js.map +20 -4
- package/dist/credentials/backgroundOps.d.ts +45 -0
- package/dist/htmx/index.js +16 -1
- package/dist/htmx/index.js.map +2 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +269 -22
- package/dist/index.js.map +8 -6
- package/dist/oidc/config.d.ts +5 -2
- package/dist/oidc/mtls.d.ts +11 -0
- package/dist/oidc/types.d.ts +1 -0
- package/dist/plugins/index.js +16 -1
- package/dist/plugins/index.js.map +2 -2
- package/package.json +6 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,19 @@
|
|
|
1
1
|
// @bun
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __returnValue = (v) => v;
|
|
4
|
+
function __exportSetter(name, newValue) {
|
|
5
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
6
|
+
}
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, {
|
|
10
|
+
get: all[name],
|
|
11
|
+
enumerable: true,
|
|
12
|
+
configurable: true,
|
|
13
|
+
set: __exportSetter.bind(all, name)
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
2
17
|
var __require = import.meta.require;
|
|
3
18
|
|
|
4
19
|
// node_modules/citra/dist/index.js
|
|
@@ -4492,6 +4507,7 @@ var RESERVED_ACCESS_CLAIMS = new Set([
|
|
|
4492
4507
|
var buildAccessClaims = ({
|
|
4493
4508
|
act,
|
|
4494
4509
|
audience,
|
|
4510
|
+
clientCertThumbprint,
|
|
4495
4511
|
clientId,
|
|
4496
4512
|
dpopJkt,
|
|
4497
4513
|
extraClaims,
|
|
@@ -4516,8 +4532,15 @@ var buildAccessClaims = ({
|
|
|
4516
4532
|
};
|
|
4517
4533
|
if (act !== undefined)
|
|
4518
4534
|
claims.act = act;
|
|
4519
|
-
if (dpopJkt !== undefined)
|
|
4520
|
-
|
|
4535
|
+
if (dpopJkt !== undefined || clientCertThumbprint !== undefined) {
|
|
4536
|
+
const cnf = {};
|
|
4537
|
+
if (dpopJkt !== undefined)
|
|
4538
|
+
cnf.jkt = dpopJkt;
|
|
4539
|
+
if (clientCertThumbprint !== undefined) {
|
|
4540
|
+
cnf["x5t#S256"] = clientCertThumbprint;
|
|
4541
|
+
}
|
|
4542
|
+
claims.cnf = cnf;
|
|
4543
|
+
}
|
|
4521
4544
|
return claims;
|
|
4522
4545
|
};
|
|
4523
4546
|
var exchangeToken = async ({
|
|
@@ -4567,6 +4590,7 @@ var exchangeToken = async ({
|
|
|
4567
4590
|
var issueTokenSet = async ({
|
|
4568
4591
|
acr,
|
|
4569
4592
|
claims,
|
|
4593
|
+
clientCertThumbprint,
|
|
4570
4594
|
clientId,
|
|
4571
4595
|
config,
|
|
4572
4596
|
dpopJkt,
|
|
@@ -4584,6 +4608,7 @@ var issueTokenSet = async ({
|
|
|
4584
4608
|
sub
|
|
4585
4609
|
});
|
|
4586
4610
|
const accessPayload = buildAccessClaims({
|
|
4611
|
+
clientCertThumbprint,
|
|
4587
4612
|
clientId,
|
|
4588
4613
|
dpopJkt,
|
|
4589
4614
|
extraClaims: { ...accessExtra, ...acr === undefined ? {} : { acr } },
|
|
@@ -4873,6 +4898,7 @@ var denyBackchannelAuth = async ({
|
|
|
4873
4898
|
}) => decideBackchannel(config, authReqId, { status: "denied" });
|
|
4874
4899
|
var exchangeBackchannelAuth = async ({
|
|
4875
4900
|
authReqId,
|
|
4901
|
+
clientCertThumbprint,
|
|
4876
4902
|
clientId,
|
|
4877
4903
|
config,
|
|
4878
4904
|
dpopJkt,
|
|
@@ -4901,6 +4927,7 @@ var exchangeBackchannelAuth = async ({
|
|
|
4901
4927
|
}
|
|
4902
4928
|
await config.backchannelAuthStore.deleteByAuthReqId(authReqId);
|
|
4903
4929
|
const tokenSet = await issueTokenSet({
|
|
4930
|
+
clientCertThumbprint,
|
|
4904
4931
|
clientId,
|
|
4905
4932
|
config,
|
|
4906
4933
|
dpopJkt,
|
|
@@ -5020,6 +5047,55 @@ var verifyJwtSignedByClient = ({
|
|
|
5020
5047
|
client
|
|
5021
5048
|
}) => verifyJwtSignedByClientImpl(client, jwt);
|
|
5022
5049
|
|
|
5050
|
+
// src/oidc/mtls.ts
|
|
5051
|
+
var RFC9440_HEADER = "client-cert";
|
|
5052
|
+
var SF_BINARY_PREFIX = ":";
|
|
5053
|
+
var SF_BINARY_SUFFIX = ":";
|
|
5054
|
+
var base64Decode2 = (value) => Uint8Array.from(atob(value), (char) => char.charCodeAt(0));
|
|
5055
|
+
var base64UrlEncode2 = (bytes) => {
|
|
5056
|
+
const binary = Array.from(bytes, (byte) => String.fromCharCode(byte)).join("");
|
|
5057
|
+
return btoa(binary).replace(/\+/gu, "-").replace(/\//gu, "_").replace(/=+$/u, "");
|
|
5058
|
+
};
|
|
5059
|
+
var computeCertThumbprint = async (derBytes) => {
|
|
5060
|
+
const digest = await crypto.subtle.digest("SHA-256", derBytes);
|
|
5061
|
+
return base64UrlEncode2(new Uint8Array(digest));
|
|
5062
|
+
};
|
|
5063
|
+
var extractRfc9440ClientCert = (headers) => {
|
|
5064
|
+
const raw = headers.get(RFC9440_HEADER);
|
|
5065
|
+
if (raw === null)
|
|
5066
|
+
return;
|
|
5067
|
+
const trimmed = raw.trim();
|
|
5068
|
+
if (!trimmed.startsWith(SF_BINARY_PREFIX) || !trimmed.endsWith(SF_BINARY_SUFFIX) || trimmed.length <= 2) {
|
|
5069
|
+
return;
|
|
5070
|
+
}
|
|
5071
|
+
try {
|
|
5072
|
+
return base64Decode2(trimmed.slice(1, -1));
|
|
5073
|
+
} catch {
|
|
5074
|
+
return;
|
|
5075
|
+
}
|
|
5076
|
+
};
|
|
5077
|
+
var resolveClientCert = async ({
|
|
5078
|
+
extract,
|
|
5079
|
+
headers
|
|
5080
|
+
}) => {
|
|
5081
|
+
if (extract !== undefined)
|
|
5082
|
+
return extract(headers);
|
|
5083
|
+
return extractRfc9440ClientCert(headers);
|
|
5084
|
+
};
|
|
5085
|
+
var verifyCertificateBoundToken = async ({
|
|
5086
|
+
cnfThumbprint,
|
|
5087
|
+
extract,
|
|
5088
|
+
headers
|
|
5089
|
+
}) => {
|
|
5090
|
+
if (cnfThumbprint === undefined)
|
|
5091
|
+
return false;
|
|
5092
|
+
const cert = await resolveClientCert({ extract, headers });
|
|
5093
|
+
if (cert === undefined)
|
|
5094
|
+
return false;
|
|
5095
|
+
const presented = await computeCertThumbprint(cert);
|
|
5096
|
+
return presented === cnfThumbprint;
|
|
5097
|
+
};
|
|
5098
|
+
|
|
5023
5099
|
// src/oidc/dpop.ts
|
|
5024
5100
|
var DEFAULT_MAX_AGE_MS = 60000;
|
|
5025
5101
|
var SECONDS_TO_MS = 1000;
|
|
@@ -5656,27 +5732,57 @@ var oidcProviderRoutes = (config) => {
|
|
|
5656
5732
|
const matches = await constantTimeEqual(await hashToken(clientSecret), client.hashedSecret);
|
|
5657
5733
|
return matches ? client : undefined;
|
|
5658
5734
|
};
|
|
5735
|
+
const tryMtlsAuth = async ({
|
|
5736
|
+
candidate,
|
|
5737
|
+
extract,
|
|
5738
|
+
requestHeaders
|
|
5739
|
+
}) => {
|
|
5740
|
+
const registered = candidate?.tlsCertificateBoundThumbprints ?? [];
|
|
5741
|
+
if (candidate === undefined || registered.length === 0)
|
|
5742
|
+
return;
|
|
5743
|
+
const cert = await resolveClientCert({
|
|
5744
|
+
extract,
|
|
5745
|
+
headers: requestHeaders
|
|
5746
|
+
});
|
|
5747
|
+
if (cert === undefined)
|
|
5748
|
+
return;
|
|
5749
|
+
const presented = await computeCertThumbprint(cert);
|
|
5750
|
+
if (!registered.includes(presented))
|
|
5751
|
+
return;
|
|
5752
|
+
return { client: candidate, clientCertThumbprint: presented };
|
|
5753
|
+
};
|
|
5659
5754
|
const authenticateTokenClient = async ({
|
|
5660
5755
|
basicClientId,
|
|
5661
5756
|
basicClientSecret,
|
|
5662
5757
|
bodyClientAssertion,
|
|
5663
5758
|
bodyClientAssertionType,
|
|
5664
5759
|
bodyClientId,
|
|
5665
|
-
bodyClientSecret
|
|
5760
|
+
bodyClientSecret,
|
|
5761
|
+
requestHeaders
|
|
5666
5762
|
}) => {
|
|
5667
5763
|
if (bodyClientAssertion !== undefined && bodyClientAssertionType === CLIENT_ASSERTION_TYPE) {
|
|
5668
|
-
|
|
5764
|
+
const client2 = await verifyClientAssertion({
|
|
5669
5765
|
assertion: bodyClientAssertion,
|
|
5670
5766
|
expectedAudience: tokenUrl,
|
|
5671
5767
|
jtiStore: config.clientAssertionJtiStore,
|
|
5672
5768
|
resolveClient: clientStore.findClient
|
|
5673
5769
|
});
|
|
5770
|
+
return client2 === undefined ? undefined : { client: client2, clientCertThumbprint: undefined };
|
|
5674
5771
|
}
|
|
5675
5772
|
const clientId = bodyClientId ?? basicClientId;
|
|
5676
|
-
const clientSecret = bodyClientSecret ?? basicClientSecret;
|
|
5677
5773
|
if (clientId === undefined)
|
|
5678
5774
|
return;
|
|
5679
|
-
|
|
5775
|
+
const candidate = await clientStore.findClient(clientId);
|
|
5776
|
+
const mtlsResult = await tryMtlsAuth({
|
|
5777
|
+
candidate,
|
|
5778
|
+
extract: config.extractTlsClientCert,
|
|
5779
|
+
requestHeaders
|
|
5780
|
+
});
|
|
5781
|
+
if (mtlsResult !== undefined)
|
|
5782
|
+
return mtlsResult;
|
|
5783
|
+
const clientSecret = bodyClientSecret ?? basicClientSecret;
|
|
5784
|
+
const client = await authenticateClient(clientId, clientSecret);
|
|
5785
|
+
return client === undefined ? undefined : { client, clientCertThumbprint: undefined };
|
|
5680
5786
|
};
|
|
5681
5787
|
const dpopNonceChallenge = async (proof) => {
|
|
5682
5788
|
if (proof === undefined || config.dpopNonce === undefined) {
|
|
@@ -5701,7 +5807,7 @@ var oidcProviderRoutes = (config) => {
|
|
|
5701
5807
|
status: HTTP_UNAUTHORIZED2
|
|
5702
5808
|
});
|
|
5703
5809
|
};
|
|
5704
|
-
const grantAuthorizationCode = async (client, body, dpop) => {
|
|
5810
|
+
const grantAuthorizationCode = async (client, body, dpop, clientCertThumbprint) => {
|
|
5705
5811
|
const {
|
|
5706
5812
|
code,
|
|
5707
5813
|
code_verifier: codeVerifier,
|
|
@@ -5725,6 +5831,7 @@ var oidcProviderRoutes = (config) => {
|
|
|
5725
5831
|
return tokenResponse(await issueTokenSet({
|
|
5726
5832
|
acr: record.acr,
|
|
5727
5833
|
claims: record.claims,
|
|
5834
|
+
clientCertThumbprint,
|
|
5728
5835
|
clientId: client.clientId,
|
|
5729
5836
|
config,
|
|
5730
5837
|
dpopJkt: dpopResult?.jkt,
|
|
@@ -5733,7 +5840,7 @@ var oidcProviderRoutes = (config) => {
|
|
|
5733
5840
|
sub: record.userId
|
|
5734
5841
|
}));
|
|
5735
5842
|
};
|
|
5736
|
-
const grantRefreshToken = async (client, body, dpop) => {
|
|
5843
|
+
const grantRefreshToken = async (client, body, dpop, clientCertThumbprint) => {
|
|
5737
5844
|
const presented = body.refresh_token;
|
|
5738
5845
|
if (presented === undefined) {
|
|
5739
5846
|
return oauthError2(HTTP_BAD_REQUEST2, "invalid_request");
|
|
@@ -5755,6 +5862,7 @@ var oidcProviderRoutes = (config) => {
|
|
|
5755
5862
|
return tokenResponse(await issueTokenSet({
|
|
5756
5863
|
acr: record.acr,
|
|
5757
5864
|
claims: record.claims,
|
|
5865
|
+
clientCertThumbprint,
|
|
5758
5866
|
clientId: client.clientId,
|
|
5759
5867
|
config,
|
|
5760
5868
|
dpopJkt: record.dpopJkt,
|
|
@@ -5792,7 +5900,7 @@ var oidcProviderRoutes = (config) => {
|
|
|
5792
5900
|
token_type: dpopResult === undefined ? "Bearer" : "DPoP"
|
|
5793
5901
|
}, HTTP_OK2);
|
|
5794
5902
|
};
|
|
5795
|
-
const grantBackchannel = async (client, body, dpop) => {
|
|
5903
|
+
const grantBackchannel = async (client, body, dpop, clientCertThumbprint) => {
|
|
5796
5904
|
if (config.backchannelAuthStore === undefined) {
|
|
5797
5905
|
return oauthError2(HTTP_BAD_REQUEST2, "unsupported_grant_type");
|
|
5798
5906
|
}
|
|
@@ -5809,6 +5917,7 @@ var oidcProviderRoutes = (config) => {
|
|
|
5809
5917
|
}
|
|
5810
5918
|
const result = await exchangeBackchannelAuth({
|
|
5811
5919
|
authReqId: body.auth_req_id,
|
|
5920
|
+
clientCertThumbprint,
|
|
5812
5921
|
clientId: client.clientId,
|
|
5813
5922
|
config,
|
|
5814
5923
|
dpopJkt: dpopResult?.jkt
|
|
@@ -5885,12 +5994,14 @@ var oidcProviderRoutes = (config) => {
|
|
|
5885
5994
|
response_types_supported: ["code"],
|
|
5886
5995
|
revocation_endpoint: `${issuer}${revokeRoute}`,
|
|
5887
5996
|
subject_types_supported: ["public"],
|
|
5997
|
+
tls_client_certificate_bound_access_tokens: true,
|
|
5888
5998
|
token_endpoint: tokenUrl,
|
|
5889
5999
|
token_endpoint_auth_methods_supported: [
|
|
5890
6000
|
"client_secret_basic",
|
|
5891
6001
|
"client_secret_post",
|
|
5892
6002
|
"none",
|
|
5893
|
-
"private_key_jwt"
|
|
6003
|
+
"private_key_jwt",
|
|
6004
|
+
"self_signed_tls_client_auth"
|
|
5894
6005
|
],
|
|
5895
6006
|
token_endpoint_auth_signing_alg_values_supported: ["ES256"],
|
|
5896
6007
|
userinfo_endpoint: `${issuer}${userinfoRoute}`
|
|
@@ -6097,27 +6208,29 @@ var oidcProviderRoutes = (config) => {
|
|
|
6097
6208
|
scope: t12.Optional(t12.String()),
|
|
6098
6209
|
state: t12.Optional(t12.String())
|
|
6099
6210
|
})
|
|
6100
|
-
}).post(tokenRoute, async ({ body, headers }) => {
|
|
6211
|
+
}).post(tokenRoute, async ({ body, headers, request }) => {
|
|
6101
6212
|
const basic = readBasicAuth2(headers.authorization);
|
|
6102
|
-
const
|
|
6213
|
+
const auth = await authenticateTokenClient({
|
|
6103
6214
|
basicClientId: basic.clientId,
|
|
6104
6215
|
basicClientSecret: basic.clientSecret,
|
|
6105
6216
|
bodyClientAssertion: body.client_assertion,
|
|
6106
6217
|
bodyClientAssertionType: body.client_assertion_type,
|
|
6107
6218
|
bodyClientId: body.client_id,
|
|
6108
|
-
bodyClientSecret: body.client_secret
|
|
6219
|
+
bodyClientSecret: body.client_secret,
|
|
6220
|
+
requestHeaders: request.headers
|
|
6109
6221
|
});
|
|
6110
|
-
if (
|
|
6222
|
+
if (auth === undefined) {
|
|
6111
6223
|
return oauthError2(HTTP_UNAUTHORIZED2, "invalid_client");
|
|
6112
6224
|
}
|
|
6225
|
+
const { client, clientCertThumbprint } = auth;
|
|
6113
6226
|
const nonceChallenge = await dpopNonceChallenge(headers.dpop);
|
|
6114
6227
|
if (nonceChallenge !== undefined)
|
|
6115
6228
|
return nonceChallenge;
|
|
6116
6229
|
if (body.grant_type === "authorization_code") {
|
|
6117
|
-
return grantAuthorizationCode(client, body, headers.dpop);
|
|
6230
|
+
return grantAuthorizationCode(client, body, headers.dpop, clientCertThumbprint);
|
|
6118
6231
|
}
|
|
6119
6232
|
if (body.grant_type === "refresh_token") {
|
|
6120
|
-
return grantRefreshToken(client, body, headers.dpop);
|
|
6233
|
+
return grantRefreshToken(client, body, headers.dpop, clientCertThumbprint);
|
|
6121
6234
|
}
|
|
6122
6235
|
if (body.grant_type === "urn:ietf:params:oauth:grant-type:token-exchange") {
|
|
6123
6236
|
return grantTokenExchange(client, body, headers.dpop);
|
|
@@ -6126,7 +6239,7 @@ var oidcProviderRoutes = (config) => {
|
|
|
6126
6239
|
return grantDeviceCode(client, body, headers.dpop);
|
|
6127
6240
|
}
|
|
6128
6241
|
if (body.grant_type === CIBA_GRANT_TYPE) {
|
|
6129
|
-
return grantBackchannel(client, body, headers.dpop);
|
|
6242
|
+
return grantBackchannel(client, body, headers.dpop, clientCertThumbprint);
|
|
6130
6243
|
}
|
|
6131
6244
|
return oauthError2(HTTP_BAD_REQUEST2, "unsupported_grant_type");
|
|
6132
6245
|
}, {
|
|
@@ -6148,22 +6261,24 @@ var oidcProviderRoutes = (config) => {
|
|
|
6148
6261
|
subject_token: t12.Optional(t12.String()),
|
|
6149
6262
|
subject_token_type: t12.Optional(t12.String())
|
|
6150
6263
|
})
|
|
6151
|
-
}).post(parRoute, async ({ body, headers }) => {
|
|
6264
|
+
}).post(parRoute, async ({ body, headers, request }) => {
|
|
6152
6265
|
if (config.pushedAuthorizationRequestStore === undefined) {
|
|
6153
6266
|
return oauthError2(HTTP_NOT_IMPLEMENTED, "unsupported_response_type");
|
|
6154
6267
|
}
|
|
6155
6268
|
const basic = readBasicAuth2(headers.authorization);
|
|
6156
|
-
const
|
|
6269
|
+
const auth = await authenticateTokenClient({
|
|
6157
6270
|
basicClientId: basic.clientId,
|
|
6158
6271
|
basicClientSecret: basic.clientSecret,
|
|
6159
6272
|
bodyClientAssertion: body.client_assertion,
|
|
6160
6273
|
bodyClientAssertionType: body.client_assertion_type,
|
|
6161
6274
|
bodyClientId: body.client_id,
|
|
6162
|
-
bodyClientSecret: body.client_secret
|
|
6275
|
+
bodyClientSecret: body.client_secret,
|
|
6276
|
+
requestHeaders: request.headers
|
|
6163
6277
|
});
|
|
6164
|
-
if (
|
|
6278
|
+
if (auth === undefined) {
|
|
6165
6279
|
return oauthError2(HTTP_UNAUTHORIZED2, "invalid_client");
|
|
6166
6280
|
}
|
|
6281
|
+
const { client } = auth;
|
|
6167
6282
|
const isAuthField = (key) => key === "client_assertion" || key === "client_assertion_type" || key === "client_secret";
|
|
6168
6283
|
const params = Object.fromEntries(Object.entries(body).filter((entry) => typeof entry[1] === "string" && !isAuthField(entry[0])));
|
|
6169
6284
|
const result = await pushAuthorizationRequest({
|
|
@@ -20671,6 +20786,132 @@ var switchActiveSession = ({
|
|
|
20671
20786
|
};
|
|
20672
20787
|
// src/tenancy.ts
|
|
20673
20788
|
var hasOrganizationScope = (value) => typeof value.organizationId === "string" && value.organizationId.length > 0;
|
|
20789
|
+
// src/credentials/backgroundOps.ts
|
|
20790
|
+
var HIBP_BREACHED_ACCOUNT_URL = "https://haveibeenpwned.com/api/v3/breachedaccount/";
|
|
20791
|
+
var HIBP_USER_AGENT = "@absolutejs/auth breach scanner";
|
|
20792
|
+
var DEFAULT_PAUSE_MS = 1700;
|
|
20793
|
+
var HIBP_NOT_FOUND = 404;
|
|
20794
|
+
var HIBP_RATE_LIMITED = 429;
|
|
20795
|
+
var MS_PER_DAY = 86400000;
|
|
20796
|
+
var MS_PER_SECOND3 = 1000;
|
|
20797
|
+
var sleep = (delayMs) => new Promise((resolve) => {
|
|
20798
|
+
setTimeout(resolve, delayMs);
|
|
20799
|
+
});
|
|
20800
|
+
var isBreachRecord = (entry) => {
|
|
20801
|
+
if (typeof entry !== "object" || entry === null)
|
|
20802
|
+
return false;
|
|
20803
|
+
if (!("name" in entry))
|
|
20804
|
+
return false;
|
|
20805
|
+
const candidate = entry;
|
|
20806
|
+
return typeof candidate.name === "string";
|
|
20807
|
+
};
|
|
20808
|
+
var isBreachRecordArray = (value) => Array.isArray(value) && value.every(isBreachRecord);
|
|
20809
|
+
var checkEmailBreaches = async (email, apiKey, truncate) => {
|
|
20810
|
+
const url = `${HIBP_BREACHED_ACCOUNT_URL}${encodeURIComponent(email)}?truncateResponse=${truncate ? "true" : "false"}`;
|
|
20811
|
+
const response = await fetch(url, {
|
|
20812
|
+
headers: {
|
|
20813
|
+
"hibp-api-key": apiKey,
|
|
20814
|
+
"user-agent": HIBP_USER_AGENT
|
|
20815
|
+
}
|
|
20816
|
+
});
|
|
20817
|
+
if (response.status === HIBP_NOT_FOUND)
|
|
20818
|
+
return [];
|
|
20819
|
+
if (response.status === HIBP_RATE_LIMITED) {
|
|
20820
|
+
const retryAfter = Number(response.headers.get("retry-after") ?? "0");
|
|
20821
|
+
if (retryAfter > 0)
|
|
20822
|
+
await sleep(retryAfter * MS_PER_SECOND3);
|
|
20823
|
+
return [];
|
|
20824
|
+
}
|
|
20825
|
+
if (!response.ok)
|
|
20826
|
+
return [];
|
|
20827
|
+
const body = await response.json();
|
|
20828
|
+
if (!isBreachRecordArray(body))
|
|
20829
|
+
return [];
|
|
20830
|
+
return body;
|
|
20831
|
+
};
|
|
20832
|
+
var scanEmail = async (email, apiKey, truncate, onBreachFound) => {
|
|
20833
|
+
const breaches = await checkEmailBreaches(email, apiKey, truncate);
|
|
20834
|
+
if (breaches.length === 0)
|
|
20835
|
+
return false;
|
|
20836
|
+
await onBreachFound({ breaches, email });
|
|
20837
|
+
return true;
|
|
20838
|
+
};
|
|
20839
|
+
var scanPage = async (options) => {
|
|
20840
|
+
let scanned = 0;
|
|
20841
|
+
let breached = 0;
|
|
20842
|
+
for (const email of options.emails) {
|
|
20843
|
+
scanned += 1;
|
|
20844
|
+
const hit = await scanEmail(email, options.apiKey, options.truncate, options.onBreachFound);
|
|
20845
|
+
if (hit)
|
|
20846
|
+
breached += 1;
|
|
20847
|
+
await sleep(options.pauseMs);
|
|
20848
|
+
}
|
|
20849
|
+
return { breached, scanned };
|
|
20850
|
+
};
|
|
20851
|
+
var runEmailBreachScan = async (input) => {
|
|
20852
|
+
const pauseMs = input.pauseMs ?? DEFAULT_PAUSE_MS;
|
|
20853
|
+
const truncate = input.truncateResponse ?? true;
|
|
20854
|
+
let scanned = 0;
|
|
20855
|
+
let breached = 0;
|
|
20856
|
+
let cursor;
|
|
20857
|
+
do {
|
|
20858
|
+
const page = await input.iterateEmails(cursor);
|
|
20859
|
+
const tally = await scanPage({
|
|
20860
|
+
apiKey: input.hibpApiKey,
|
|
20861
|
+
emails: page.emails,
|
|
20862
|
+
onBreachFound: input.onBreachFound,
|
|
20863
|
+
pauseMs,
|
|
20864
|
+
truncate
|
|
20865
|
+
});
|
|
20866
|
+
scanned += tally.scanned;
|
|
20867
|
+
breached += tally.breached;
|
|
20868
|
+
cursor = page.nextCursor;
|
|
20869
|
+
} while (cursor !== undefined);
|
|
20870
|
+
const result = { breached, scanned };
|
|
20871
|
+
return result;
|
|
20872
|
+
};
|
|
20873
|
+
var pruneCandidate = async (candidate, cutoff, dryRun, onDelete) => {
|
|
20874
|
+
const reference = candidate.lastLoginAt ?? candidate.createdAt;
|
|
20875
|
+
if (reference === undefined || reference === null)
|
|
20876
|
+
return false;
|
|
20877
|
+
if (reference >= cutoff)
|
|
20878
|
+
return false;
|
|
20879
|
+
if (!dryRun)
|
|
20880
|
+
await onDelete(candidate.userId);
|
|
20881
|
+
return true;
|
|
20882
|
+
};
|
|
20883
|
+
var prunePage = async (options) => {
|
|
20884
|
+
const pruned = [];
|
|
20885
|
+
for (const candidate of options.candidates) {
|
|
20886
|
+
const removed = await pruneCandidate(candidate, options.cutoff, options.dryRun, options.onDelete);
|
|
20887
|
+
if (removed)
|
|
20888
|
+
pruned.push(candidate.userId);
|
|
20889
|
+
}
|
|
20890
|
+
return pruned;
|
|
20891
|
+
};
|
|
20892
|
+
var pruneInactiveUsers = async (input) => {
|
|
20893
|
+
const now = input.now?.() ?? Date.now();
|
|
20894
|
+
const thresholdMs = input.olderThanDays * MS_PER_DAY;
|
|
20895
|
+
const cutoff = now - thresholdMs;
|
|
20896
|
+
const dryRun = input.dryRun ?? false;
|
|
20897
|
+
const prunedUserIds = [];
|
|
20898
|
+
let scanned = 0;
|
|
20899
|
+
let cursor;
|
|
20900
|
+
do {
|
|
20901
|
+
const page = await input.iterateUsers(cursor);
|
|
20902
|
+
scanned += page.users.length;
|
|
20903
|
+
const removed = await prunePage({
|
|
20904
|
+
candidates: page.users,
|
|
20905
|
+
cutoff,
|
|
20906
|
+
dryRun,
|
|
20907
|
+
onDelete: input.onDelete
|
|
20908
|
+
});
|
|
20909
|
+
prunedUserIds.push(...removed);
|
|
20910
|
+
cursor = page.nextCursor;
|
|
20911
|
+
} while (cursor !== undefined);
|
|
20912
|
+
const result = { dryRun, prunedUserIds, scanned };
|
|
20913
|
+
return result;
|
|
20914
|
+
};
|
|
20674
20915
|
// src/credentials/emailValidation.ts
|
|
20675
20916
|
import { resolveMx } from "dns/promises";
|
|
20676
20917
|
var EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/u;
|
|
@@ -24240,6 +24481,7 @@ export {
|
|
|
24240
24481
|
verifyDpopNonce,
|
|
24241
24482
|
verifyCognitoSha256,
|
|
24242
24483
|
verifyClientAssertion,
|
|
24484
|
+
verifyCertificateBoundToken,
|
|
24243
24485
|
verifyAuth0Pbkdf2,
|
|
24244
24486
|
verifyAuditChain,
|
|
24245
24487
|
verifyApiKey,
|
|
@@ -24272,6 +24514,7 @@ export {
|
|
|
24272
24514
|
samlServiceProvidersTable,
|
|
24273
24515
|
samlIdpRoutes,
|
|
24274
24516
|
runMigrations,
|
|
24517
|
+
runEmailBreachScan,
|
|
24275
24518
|
rotateVaultKey,
|
|
24276
24519
|
rotateMfaEncryptionKey,
|
|
24277
24520
|
rolesTable,
|
|
@@ -24288,6 +24531,7 @@ export {
|
|
|
24288
24531
|
resolveOAuthAuthorization,
|
|
24289
24532
|
resolveCookieSecure,
|
|
24290
24533
|
resolveClientProviderEntry,
|
|
24534
|
+
resolveClientCert,
|
|
24291
24535
|
resolveAuthHtmxRenderers,
|
|
24292
24536
|
resolveApiPrincipal,
|
|
24293
24537
|
removeFromSessionRing,
|
|
@@ -24298,6 +24542,7 @@ export {
|
|
|
24298
24542
|
readUserInfoBearer,
|
|
24299
24543
|
readSessionRing,
|
|
24300
24544
|
pushAuthorizationRequest,
|
|
24545
|
+
pruneInactiveUsers,
|
|
24301
24546
|
providers,
|
|
24302
24547
|
providerOptions,
|
|
24303
24548
|
protectRoutePlugin,
|
|
@@ -24384,6 +24629,7 @@ export {
|
|
|
24384
24629
|
fingerprintDevice,
|
|
24385
24630
|
fetchUserInfo,
|
|
24386
24631
|
fanOutBackchannelLogout,
|
|
24632
|
+
extractRfc9440ClientCert,
|
|
24387
24633
|
extractPropFromIdentity,
|
|
24388
24634
|
extractDpopNonceClaim,
|
|
24389
24635
|
exportAuditCsv,
|
|
@@ -24543,6 +24789,7 @@ export {
|
|
|
24543
24789
|
consumePushedRequest,
|
|
24544
24790
|
consumeBackupCode,
|
|
24545
24791
|
constantTimeEqual,
|
|
24792
|
+
computeCertThumbprint,
|
|
24546
24793
|
complianceRoutes,
|
|
24547
24794
|
check,
|
|
24548
24795
|
buildClientProviders,
|
|
@@ -24599,5 +24846,5 @@ export {
|
|
|
24599
24846
|
AuthIdentityConflictError
|
|
24600
24847
|
};
|
|
24601
24848
|
|
|
24602
|
-
//# debugId=
|
|
24849
|
+
//# debugId=26C38ACE51F8A69A64756E2164756E21
|
|
24603
24850
|
//# sourceMappingURL=index.js.map
|