cauthy-auth 0.11.0 → 0.13.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/index.mjs CHANGED
@@ -985,6 +985,11 @@ function createCauthy(given = {}) {
985
985
  }
986
986
  const STEP_SECONDS = 600;
987
987
  const PASSKEY_SECONDS = 300;
988
+ const factorsOf = (d) => ({
989
+ totp: d?.totp === true,
990
+ phone: d?.phone ? { number: String(d.phone.number ?? ""), channel: String(d.phone.channel ?? "sms") } : null,
991
+ phoneChannels: Array.isArray(d?.phone_channels) ? d.phone_channels.map(String) : []
992
+ });
988
993
  const isCredential = (v) => typeof v === "object" && v !== null && !Array.isArray(v) && typeof v.id === "string" && typeof v.response === "object";
989
994
  const passkeyOf = (d) => ({
990
995
  id: String(d?.id ?? ""),
@@ -1035,6 +1040,9 @@ function createCauthy(given = {}) {
1035
1040
  ...clientId ? { "x-cauthy-client-id": clientId } : {},
1036
1041
  ...await passedOn(request),
1037
1042
  ...bearer2 ? { authorization: `Bearer ${bearer2}` } : {},
1043
+ // The answer to the workspace's Turnstile challenge, from the
1044
+ // person's browser: Cauthy checks it at the doors that ask for it.
1045
+ ...request.headers.get("x-cauthy-captcha") ? { "x-captcha-token": request.headers.get("x-cauthy-captcha") } : {},
1038
1046
  ...request.headers.get("accept-language") ? { "accept-language": request.headers.get("accept-language") } : {},
1039
1047
  // The language the application says its person reads, over the browser's.
1040
1048
  ...request.headers.get("x-cauthy-locale") ? { "x-cauthy-locale": request.headers.get("x-cauthy-locale") } : {},
@@ -1092,6 +1100,12 @@ function createCauthy(given = {}) {
1092
1100
  "/me/mfa/verify",
1093
1101
  "/me/mfa/disable",
1094
1102
  "/me/mfa/recovery-codes",
1103
+ "/me/mfa/factors",
1104
+ "/me/mfa/phone",
1105
+ "/me/mfa/phone/verify",
1106
+ "/me/mfa/phone/remove",
1107
+ "/sign-in/mfa/methods",
1108
+ "/sign-in/mfa/send",
1095
1109
  "/me/sessions",
1096
1110
  "/me/sessions/end",
1097
1111
  "/me/email",
@@ -1102,6 +1116,8 @@ function createCauthy(given = {}) {
1102
1116
  "/look",
1103
1117
  "/sign-in/passkey/begin",
1104
1118
  "/sign-in/passkey/finish",
1119
+ "/sign-in/google-one-tap/begin",
1120
+ "/sign-in/google-one-tap",
1105
1121
  "/me/passkeys",
1106
1122
  "/me/passkeys/add/begin",
1107
1123
  "/me/passkeys/add/finish",
@@ -1133,7 +1149,8 @@ function createCauthy(given = {}) {
1133
1149
  magicLink: settings.data?.allow_magic_link === true && pages.signIn !== void 0,
1134
1150
  passkey: place.error ? true : here || place.data?.on_cauthy === true,
1135
1151
  passkeyHere: here,
1136
- passkeyOnCauthy: place.error ? true : place.data?.on_cauthy === true
1152
+ passkeyOnCauthy: place.error ? true : place.data?.on_cauthy === true,
1153
+ ...settings.data?.captcha_enabled === true && settings.data?.captcha_site_key ? { captchaSiteKey: String(settings.data.captcha_site_key) } : {}
1137
1154
  });
1138
1155
  }
1139
1156
  if (route.startsWith("/sign-in/social/") && !post) {
@@ -1203,6 +1220,13 @@ function createCauthy(given = {}) {
1203
1220
  const list = Array.isArray(res.data) ? res.data : [];
1204
1221
  return json({ passkeys: list.map(passkeyOf) }, 200, mine.headers);
1205
1222
  }
1223
+ if (route === "/me/mfa/factors" && !post) {
1224
+ const mine = await signedInAs(request);
1225
+ if ("response" in mine) return mine.response;
1226
+ const res = await ask(request, "GET", "/v1/auth/mfa/factors", void 0, void 0, mine.token);
1227
+ if (res.error) return problem(res.status, res.error.code, res.error.message, void 0, mine.headers);
1228
+ return json(factorsOf(res.data), 200, mine.headers);
1229
+ }
1206
1230
  if ((route === "/me" || route === "/me/sessions") && !post) {
1207
1231
  const mine = await signedInAs(request);
1208
1232
  if ("response" in mine) return mine.response;
@@ -1251,6 +1275,20 @@ function createCauthy(given = {}) {
1251
1275
  if (res.error) return problem(res.status, res.error.code, res.error.message, "code");
1252
1276
  return signedIn(request, res.data, [writeCookie(stepCookie, "", attrs(request, 0))]);
1253
1277
  }
1278
+ if (route === "/sign-in/mfa/methods" || route === "/sign-in/mfa/send") {
1279
+ const sealed = readCookies(request.headers.get("cookie")).get(stepCookie);
1280
+ const step = sealed ? await unseal(sealed, await key) : null;
1281
+ if (step === null || step.kind !== "mfa") return problem(400, "step_expired", "Sign in again: the code was asked for too long ago.");
1282
+ if (route === "/sign-in/mfa/methods") {
1283
+ const res2 = await ask(request, "POST", "/v1/auth/mfa/methods", { mfa_token: step.token });
1284
+ if (res2.error) return problem(res2.status, res2.error.code, res2.error.message);
1285
+ const p = res2.data?.phone;
1286
+ return json({ status: "ok", totp: res2.data?.totp === true, phone: p ? { number: String(p.number ?? ""), channel: String(p.channel ?? "sms") } : null });
1287
+ }
1288
+ const res = await ask(request, "POST", "/v1/auth/mfa/send", { mfa_token: step.token });
1289
+ if (res.error) return problem(res.status, res.error.code, res.error.message);
1290
+ return json({ status: "sent", sentTo: String(res.data?.sent_to ?? ""), channel: String(res.data?.channel ?? "sms") });
1291
+ }
1254
1292
  if (route === "/sign-up/email") {
1255
1293
  const bad = firstProblem(checkName(b.name), checkEmail(b.email), checkNewPassword(b.password));
1256
1294
  if (bad) return invalid(bad);
@@ -1309,6 +1347,23 @@ function createCauthy(given = {}) {
1309
1347
  if (res.error) return refused(res, "code");
1310
1348
  return json({ status: "enabled", recoveryCodes: Array.isArray(res.data?.recovery_codes) ? res.data.recovery_codes.map(String) : [] }, 200, mine.headers);
1311
1349
  }
1350
+ if (route === "/me/mfa/phone") {
1351
+ const res = await as("/v1/auth/mfa/phone", { phone: typeof b.phone === "string" ? b.phone : "", channel: typeof b.channel === "string" ? b.channel : "sms", password });
1352
+ if (res.error) return refused(res, res.error.code === "step_up_required" ? "password" : res.error.code === "validation_error" ? "phone" : void 0);
1353
+ return json({ status: "sent", sentTo: String(res.data?.sent_to ?? ""), channel: String(res.data?.channel ?? "") }, 200, mine.headers);
1354
+ }
1355
+ if (route === "/me/mfa/phone/verify") {
1356
+ const bad = checkCode(b.code);
1357
+ if (bad) return invalid(bad);
1358
+ const res = await as("/v1/auth/mfa/phone/verify", { code: String(b.code).trim() });
1359
+ if (res.error) return refused(res, "code");
1360
+ return json({ status: "enabled", recoveryCodes: Array.isArray(res.data?.recovery_codes) ? res.data.recovery_codes.map(String) : [] }, 200, mine.headers);
1361
+ }
1362
+ if (route === "/me/mfa/phone/remove") {
1363
+ const res = await as("/v1/auth/mfa/phone/remove", { password });
1364
+ if (res.error) return refused(res, res.error.code === "step_up_required" ? "password" : void 0);
1365
+ return json({ status: "removed" }, 200, mine.headers);
1366
+ }
1312
1367
  if (route === "/me/mfa/disable") {
1313
1368
  const res = await as("/v1/auth/me/mfa/disable", { password });
1314
1369
  if (res.error) return refused(res, res.error.code === "step_up_required" ? "password" : void 0);
@@ -1410,6 +1465,17 @@ function createCauthy(given = {}) {
1410
1465
  }
1411
1466
  return signedIn(request, res.data, [clear]);
1412
1467
  }
1468
+ if (route === "/sign-in/google-one-tap/begin") {
1469
+ const res = await ask(request, "POST", "/v1/auth/google/one-tap/begin", {});
1470
+ if (res.error) return problem(res.status, res.error.code, res.error.message);
1471
+ return json({ status: "started", clientId: String(res.data?.client_id ?? ""), nonce: String(res.data?.nonce ?? "") });
1472
+ }
1473
+ if (route === "/sign-in/google-one-tap") {
1474
+ if (typeof b.credential !== "string" || b.credential === "") return problem(400, "bad_request", "Send the credential Google gave the page.");
1475
+ const res = await ask(request, "POST", "/v1/auth/google/one-tap", { credential: b.credential });
1476
+ if (res.error) return problem(res.status, res.error.code, res.error.message);
1477
+ return signedIn(request, res.data);
1478
+ }
1413
1479
  if (route === "/sign-in/magic-link") {
1414
1480
  const bad = checkEmail(b.email);
1415
1481
  if (bad) return invalid(bad);