@robelest/convex-auth 0.0.4-preview.21 → 0.0.4-preview.23
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/authorization/index.d.ts +1 -1
- package/dist/authorization/index.js +1 -1
- package/dist/authorization/index.js.map +1 -1
- package/dist/client/index.d.ts +1 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +36 -39
- package/dist/client/index.js.map +1 -1
- package/dist/component/client/index.d.ts +1 -2
- package/dist/component/convex.config.d.ts +2 -2
- package/dist/component/convex.config.d.ts.map +1 -1
- package/dist/component/model.d.ts +5 -5
- package/dist/component/model.d.ts.map +1 -1
- package/dist/component/public/enterprise/audit.d.ts.map +1 -1
- package/dist/component/public/enterprise/audit.js.map +1 -1
- package/dist/component/public/enterprise/core.d.ts.map +1 -1
- package/dist/component/public/enterprise/core.js.map +1 -1
- package/dist/component/public/enterprise/domains.d.ts.map +1 -1
- package/dist/component/public/enterprise/domains.js.map +1 -1
- package/dist/component/public/enterprise/scim.d.ts.map +1 -1
- package/dist/component/public/enterprise/scim.js.map +1 -1
- package/dist/component/public/enterprise/secrets.d.ts.map +1 -1
- package/dist/component/public/enterprise/secrets.js.map +1 -1
- package/dist/component/public/enterprise/webhooks.d.ts.map +1 -1
- package/dist/component/public/enterprise/webhooks.js.map +1 -1
- package/dist/component/public/factors/devices.d.ts.map +1 -1
- package/dist/component/public/factors/devices.js.map +1 -1
- package/dist/component/public/factors/passkeys.d.ts.map +1 -1
- package/dist/component/public/factors/passkeys.js.map +1 -1
- package/dist/component/public/factors/totp.d.ts.map +1 -1
- package/dist/component/public/factors/totp.js.map +1 -1
- package/dist/component/public/groups/core.js.map +1 -1
- package/dist/component/public/groups/invites.d.ts.map +1 -1
- package/dist/component/public/groups/invites.js.map +1 -1
- package/dist/component/public/groups/members.d.ts.map +1 -1
- package/dist/component/public/groups/members.js.map +1 -1
- package/dist/component/public/identity/accounts.d.ts.map +1 -1
- package/dist/component/public/identity/accounts.js.map +1 -1
- package/dist/component/public/identity/codes.d.ts.map +1 -1
- package/dist/component/public/identity/codes.js.map +1 -1
- package/dist/component/public/identity/sessions.d.ts.map +1 -1
- package/dist/component/public/identity/sessions.js.map +1 -1
- package/dist/component/public/identity/tokens.d.ts.map +1 -1
- package/dist/component/public/identity/tokens.js.map +1 -1
- package/dist/component/public/identity/users.d.ts.map +1 -1
- package/dist/component/public/identity/users.js.map +1 -1
- package/dist/component/public/identity/verifiers.d.ts.map +1 -1
- package/dist/component/public/identity/verifiers.js.map +1 -1
- package/dist/component/public/security/keys.d.ts.map +1 -1
- package/dist/component/public/security/keys.js.map +1 -1
- package/dist/component/public/security/limits.d.ts.map +1 -1
- package/dist/component/public/security/limits.js.map +1 -1
- package/dist/component/schema.d.ts +39 -39
- package/dist/component/server/auth.d.ts +95 -52
- package/dist/component/server/auth.d.ts.map +1 -1
- package/dist/component/server/auth.js +63 -43
- package/dist/component/server/auth.js.map +1 -1
- package/dist/component/server/core.js +116 -235
- package/dist/component/server/core.js.map +1 -1
- package/dist/component/server/crypto.js +25 -7
- package/dist/component/server/crypto.js.map +1 -1
- package/dist/component/server/device.js +58 -15
- package/dist/component/server/device.js.map +1 -1
- package/dist/component/server/enterprise/domain.js +148 -59
- package/dist/component/server/enterprise/domain.js.map +1 -1
- package/dist/component/server/enterprise/http.js +36 -15
- package/dist/component/server/enterprise/http.js.map +1 -1
- package/dist/component/server/enterprise/oidc.js +1 -1
- package/dist/component/server/http.js +26 -21
- package/dist/component/server/http.js.map +1 -1
- package/dist/component/server/identity.js +5 -2
- package/dist/component/server/identity.js.map +1 -1
- package/dist/component/server/limits.js +21 -30
- package/dist/component/server/limits.js.map +1 -1
- package/dist/component/server/mutations/account.js +12 -10
- package/dist/component/server/mutations/account.js.map +1 -1
- package/dist/component/server/mutations/code.js +5 -2
- package/dist/component/server/mutations/code.js.map +1 -1
- package/dist/component/server/mutations/invalidate.js +1 -1
- package/dist/component/server/mutations/invalidate.js.map +1 -1
- package/dist/component/server/mutations/oauth.js +10 -4
- package/dist/component/server/mutations/oauth.js.map +1 -1
- package/dist/component/server/mutations/refresh.js +2 -2
- package/dist/component/server/mutations/refresh.js.map +1 -1
- package/dist/component/server/mutations/register.js +46 -42
- package/dist/component/server/mutations/register.js.map +1 -1
- package/dist/component/server/mutations/retrieve.js +21 -25
- package/dist/component/server/mutations/retrieve.js.map +1 -1
- package/dist/component/server/mutations/signature.js +10 -4
- package/dist/component/server/mutations/signature.js.map +1 -1
- package/dist/component/server/mutations/signout.js.map +1 -1
- package/dist/component/server/mutations/store.js +9 -24
- package/dist/component/server/mutations/store.js.map +1 -1
- package/dist/component/server/mutations/verifier.js.map +1 -1
- package/dist/component/server/mutations/verify.js +1 -1
- package/dist/component/server/mutations/verify.js.map +1 -1
- package/dist/component/server/oauth.js +53 -16
- package/dist/component/server/oauth.js.map +1 -1
- package/dist/component/server/passkey.js +115 -31
- package/dist/component/server/passkey.js.map +1 -1
- package/dist/component/server/redirects.js +9 -3
- package/dist/component/server/redirects.js.map +1 -1
- package/dist/component/server/refresh.js +10 -7
- package/dist/component/server/refresh.js.map +1 -1
- package/dist/component/server/runtime.d.ts +3 -3
- package/dist/component/server/runtime.d.ts.map +1 -1
- package/dist/component/server/runtime.js +62 -20
- package/dist/component/server/runtime.js.map +1 -1
- package/dist/component/server/signin.js +34 -10
- package/dist/component/server/signin.js.map +1 -1
- package/dist/component/server/totp.js +79 -19
- package/dist/component/server/totp.js.map +1 -1
- package/dist/component/server/types.d.ts +12 -20
- package/dist/component/server/types.d.ts.map +1 -1
- package/dist/component/server/types.js.map +1 -1
- package/dist/component/server/users.js +6 -3
- package/dist/component/server/users.js.map +1 -1
- package/dist/component/server/utils.js +10 -4
- package/dist/component/server/utils.js.map +1 -1
- package/dist/core/types.d.ts +14 -22
- package/dist/core/types.d.ts.map +1 -1
- package/dist/factors/device.js +8 -9
- package/dist/factors/device.js.map +1 -1
- package/dist/factors/passkey.js +18 -21
- package/dist/factors/passkey.js.map +1 -1
- package/dist/providers/password.js +66 -81
- package/dist/providers/password.js.map +1 -1
- package/dist/runtime/invite.js +2 -8
- package/dist/runtime/invite.js.map +1 -1
- package/dist/server/auth.d.ts +95 -52
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +63 -43
- package/dist/server/auth.js.map +1 -1
- package/dist/server/core.d.ts +71 -159
- package/dist/server/core.d.ts.map +1 -1
- package/dist/server/core.js +116 -235
- package/dist/server/core.js.map +1 -1
- package/dist/server/crypto.d.ts.map +1 -1
- package/dist/server/crypto.js +25 -7
- package/dist/server/crypto.js.map +1 -1
- package/dist/server/device.js +58 -15
- package/dist/server/device.js.map +1 -1
- package/dist/server/enterprise/domain.d.ts +0 -8
- package/dist/server/enterprise/domain.d.ts.map +1 -1
- package/dist/server/enterprise/domain.js +148 -59
- package/dist/server/enterprise/domain.js.map +1 -1
- package/dist/server/enterprise/http.d.ts.map +1 -1
- package/dist/server/enterprise/http.js +35 -14
- package/dist/server/enterprise/http.js.map +1 -1
- package/dist/server/http.d.ts +2 -2
- package/dist/server/http.d.ts.map +1 -1
- package/dist/server/http.js +25 -20
- package/dist/server/http.js.map +1 -1
- package/dist/server/identity.js +5 -2
- package/dist/server/identity.js.map +1 -1
- package/dist/server/index.d.ts +2 -2
- package/dist/server/limits.js +21 -30
- package/dist/server/limits.js.map +1 -1
- package/dist/server/mounts.d.ts +26 -64
- package/dist/server/mounts.d.ts.map +1 -1
- package/dist/server/mounts.js +45 -106
- package/dist/server/mounts.js.map +1 -1
- package/dist/server/mutations/account.d.ts +8 -9
- package/dist/server/mutations/account.d.ts.map +1 -1
- package/dist/server/mutations/account.js +11 -9
- package/dist/server/mutations/account.js.map +1 -1
- package/dist/server/mutations/code.d.ts +13 -13
- package/dist/server/mutations/code.d.ts.map +1 -1
- package/dist/server/mutations/code.js +5 -2
- package/dist/server/mutations/code.js.map +1 -1
- package/dist/server/mutations/invalidate.d.ts +4 -4
- package/dist/server/mutations/invalidate.d.ts.map +1 -1
- package/dist/server/mutations/invalidate.js.map +1 -1
- package/dist/server/mutations/oauth.d.ts +12 -10
- package/dist/server/mutations/oauth.d.ts.map +1 -1
- package/dist/server/mutations/oauth.js +9 -3
- package/dist/server/mutations/oauth.js.map +1 -1
- package/dist/server/mutations/refresh.d.ts +3 -3
- package/dist/server/mutations/refresh.d.ts.map +1 -1
- package/dist/server/mutations/refresh.js +1 -1
- package/dist/server/mutations/refresh.js.map +1 -1
- package/dist/server/mutations/register.d.ts +11 -11
- package/dist/server/mutations/register.d.ts.map +1 -1
- package/dist/server/mutations/register.js +45 -41
- package/dist/server/mutations/register.js.map +1 -1
- package/dist/server/mutations/retrieve.d.ts +6 -6
- package/dist/server/mutations/retrieve.d.ts.map +1 -1
- package/dist/server/mutations/retrieve.js +20 -24
- package/dist/server/mutations/retrieve.js.map +1 -1
- package/dist/server/mutations/signature.d.ts +6 -7
- package/dist/server/mutations/signature.d.ts.map +1 -1
- package/dist/server/mutations/signature.js +9 -3
- package/dist/server/mutations/signature.js.map +1 -1
- package/dist/server/mutations/signin.d.ts +5 -5
- package/dist/server/mutations/signin.d.ts.map +1 -1
- package/dist/server/mutations/signout.js.map +1 -1
- package/dist/server/mutations/store.d.ts +97 -97
- package/dist/server/mutations/store.d.ts.map +1 -1
- package/dist/server/mutations/store.js +8 -23
- package/dist/server/mutations/store.js.map +1 -1
- package/dist/server/mutations/verifier.js.map +1 -1
- package/dist/server/mutations/verify.d.ts +10 -10
- package/dist/server/mutations/verify.d.ts.map +1 -1
- package/dist/server/mutations/verify.js.map +1 -1
- package/dist/server/oauth.js +53 -16
- package/dist/server/oauth.js.map +1 -1
- package/dist/server/passkey.d.ts +2 -2
- package/dist/server/passkey.d.ts.map +1 -1
- package/dist/server/passkey.js +114 -30
- package/dist/server/passkey.js.map +1 -1
- package/dist/server/redirects.js +9 -3
- package/dist/server/redirects.js.map +1 -1
- package/dist/server/refresh.js +10 -7
- package/dist/server/refresh.js.map +1 -1
- package/dist/server/runtime.d.ts +14 -14
- package/dist/server/runtime.d.ts.map +1 -1
- package/dist/server/runtime.js +61 -19
- package/dist/server/runtime.js.map +1 -1
- package/dist/server/signin.js +34 -10
- package/dist/server/signin.js.map +1 -1
- package/dist/server/ssr.d.ts.map +1 -1
- package/dist/server/ssr.js +175 -184
- package/dist/server/ssr.js.map +1 -1
- package/dist/server/totp.js +78 -18
- package/dist/server/totp.js.map +1 -1
- package/dist/server/types.d.ts +13 -21
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/types.js.map +1 -1
- package/dist/server/users.js +6 -3
- package/dist/server/users.js.map +1 -1
- package/dist/server/utils.js +10 -4
- package/dist/server/utils.js.map +1 -1
- package/package.json +2 -6
- package/src/authorization/index.ts +1 -1
- package/src/cli/index.ts +1 -1
- package/src/client/core/types.ts +14 -14
- package/src/client/factors/device.ts +10 -12
- package/src/client/factors/passkey.ts +23 -26
- package/src/client/index.ts +54 -64
- package/src/client/runtime/invite.ts +5 -7
- package/src/component/index.ts +1 -0
- package/src/component/public/enterprise/audit.ts +6 -1
- package/src/component/public/enterprise/core.ts +1 -0
- package/src/component/public/enterprise/domains.ts +5 -1
- package/src/component/public/enterprise/scim.ts +1 -0
- package/src/component/public/enterprise/secrets.ts +1 -0
- package/src/component/public/enterprise/webhooks.ts +1 -0
- package/src/component/public/factors/devices.ts +1 -0
- package/src/component/public/factors/passkeys.ts +1 -0
- package/src/component/public/factors/totp.ts +1 -0
- package/src/component/public/groups/core.ts +1 -1
- package/src/component/public/groups/invites.ts +7 -1
- package/src/component/public/groups/members.ts +1 -0
- package/src/component/public/identity/accounts.ts +1 -0
- package/src/component/public/identity/codes.ts +1 -0
- package/src/component/public/identity/sessions.ts +1 -0
- package/src/component/public/identity/tokens.ts +1 -0
- package/src/component/public/identity/users.ts +1 -0
- package/src/component/public/identity/verifiers.ts +1 -0
- package/src/component/public/security/keys.ts +1 -0
- package/src/component/public/security/limits.ts +1 -0
- package/src/providers/password.ts +89 -110
- package/src/server/auth.ts +177 -111
- package/src/server/core.ts +197 -233
- package/src/server/crypto.ts +31 -29
- package/src/server/device.ts +65 -32
- package/src/server/enterprise/domain.ts +158 -170
- package/src/server/enterprise/http.ts +46 -39
- package/src/server/http.ts +36 -30
- package/src/server/identity.ts +5 -5
- package/src/server/index.ts +2 -0
- package/src/server/limits.ts +53 -80
- package/src/server/mounts.ts +47 -74
- package/src/server/mutations/account.ts +22 -36
- package/src/server/mutations/code.ts +6 -6
- package/src/server/mutations/invalidate.ts +1 -1
- package/src/server/mutations/oauth.ts +14 -8
- package/src/server/mutations/refresh.ts +5 -4
- package/src/server/mutations/register.ts +87 -132
- package/src/server/mutations/retrieve.ts +44 -44
- package/src/server/mutations/signature.ts +13 -6
- package/src/server/mutations/signout.ts +1 -1
- package/src/server/mutations/store.ts +16 -31
- package/src/server/mutations/verifier.ts +1 -1
- package/src/server/mutations/verify.ts +3 -5
- package/src/server/oauth.ts +60 -69
- package/src/server/passkey.ts +567 -517
- package/src/server/redirects.ts +10 -6
- package/src/server/refresh.ts +14 -18
- package/src/server/runtime.ts +70 -55
- package/src/server/signin.ts +44 -37
- package/src/server/ssr.ts +390 -407
- package/src/server/totp.ts +85 -35
- package/src/server/types.ts +19 -22
- package/src/server/users.ts +7 -6
- package/src/server/utils.ts +10 -12
- package/dist/component/server/authError.js +0 -34
- package/dist/component/server/authError.js.map +0 -1
- package/dist/component/server/errors.d.ts +0 -1
- package/dist/component/server/errors.js +0 -137
- package/dist/component/server/errors.js.map +0 -1
- package/dist/server/authError.d.ts +0 -46
- package/dist/server/authError.d.ts.map +0 -1
- package/dist/server/authError.js +0 -34
- package/dist/server/authError.js.map +0 -1
- package/dist/server/errors.d.ts +0 -177
- package/dist/server/errors.d.ts.map +0 -1
- package/dist/server/errors.js +0 -212
- package/dist/server/errors.js.map +0 -1
- package/src/server/authError.ts +0 -44
- package/src/server/errors.ts +0 -290
|
@@ -1,11 +1,10 @@
|
|
|
1
|
+
import { Fx } from "@robelest/fx";
|
|
2
|
+
import { Cv } from "@robelest/fx/convex";
|
|
1
3
|
import type { GenericActionCtx, HttpRouter } from "convex/server";
|
|
4
|
+
import { ConvexError } from "convex/values";
|
|
2
5
|
import { serialize as serializeCookie } from "cookie";
|
|
3
6
|
|
|
4
7
|
import { redirectToParamCookie, useRedirectToParam } from "../cookies";
|
|
5
|
-
import { isAuthError } from "../errors";
|
|
6
|
-
import { Fx } from "@robelest/fx";
|
|
7
|
-
|
|
8
|
-
import { AuthError } from "../authError";
|
|
9
8
|
import { addSSORoutes, convertErrorsToResponse, getCookies } from "../http";
|
|
10
9
|
import type { SSORuntimeRoute } from "../http";
|
|
11
10
|
import { createOAuthAuthorizationURL, handleOAuthCallback } from "../oauth";
|
|
@@ -207,12 +206,10 @@ export function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {
|
|
|
207
206
|
runtimeRoute.protocol !== "saml" ||
|
|
208
207
|
runtimeRoute.rest.length !== 1 ||
|
|
209
208
|
runtimeRoute.rest[0] !== "acs",
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
).toConvexError(),
|
|
215
|
-
),
|
|
209
|
+
Cv.fail({
|
|
210
|
+
code: "INVALID_PARAMETERS",
|
|
211
|
+
message: "Invalid enterprise runtime path.",
|
|
212
|
+
}),
|
|
216
213
|
);
|
|
217
214
|
|
|
218
215
|
const enterpriseId = runtimeRoute.enterpriseId;
|
|
@@ -230,10 +227,10 @@ export function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {
|
|
|
230
227
|
config: loaded.config,
|
|
231
228
|
}),
|
|
232
229
|
err: (e) =>
|
|
233
|
-
|
|
234
|
-
"OAUTH_PROVIDER_ERROR",
|
|
235
|
-
`SAML response parse failed: ${e instanceof Error ? e.message : String(e)}`,
|
|
236
|
-
)
|
|
230
|
+
Cv.error({
|
|
231
|
+
code: "OAUTH_PROVIDER_ERROR",
|
|
232
|
+
message: `SAML response parse failed: ${e instanceof Error ? e.message : String(e)}`,
|
|
233
|
+
}),
|
|
237
234
|
});
|
|
238
235
|
|
|
239
236
|
yield* Fx.from({
|
|
@@ -247,10 +244,11 @@ export function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {
|
|
|
247
244
|
return Promise.resolve();
|
|
248
245
|
},
|
|
249
246
|
err: () =>
|
|
250
|
-
|
|
251
|
-
"OAUTH_INVALID_STATE",
|
|
252
|
-
|
|
253
|
-
|
|
247
|
+
Cv.error({
|
|
248
|
+
code: "OAUTH_INVALID_STATE",
|
|
249
|
+
message:
|
|
250
|
+
"SAML RelayState did not match the pending login request.",
|
|
251
|
+
}),
|
|
254
252
|
});
|
|
255
253
|
|
|
256
254
|
const { samlAttributes, samlSessionIndex, ...userProfile } =
|
|
@@ -331,10 +329,10 @@ export function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {
|
|
|
331
329
|
runtimeRoute.rest.length !== 1 ||
|
|
332
330
|
runtimeRoute.rest[0] !== "slo"
|
|
333
331
|
) {
|
|
334
|
-
throw
|
|
335
|
-
"INVALID_PARAMETERS",
|
|
336
|
-
"Invalid enterprise runtime path.",
|
|
337
|
-
)
|
|
332
|
+
throw Cv.error({
|
|
333
|
+
code: "INVALID_PARAMETERS",
|
|
334
|
+
message: "Invalid enterprise runtime path.",
|
|
335
|
+
});
|
|
338
336
|
}
|
|
339
337
|
const { loaded, enterprise } = await loadActiveEnterpriseSamlOrThrow(
|
|
340
338
|
ctx,
|
|
@@ -371,10 +369,10 @@ export function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {
|
|
|
371
369
|
if (parsedMessage.hasSamlResponse) {
|
|
372
370
|
return new Response(null, { status: 204 });
|
|
373
371
|
}
|
|
374
|
-
throw
|
|
375
|
-
"INVALID_PARAMETERS",
|
|
376
|
-
"Missing SAML logout payload.",
|
|
377
|
-
)
|
|
372
|
+
throw Cv.error({
|
|
373
|
+
code: "INVALID_PARAMETERS",
|
|
374
|
+
message: "Missing SAML logout payload.",
|
|
375
|
+
});
|
|
378
376
|
};
|
|
379
377
|
|
|
380
378
|
const handleScimRequest = async (
|
|
@@ -645,7 +643,7 @@ export function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {
|
|
|
645
643
|
userId,
|
|
646
644
|
data: patchData,
|
|
647
645
|
});
|
|
648
|
-
const resolution = await auth.member.
|
|
646
|
+
const resolution = await auth.member.inspect(state.ctx, {
|
|
649
647
|
groupId: state.enterprise.groupId,
|
|
650
648
|
userId,
|
|
651
649
|
});
|
|
@@ -711,7 +709,7 @@ export function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {
|
|
|
711
709
|
);
|
|
712
710
|
if (missing) return missing;
|
|
713
711
|
const userId = state.parsedPath.resourceId!;
|
|
714
|
-
const resolution = await auth.member.
|
|
712
|
+
const resolution = await auth.member.inspect(state.ctx, {
|
|
715
713
|
groupId: state.enterprise.groupId,
|
|
716
714
|
userId,
|
|
717
715
|
});
|
|
@@ -961,15 +959,12 @@ export function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {
|
|
|
961
959
|
);
|
|
962
960
|
const userId = match?.[1];
|
|
963
961
|
if (userId) {
|
|
964
|
-
const resolution = await auth.member.
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
);
|
|
962
|
+
const resolution = await auth.member.inspect(state.ctx, {
|
|
963
|
+
groupId,
|
|
964
|
+
userId,
|
|
965
|
+
});
|
|
968
966
|
if (resolution.membership) {
|
|
969
|
-
await auth.member.delete(
|
|
970
|
-
state.ctx,
|
|
971
|
-
resolution.membership._id,
|
|
972
|
-
);
|
|
967
|
+
await auth.member.delete(state.ctx, resolution.membership._id);
|
|
973
968
|
}
|
|
974
969
|
}
|
|
975
970
|
}
|
|
@@ -1105,7 +1100,13 @@ export function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {
|
|
|
1105
1100
|
) {
|
|
1106
1101
|
return scimError(400, "invalidFilter", error.message);
|
|
1107
1102
|
}
|
|
1108
|
-
if (
|
|
1103
|
+
if (
|
|
1104
|
+
error instanceof ConvexError &&
|
|
1105
|
+
typeof error.data === "object" &&
|
|
1106
|
+
error.data !== null &&
|
|
1107
|
+
"code" in error.data &&
|
|
1108
|
+
"message" in error.data
|
|
1109
|
+
) {
|
|
1109
1110
|
const code = error.data.code as string;
|
|
1110
1111
|
const status =
|
|
1111
1112
|
code === "MISSING_BEARER_TOKEN" || code === "INVALID_API_KEY"
|
|
@@ -1141,7 +1142,10 @@ export function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {
|
|
|
1141
1142
|
const url = new URL(request.url);
|
|
1142
1143
|
const verifier = url.searchParams.get("code");
|
|
1143
1144
|
if (!verifier) {
|
|
1144
|
-
throw
|
|
1145
|
+
throw Cv.error({
|
|
1146
|
+
code: "OAUTH_MISSING_VERIFIER",
|
|
1147
|
+
message: "Missing sign-in verifier.",
|
|
1148
|
+
});
|
|
1145
1149
|
}
|
|
1146
1150
|
const { loaded, enterprise } = await loadActiveEnterpriseSamlOrThrow(
|
|
1147
1151
|
ctx,
|
|
@@ -1204,7 +1208,10 @@ export function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {
|
|
|
1204
1208
|
const url = new URL(request.url);
|
|
1205
1209
|
const verifier = url.searchParams.get("code");
|
|
1206
1210
|
if (!verifier) {
|
|
1207
|
-
throw
|
|
1211
|
+
throw Cv.error({
|
|
1212
|
+
code: "OAUTH_MISSING_VERIFIER",
|
|
1213
|
+
message: "Missing sign-in verifier.",
|
|
1214
|
+
});
|
|
1208
1215
|
}
|
|
1209
1216
|
const { enterprise, oidc } = await loadEnterpriseOidcOrThrow(
|
|
1210
1217
|
ctx,
|
package/src/server/http.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Fx } from "@robelest/fx";
|
|
2
|
+
import { Cv } from "@robelest/fx/convex";
|
|
1
3
|
import {
|
|
2
4
|
GenericActionCtx,
|
|
3
5
|
GenericDataModel,
|
|
@@ -7,10 +9,6 @@ import {
|
|
|
7
9
|
import { ConvexError } from "convex/values";
|
|
8
10
|
import { parse as parseCookies } from "cookie";
|
|
9
11
|
|
|
10
|
-
import { isAuthError } from "./errors";
|
|
11
|
-
import { Fx } from "@robelest/fx";
|
|
12
|
-
|
|
13
|
-
import { AuthError } from "./authError";
|
|
14
12
|
import type { CorsConfig, HttpKeyContext } from "./types";
|
|
15
13
|
import { logError } from "./utils";
|
|
16
14
|
|
|
@@ -59,19 +57,21 @@ export function createHttpAction(auth: {
|
|
|
59
57
|
const rawKey = authHeader.slice(7);
|
|
60
58
|
|
|
61
59
|
const keyResult = await Fx.run(
|
|
62
|
-
Fx.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
Fx.fold({
|
|
67
|
-
ok: (result) => ({ ok: true, value: result }) as const,
|
|
68
|
-
err: (error) => ({ ok: false, error }) as const,
|
|
69
|
-
}),
|
|
60
|
+
Fx.attempt(
|
|
61
|
+
() => auth.key.verify(genericCtx, rawKey),
|
|
62
|
+
(result) => ({ ok: true, value: result }) as const,
|
|
63
|
+
(error) => ({ ok: false, error }) as const,
|
|
70
64
|
),
|
|
71
65
|
);
|
|
72
66
|
|
|
73
67
|
if (!keyResult.ok) {
|
|
74
|
-
if (
|
|
68
|
+
if (
|
|
69
|
+
keyResult.error instanceof ConvexError &&
|
|
70
|
+
typeof keyResult.error.data === "object" &&
|
|
71
|
+
keyResult.error.data !== null &&
|
|
72
|
+
"code" in keyResult.error.data &&
|
|
73
|
+
"message" in keyResult.error.data
|
|
74
|
+
) {
|
|
75
75
|
const { code, message } = keyResult.error.data as {
|
|
76
76
|
code: string;
|
|
77
77
|
message: string;
|
|
@@ -219,7 +219,13 @@ export function convertErrorsToResponse(
|
|
|
219
219
|
err: (error) => error,
|
|
220
220
|
}).pipe(
|
|
221
221
|
Fx.recover((error) => {
|
|
222
|
-
if (
|
|
222
|
+
if (
|
|
223
|
+
error instanceof ConvexError &&
|
|
224
|
+
typeof error.data === "object" &&
|
|
225
|
+
error.data !== null &&
|
|
226
|
+
"code" in error.data &&
|
|
227
|
+
"message" in error.data
|
|
228
|
+
) {
|
|
223
229
|
return Fx.succeed(
|
|
224
230
|
new Response(
|
|
225
231
|
JSON.stringify({
|
|
@@ -426,10 +432,10 @@ export function addSSORoutes(
|
|
|
426
432
|
deps.routeBase,
|
|
427
433
|
);
|
|
428
434
|
if (!route) {
|
|
429
|
-
throw
|
|
430
|
-
"INVALID_PARAMETERS",
|
|
431
|
-
"Invalid enterprise runtime path.",
|
|
432
|
-
)
|
|
435
|
+
throw Cv.error({
|
|
436
|
+
code: "INVALID_PARAMETERS",
|
|
437
|
+
message: "Invalid enterprise runtime path.",
|
|
438
|
+
});
|
|
433
439
|
}
|
|
434
440
|
if (route.protocol === "saml" && route.rest.length === 1) {
|
|
435
441
|
if (route.rest[0] === "metadata") {
|
|
@@ -456,10 +462,10 @@ export function addSSORoutes(
|
|
|
456
462
|
if (route.protocol === "scim" && route.rest[0] === "v2") {
|
|
457
463
|
return await deps.handleScimRequest(ctx, request);
|
|
458
464
|
}
|
|
459
|
-
throw
|
|
460
|
-
"INVALID_PARAMETERS",
|
|
461
|
-
"Invalid enterprise runtime path.",
|
|
462
|
-
)
|
|
465
|
+
throw Cv.error({
|
|
466
|
+
code: "INVALID_PARAMETERS",
|
|
467
|
+
message: "Invalid enterprise runtime path.",
|
|
468
|
+
});
|
|
463
469
|
}),
|
|
464
470
|
),
|
|
465
471
|
});
|
|
@@ -484,10 +490,10 @@ export function addSSORoutes(
|
|
|
484
490
|
if (route?.protocol === "scim" && route.rest[0] === "v2") {
|
|
485
491
|
return await deps.handleScimRequest(ctx, request);
|
|
486
492
|
}
|
|
487
|
-
throw
|
|
488
|
-
"INVALID_PARAMETERS",
|
|
489
|
-
"Invalid enterprise runtime path.",
|
|
490
|
-
)
|
|
493
|
+
throw Cv.error({
|
|
494
|
+
code: "INVALID_PARAMETERS",
|
|
495
|
+
message: "Invalid enterprise runtime path.",
|
|
496
|
+
});
|
|
491
497
|
}),
|
|
492
498
|
),
|
|
493
499
|
});
|
|
@@ -504,10 +510,10 @@ export function addSSORoutes(
|
|
|
504
510
|
if (route?.protocol === "scim" && route.rest[0] === "v2") {
|
|
505
511
|
return await deps.handleScimRequest(ctx, request);
|
|
506
512
|
}
|
|
507
|
-
throw
|
|
508
|
-
"INVALID_PARAMETERS",
|
|
509
|
-
"Invalid enterprise runtime path.",
|
|
510
|
-
)
|
|
513
|
+
throw Cv.error({
|
|
514
|
+
code: "INVALID_PARAMETERS",
|
|
515
|
+
message: "Invalid enterprise runtime path.",
|
|
516
|
+
});
|
|
511
517
|
}),
|
|
512
518
|
),
|
|
513
519
|
});
|
package/src/server/identity.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Cv } from "@robelest/fx/convex";
|
|
2
2
|
|
|
3
3
|
/** @internal */
|
|
4
4
|
export function userIdFromIdentitySubject(subject: string): string {
|
|
@@ -9,10 +9,10 @@ export function userIdFromIdentitySubject(subject: string): string {
|
|
|
9
9
|
rest.length === 0 ||
|
|
10
10
|
rest.some((segment) => segment.length === 0)
|
|
11
11
|
) {
|
|
12
|
-
throw
|
|
13
|
-
"INTERNAL_ERROR",
|
|
14
|
-
"Authenticated identity subject is malformed.",
|
|
15
|
-
);
|
|
12
|
+
throw Cv.error({
|
|
13
|
+
code: "INTERNAL_ERROR",
|
|
14
|
+
message: "Authenticated identity subject is malformed.",
|
|
15
|
+
});
|
|
16
16
|
}
|
|
17
17
|
return userId;
|
|
18
18
|
}
|
package/src/server/index.ts
CHANGED
package/src/server/limits.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { Fx } from "@robelest/fx";
|
|
2
|
+
import { ConvexError } from "convex/values";
|
|
2
3
|
|
|
3
4
|
import { authDb } from "./db";
|
|
4
|
-
import { AuthError } from "./authError";
|
|
5
5
|
import { Doc, MutationCtx } from "./types";
|
|
6
6
|
import { ConvexAuthConfig } from "./types";
|
|
7
|
-
import { errorMessage } from "./utils";
|
|
8
7
|
|
|
9
8
|
const DEFAULT_MAX_SIGN_IN_ATTEMPTS_PER_HOUR = 10;
|
|
10
9
|
|
|
@@ -16,7 +15,7 @@ export const isSignInRateLimited = (
|
|
|
16
15
|
ctx: MutationCtx,
|
|
17
16
|
identifier: string,
|
|
18
17
|
config: ConvexAuthConfig,
|
|
19
|
-
): Fx<boolean,
|
|
18
|
+
): Fx<boolean, ConvexError<any>> =>
|
|
20
19
|
getRateLimitState(ctx, identifier, config).pipe(
|
|
21
20
|
Fx.map((state) => state !== null && state.attemptsLeft < 1),
|
|
22
21
|
);
|
|
@@ -31,40 +30,28 @@ export const recordFailedSignIn = (
|
|
|
31
30
|
ctx: MutationCtx,
|
|
32
31
|
identifier: string,
|
|
33
32
|
config: ConvexAuthConfig,
|
|
34
|
-
): Fx<void,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
DEFAULT_MAX_SIGN_IN_ATTEMPTS_PER_HOUR) - 1,
|
|
57
|
-
lastAttemptTime: Date.now(),
|
|
58
|
-
}),
|
|
59
|
-
err: (e) =>
|
|
60
|
-
new AuthError(
|
|
61
|
-
"INTERNAL_ERROR",
|
|
62
|
-
`Failed to create rate limit: ${errorMessage(e)}`,
|
|
63
|
-
),
|
|
64
|
-
}),
|
|
65
|
-
),
|
|
66
|
-
Fx.map(() => undefined),
|
|
67
|
-
);
|
|
33
|
+
): Fx<void, ConvexError<any>> =>
|
|
34
|
+
Fx.gen(function* () {
|
|
35
|
+
const state = yield* getRateLimitState(ctx, identifier, config);
|
|
36
|
+
if (state !== null) {
|
|
37
|
+
yield* Fx.promise(() =>
|
|
38
|
+
authDb(ctx, config).rateLimits.patch(state.limit._id, {
|
|
39
|
+
attemptsLeft: state.attemptsLeft - 1,
|
|
40
|
+
lastAttemptTime: Date.now(),
|
|
41
|
+
}),
|
|
42
|
+
);
|
|
43
|
+
} else {
|
|
44
|
+
yield* Fx.promise(() =>
|
|
45
|
+
authDb(ctx, config).rateLimits.create({
|
|
46
|
+
identifier,
|
|
47
|
+
attemptsLeft:
|
|
48
|
+
(config.signIn?.maxFailedAttemptsPerHour ??
|
|
49
|
+
DEFAULT_MAX_SIGN_IN_ATTEMPTS_PER_HOUR) - 1,
|
|
50
|
+
lastAttemptTime: Date.now(),
|
|
51
|
+
}),
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
68
55
|
|
|
69
56
|
/**
|
|
70
57
|
* Reset the rate limit for the given identifier (e.g. after successful sign-in).
|
|
@@ -74,21 +61,15 @@ export const resetSignInRateLimit = (
|
|
|
74
61
|
ctx: MutationCtx,
|
|
75
62
|
identifier: string,
|
|
76
63
|
config: ConvexAuthConfig,
|
|
77
|
-
): Fx<void,
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
`Failed to delete rate limit: ${errorMessage(e)}`,
|
|
87
|
-
),
|
|
88
|
-
})
|
|
89
|
-
: Fx.unit,
|
|
90
|
-
),
|
|
91
|
-
);
|
|
64
|
+
): Fx<void, ConvexError<any>> =>
|
|
65
|
+
Fx.gen(function* () {
|
|
66
|
+
const state = yield* getRateLimitState(ctx, identifier, config);
|
|
67
|
+
if (state !== null) {
|
|
68
|
+
yield* Fx.promise(() =>
|
|
69
|
+
authDb(ctx, config).rateLimits.delete(state.limit._id),
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
92
73
|
|
|
93
74
|
// ---------------------------------------------------------------------------
|
|
94
75
|
// Internal
|
|
@@ -103,32 +84,24 @@ const getRateLimitState = (
|
|
|
103
84
|
ctx: MutationCtx,
|
|
104
85
|
identifier: string,
|
|
105
86
|
config: ConvexAuthConfig,
|
|
106
|
-
): Fx<RateLimitState,
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
87
|
+
): Fx<RateLimitState, ConvexError<any>> =>
|
|
88
|
+
Fx.gen(function* () {
|
|
89
|
+
const now = Date.now();
|
|
90
|
+
const maxAttemptsPerHour =
|
|
91
|
+
config.signIn?.maxFailedAttemptsPerHour ??
|
|
92
|
+
DEFAULT_MAX_SIGN_IN_ATTEMPTS_PER_HOUR;
|
|
111
93
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
const maxAttemptsPerMs = maxAttemptsPerHour / (60 * 60 * 1000);
|
|
127
|
-
const attemptsLeft = Math.min(
|
|
128
|
-
maxAttemptsPerHour,
|
|
129
|
-
limit.attemptsLeft + elapsed * maxAttemptsPerMs,
|
|
130
|
-
);
|
|
131
|
-
return { limit, attemptsLeft };
|
|
132
|
-
}),
|
|
133
|
-
);
|
|
134
|
-
};
|
|
94
|
+
const limit = (yield* Fx.promise(() =>
|
|
95
|
+
authDb(ctx, config).rateLimits.get(identifier),
|
|
96
|
+
)) as
|
|
97
|
+
| (Doc<"RateLimit"> & { attemptsLeft: number; lastAttemptTime: number })
|
|
98
|
+
| null;
|
|
99
|
+
if (limit === null) return null;
|
|
100
|
+
const elapsed = now - limit.lastAttemptTime;
|
|
101
|
+
const maxAttemptsPerMs = maxAttemptsPerHour / (60 * 60 * 1000);
|
|
102
|
+
const attemptsLeft = Math.min(
|
|
103
|
+
maxAttemptsPerHour,
|
|
104
|
+
limit.attemptsLeft + elapsed * maxAttemptsPerMs,
|
|
105
|
+
);
|
|
106
|
+
return { limit, attemptsLeft };
|
|
107
|
+
});
|