tempest-express-sdk 0.5.0 → 0.7.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 +4 -5
- package/dist/chunk-PKUUVK7K.js +6 -0
- package/dist/{chunk-ZU6W433I.js.map → chunk-PKUUVK7K.js.map} +1 -1
- package/dist/cli.cjs +1 -1
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/index.cjs +427 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +370 -6
- package/dist/index.d.ts +370 -6
- package/dist/index.js +416 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-ZU6W433I.js +0 -6
package/dist/index.cjs
CHANGED
|
@@ -8197,6 +8197,190 @@ function makeWhatsAppWebhookRouter(options) {
|
|
|
8197
8197
|
return router;
|
|
8198
8198
|
}
|
|
8199
8199
|
|
|
8200
|
+
// src/integrations/telegram.ts
|
|
8201
|
+
var MEDIA_METHOD = {
|
|
8202
|
+
image: { method: "sendPhoto", field: "photo" },
|
|
8203
|
+
video: { method: "sendVideo", field: "video" },
|
|
8204
|
+
audio: { method: "sendAudio", field: "audio" },
|
|
8205
|
+
document: { method: "sendDocument", field: "document" }
|
|
8206
|
+
};
|
|
8207
|
+
var TelegramProvider = class {
|
|
8208
|
+
http;
|
|
8209
|
+
pollTimeout;
|
|
8210
|
+
/**
|
|
8211
|
+
* @param options - Bot token and API options.
|
|
8212
|
+
*/
|
|
8213
|
+
constructor(options) {
|
|
8214
|
+
const base = `${options.apiBase ?? "https://api.telegram.org"}/bot${options.token}`;
|
|
8215
|
+
this.pollTimeout = options.pollTimeoutSeconds ?? 30;
|
|
8216
|
+
this.http = new HTTPClient({
|
|
8217
|
+
baseUrl: base,
|
|
8218
|
+
defaultHeaders: { "content-type": "application/json" },
|
|
8219
|
+
// Timeout must exceed the long-poll window.
|
|
8220
|
+
timeoutMs: (this.pollTimeout + 10) * 1e3
|
|
8221
|
+
});
|
|
8222
|
+
}
|
|
8223
|
+
/** Call a Bot API method, returning the `result`, throwing on `ok: false`. */
|
|
8224
|
+
async call(method, body) {
|
|
8225
|
+
const res = await this.http.post(`/${method}`, { body: JSON.stringify(body) });
|
|
8226
|
+
const data = await res.json().catch(() => ({}));
|
|
8227
|
+
if (!res.ok || !data.ok) {
|
|
8228
|
+
throw new Error(`Telegram ${method} failed: ${data.description ?? res.statusText}`);
|
|
8229
|
+
}
|
|
8230
|
+
return data.result;
|
|
8231
|
+
}
|
|
8232
|
+
async sendText(to, text) {
|
|
8233
|
+
const result = await this.call("sendMessage", {
|
|
8234
|
+
chat_id: to,
|
|
8235
|
+
text
|
|
8236
|
+
});
|
|
8237
|
+
return { id: String(result.message_id), status: "sent" };
|
|
8238
|
+
}
|
|
8239
|
+
async sendMedia(to, media) {
|
|
8240
|
+
const { method, field } = MEDIA_METHOD[media.kind];
|
|
8241
|
+
const body = { chat_id: to, [field]: media.media };
|
|
8242
|
+
if (media.caption !== void 0) body.caption = media.caption;
|
|
8243
|
+
const result = await this.call(method, body);
|
|
8244
|
+
return { id: String(result.message_id), status: "sent" };
|
|
8245
|
+
}
|
|
8246
|
+
async status() {
|
|
8247
|
+
try {
|
|
8248
|
+
await this.call("getMe", {});
|
|
8249
|
+
return "connected";
|
|
8250
|
+
} catch {
|
|
8251
|
+
return "disconnected";
|
|
8252
|
+
}
|
|
8253
|
+
}
|
|
8254
|
+
/**
|
|
8255
|
+
* Subscribe to inbound messages via `getUpdates` long-polling.
|
|
8256
|
+
*
|
|
8257
|
+
* @param handler - Invoked for each inbound text message.
|
|
8258
|
+
* @returns A stop function that ends the polling loop.
|
|
8259
|
+
*/
|
|
8260
|
+
async onMessage(handler) {
|
|
8261
|
+
let running = true;
|
|
8262
|
+
let offset = 0;
|
|
8263
|
+
const loop = async () => {
|
|
8264
|
+
while (running) {
|
|
8265
|
+
let updates = [];
|
|
8266
|
+
try {
|
|
8267
|
+
updates = await this.call("getUpdates", {
|
|
8268
|
+
offset,
|
|
8269
|
+
timeout: this.pollTimeout
|
|
8270
|
+
});
|
|
8271
|
+
} catch {
|
|
8272
|
+
if (running) await new Promise((r) => setTimeout(r, 1e3));
|
|
8273
|
+
continue;
|
|
8274
|
+
}
|
|
8275
|
+
for (const update2 of updates) {
|
|
8276
|
+
offset = update2.update_id + 1;
|
|
8277
|
+
const message = update2.message;
|
|
8278
|
+
if (!message) continue;
|
|
8279
|
+
await handler({
|
|
8280
|
+
from: String(message.chat.id),
|
|
8281
|
+
messageId: String(message.message_id),
|
|
8282
|
+
...typeof message.text === "string" ? { text: message.text } : {},
|
|
8283
|
+
mediaType: null,
|
|
8284
|
+
timestamp: new Date(message.date * 1e3).toISOString(),
|
|
8285
|
+
direction: "incoming"
|
|
8286
|
+
});
|
|
8287
|
+
}
|
|
8288
|
+
}
|
|
8289
|
+
};
|
|
8290
|
+
void loop();
|
|
8291
|
+
return async () => {
|
|
8292
|
+
running = false;
|
|
8293
|
+
};
|
|
8294
|
+
}
|
|
8295
|
+
};
|
|
8296
|
+
var TwilioSmsProvider = class {
|
|
8297
|
+
http;
|
|
8298
|
+
from;
|
|
8299
|
+
messagesPath;
|
|
8300
|
+
accountPath;
|
|
8301
|
+
/**
|
|
8302
|
+
* @param options - Account SID, auth token and default sender.
|
|
8303
|
+
*/
|
|
8304
|
+
constructor(options) {
|
|
8305
|
+
this.from = options.from;
|
|
8306
|
+
this.messagesPath = `/2010-04-01/Accounts/${options.accountSid}/Messages.json`;
|
|
8307
|
+
this.accountPath = `/2010-04-01/Accounts/${options.accountSid}.json`;
|
|
8308
|
+
const basic = Buffer.from(`${options.accountSid}:${options.authToken}`).toString(
|
|
8309
|
+
"base64"
|
|
8310
|
+
);
|
|
8311
|
+
this.http = new HTTPClient({
|
|
8312
|
+
baseUrl: options.apiBase ?? "https://api.twilio.com",
|
|
8313
|
+
defaultHeaders: {
|
|
8314
|
+
Authorization: `Basic ${basic}`,
|
|
8315
|
+
"content-type": "application/x-www-form-urlencoded"
|
|
8316
|
+
}
|
|
8317
|
+
});
|
|
8318
|
+
}
|
|
8319
|
+
/** POST a form body to Twilio and parse the JSON, throwing on non-2xx. */
|
|
8320
|
+
async postForm(params) {
|
|
8321
|
+
const res = await this.http.post(this.messagesPath, {
|
|
8322
|
+
body: new URLSearchParams(params).toString()
|
|
8323
|
+
});
|
|
8324
|
+
const data = await res.json().catch(() => ({}));
|
|
8325
|
+
if (!res.ok) {
|
|
8326
|
+
throw new Error(
|
|
8327
|
+
`Twilio send failed (${res.status}): ${data.message ?? res.statusText}`
|
|
8328
|
+
);
|
|
8329
|
+
}
|
|
8330
|
+
return {
|
|
8331
|
+
status: data.status ?? "queued",
|
|
8332
|
+
...data.sid ? { id: data.sid } : {}
|
|
8333
|
+
};
|
|
8334
|
+
}
|
|
8335
|
+
async sendText(to, text) {
|
|
8336
|
+
return this.postForm({ To: to, From: this.from, Body: text });
|
|
8337
|
+
}
|
|
8338
|
+
async sendMedia(to, media) {
|
|
8339
|
+
return this.postForm({
|
|
8340
|
+
To: to,
|
|
8341
|
+
From: this.from,
|
|
8342
|
+
MediaUrl: media.media,
|
|
8343
|
+
...media.caption !== void 0 ? { Body: media.caption } : {}
|
|
8344
|
+
});
|
|
8345
|
+
}
|
|
8346
|
+
async status() {
|
|
8347
|
+
const res = await this.http.get(this.accountPath);
|
|
8348
|
+
const data = await res.json().catch(() => ({}));
|
|
8349
|
+
return data.status ?? (res.ok ? "connected" : "disconnected");
|
|
8350
|
+
}
|
|
8351
|
+
};
|
|
8352
|
+
function validateTwilioSignature(authToken, url, params, signature) {
|
|
8353
|
+
const data = url + Object.keys(params).sort().map((key) => key + params[key]).join("");
|
|
8354
|
+
const expected = crypto.createHmac("sha1", authToken).update(data, "utf8").digest("base64");
|
|
8355
|
+
const a = Buffer.from(expected);
|
|
8356
|
+
const b = Buffer.from(signature);
|
|
8357
|
+
return a.length === b.length && crypto.timingSafeEqual(a, b);
|
|
8358
|
+
}
|
|
8359
|
+
function makeTwilioWebhookRouter(options) {
|
|
8360
|
+
const path = options.path ?? "/sms/inbound";
|
|
8361
|
+
const router = express2.Router();
|
|
8362
|
+
router.post(path, async (req, res) => {
|
|
8363
|
+
const body = req.body ?? {};
|
|
8364
|
+
if (options.authToken) {
|
|
8365
|
+
const url = options.publicUrl ?? `${req.protocol}://${req.get("host")}${req.originalUrl}`;
|
|
8366
|
+
const signature = req.header("x-twilio-signature") ?? "";
|
|
8367
|
+
if (!validateTwilioSignature(options.authToken, url, body, signature)) {
|
|
8368
|
+
throw new UnauthorizedException({ message: "Invalid Twilio signature" });
|
|
8369
|
+
}
|
|
8370
|
+
}
|
|
8371
|
+
await options.onMessage({
|
|
8372
|
+
from: String(body.From ?? ""),
|
|
8373
|
+
messageId: String(body.MessageSid ?? ""),
|
|
8374
|
+
...body.Body ? { text: body.Body } : {},
|
|
8375
|
+
mediaType: null,
|
|
8376
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8377
|
+
direction: "incoming"
|
|
8378
|
+
});
|
|
8379
|
+
res.type("text/xml").send("<Response></Response>");
|
|
8380
|
+
});
|
|
8381
|
+
return router;
|
|
8382
|
+
}
|
|
8383
|
+
|
|
8200
8384
|
// src/admin/site.ts
|
|
8201
8385
|
var AdminSite = class {
|
|
8202
8386
|
/**
|
|
@@ -8331,6 +8515,17 @@ var authResponseSchema = zod.z.object({
|
|
|
8331
8515
|
user: userPublicSchema,
|
|
8332
8516
|
tokens: tokenPairSchema
|
|
8333
8517
|
}).openapi("AuthResponse");
|
|
8518
|
+
var mfaEnrollResponseSchema = zod.z.object({
|
|
8519
|
+
secret: zod.z.string().openapi({ description: "Base32 TOTP secret (manual entry)." }),
|
|
8520
|
+
otpauthUri: zod.z.string().openapi({ description: "otpauth:// URI to render as QR." })
|
|
8521
|
+
}).openapi("MfaEnrollResponse");
|
|
8522
|
+
var mfaCodeSchema = zod.z.object({ code: zod.z.string().min(1).openapi({ description: "Authenticator code." }) }).openapi("MfaCode");
|
|
8523
|
+
var activationSchema = zod.z.object({ token: zod.z.string().min(1).openapi({ description: "Activation token." }) }).openapi("Activation");
|
|
8524
|
+
var passwordResetRequestSchema = zod.z.object({ email: zod.z.string().email().openapi({ description: "Account email." }) }).openapi("PasswordResetRequest");
|
|
8525
|
+
var passwordResetConfirmSchema = zod.z.object({
|
|
8526
|
+
token: zod.z.string().min(1).openapi({ description: "Reset token." }),
|
|
8527
|
+
password: zod.z.string().min(1).openapi({ description: "New plaintext password." })
|
|
8528
|
+
}).openapi("PasswordResetConfirm");
|
|
8334
8529
|
|
|
8335
8530
|
// src/auth/service.ts
|
|
8336
8531
|
function toPublic(user) {
|
|
@@ -8443,6 +8638,178 @@ var UserAuthService = class {
|
|
|
8443
8638
|
}
|
|
8444
8639
|
};
|
|
8445
8640
|
|
|
8641
|
+
// src/auth/mfa.ts
|
|
8642
|
+
var MfaService = class {
|
|
8643
|
+
store;
|
|
8644
|
+
totp;
|
|
8645
|
+
/**
|
|
8646
|
+
* @param options - Store and TOTP helper.
|
|
8647
|
+
*/
|
|
8648
|
+
constructor(options) {
|
|
8649
|
+
this.store = options.store;
|
|
8650
|
+
this.totp = options.totp;
|
|
8651
|
+
}
|
|
8652
|
+
/**
|
|
8653
|
+
* Begin enrollment: generate and persist a secret, return the QR URI.
|
|
8654
|
+
*
|
|
8655
|
+
* @param userId - The enrolling user.
|
|
8656
|
+
* @param accountName - Label shown in the authenticator (usually the email).
|
|
8657
|
+
* @returns The secret and provisioning URI.
|
|
8658
|
+
*/
|
|
8659
|
+
async enroll(userId, accountName) {
|
|
8660
|
+
const secret = this.totp.generateSecret();
|
|
8661
|
+
await this.store.setSecret(userId, secret);
|
|
8662
|
+
await this.store.setEnabled(userId, false);
|
|
8663
|
+
return { secret, otpauthUri: this.totp.provisioningUri(secret, accountName) };
|
|
8664
|
+
}
|
|
8665
|
+
/**
|
|
8666
|
+
* Confirm enrollment by verifying a code, enabling MFA on success.
|
|
8667
|
+
*
|
|
8668
|
+
* @param userId - The user.
|
|
8669
|
+
* @param code - The 6-digit code from the authenticator.
|
|
8670
|
+
* @throws {ValidationException} When no secret is pending or the code is wrong.
|
|
8671
|
+
*/
|
|
8672
|
+
async confirm(userId, code) {
|
|
8673
|
+
const secret = await this.store.getSecret(userId);
|
|
8674
|
+
if (!secret) throw new ValidationException({ message: "MFA not initialized" });
|
|
8675
|
+
if (!this.totp.verify(secret, code)) {
|
|
8676
|
+
throw new ValidationException({ message: "Invalid MFA code" });
|
|
8677
|
+
}
|
|
8678
|
+
await this.store.setEnabled(userId, true);
|
|
8679
|
+
}
|
|
8680
|
+
/**
|
|
8681
|
+
* Verify a code (login step). Returns `false` without throwing.
|
|
8682
|
+
*
|
|
8683
|
+
* @param userId - The user.
|
|
8684
|
+
* @param code - The submitted code.
|
|
8685
|
+
* @returns `true` when the code is valid.
|
|
8686
|
+
*/
|
|
8687
|
+
async verify(userId, code) {
|
|
8688
|
+
const secret = await this.store.getSecret(userId);
|
|
8689
|
+
return secret ? this.totp.verify(secret, code) : false;
|
|
8690
|
+
}
|
|
8691
|
+
/**
|
|
8692
|
+
* Disable MFA after verifying a code.
|
|
8693
|
+
*
|
|
8694
|
+
* @param userId - The user.
|
|
8695
|
+
* @param code - The submitted code.
|
|
8696
|
+
* @throws {ValidationException} When the code is invalid.
|
|
8697
|
+
*/
|
|
8698
|
+
async disable(userId, code) {
|
|
8699
|
+
if (!await this.verify(userId, code)) {
|
|
8700
|
+
throw new ValidationException({ message: "Invalid MFA code" });
|
|
8701
|
+
}
|
|
8702
|
+
await this.store.setEnabled(userId, false);
|
|
8703
|
+
await this.store.setSecret(userId, "");
|
|
8704
|
+
}
|
|
8705
|
+
};
|
|
8706
|
+
|
|
8707
|
+
// src/auth/activation.ts
|
|
8708
|
+
var ActivationService = class {
|
|
8709
|
+
store;
|
|
8710
|
+
ttlSeconds;
|
|
8711
|
+
/**
|
|
8712
|
+
* @param options - Store and token TTL.
|
|
8713
|
+
*/
|
|
8714
|
+
constructor(options) {
|
|
8715
|
+
this.store = options.store;
|
|
8716
|
+
this.ttlSeconds = options.ttlSeconds ?? 60 * 60 * 24;
|
|
8717
|
+
}
|
|
8718
|
+
/**
|
|
8719
|
+
* Start activation: issue a token and persist its hash.
|
|
8720
|
+
*
|
|
8721
|
+
* @param userId - The user to activate.
|
|
8722
|
+
* @returns The one-time plaintext token (embed in the activation link).
|
|
8723
|
+
*/
|
|
8724
|
+
async start(userId) {
|
|
8725
|
+
const { plaintext, tokenHash } = generateOpaqueToken();
|
|
8726
|
+
await this.store.saveActivationToken(
|
|
8727
|
+
userId,
|
|
8728
|
+
tokenHash,
|
|
8729
|
+
Date.now() + this.ttlSeconds * 1e3
|
|
8730
|
+
);
|
|
8731
|
+
return plaintext;
|
|
8732
|
+
}
|
|
8733
|
+
/**
|
|
8734
|
+
* Activate an account from a token.
|
|
8735
|
+
*
|
|
8736
|
+
* @param token - The plaintext token from the activation link.
|
|
8737
|
+
* @returns The activated user id.
|
|
8738
|
+
* @throws {InvalidTokenException} When the token is unknown or expired.
|
|
8739
|
+
*/
|
|
8740
|
+
async activate(token) {
|
|
8741
|
+
const tokenHash = hashOpaqueToken(token);
|
|
8742
|
+
const record = await this.store.findActivationToken(tokenHash);
|
|
8743
|
+
if (!record || record.expiresAt <= Date.now()) {
|
|
8744
|
+
throw new InvalidTokenException({ message: "Invalid or expired activation token" });
|
|
8745
|
+
}
|
|
8746
|
+
await this.store.activate(record.userId);
|
|
8747
|
+
await this.store.clearActivationToken(tokenHash);
|
|
8748
|
+
return record.userId;
|
|
8749
|
+
}
|
|
8750
|
+
};
|
|
8751
|
+
|
|
8752
|
+
// src/auth/passwordReset.ts
|
|
8753
|
+
var PasswordResetService = class {
|
|
8754
|
+
store;
|
|
8755
|
+
password;
|
|
8756
|
+
ttlSeconds;
|
|
8757
|
+
passwordMinLength;
|
|
8758
|
+
/**
|
|
8759
|
+
* @param options - Store, password hasher and policy.
|
|
8760
|
+
*/
|
|
8761
|
+
constructor(options) {
|
|
8762
|
+
this.store = options.store;
|
|
8763
|
+
this.password = options.password;
|
|
8764
|
+
this.ttlSeconds = options.ttlSeconds ?? 3600;
|
|
8765
|
+
this.passwordMinLength = options.passwordMinLength ?? 12;
|
|
8766
|
+
}
|
|
8767
|
+
/**
|
|
8768
|
+
* Request a reset for `email`.
|
|
8769
|
+
*
|
|
8770
|
+
* Returns the plaintext token only when the email maps to a user; otherwise
|
|
8771
|
+
* `null`. Callers should respond with the same success shape either way to
|
|
8772
|
+
* avoid user enumeration — email the token only when present.
|
|
8773
|
+
*
|
|
8774
|
+
* @param email - The account email.
|
|
8775
|
+
* @returns The one-time token, or `null` when no user matches.
|
|
8776
|
+
*/
|
|
8777
|
+
async request(email) {
|
|
8778
|
+
const userId = await this.store.findUserIdByEmail(email.toLowerCase());
|
|
8779
|
+
if (!userId) return null;
|
|
8780
|
+
const { plaintext, tokenHash } = generateOpaqueToken();
|
|
8781
|
+
await this.store.saveResetToken(
|
|
8782
|
+
userId,
|
|
8783
|
+
tokenHash,
|
|
8784
|
+
Date.now() + this.ttlSeconds * 1e3
|
|
8785
|
+
);
|
|
8786
|
+
return plaintext;
|
|
8787
|
+
}
|
|
8788
|
+
/**
|
|
8789
|
+
* Confirm a reset: validate the token + new password and rehash.
|
|
8790
|
+
*
|
|
8791
|
+
* @param token - The plaintext reset token.
|
|
8792
|
+
* @param newPassword - The new plaintext password.
|
|
8793
|
+
* @throws {ValidationException} When the new password is too short.
|
|
8794
|
+
* @throws {InvalidTokenException} When the token is unknown or expired.
|
|
8795
|
+
*/
|
|
8796
|
+
async confirm(token, newPassword) {
|
|
8797
|
+
if (newPassword.length < this.passwordMinLength) {
|
|
8798
|
+
throw new ValidationException({
|
|
8799
|
+
message: `Password must be at least ${this.passwordMinLength} characters`,
|
|
8800
|
+
details: { minLength: this.passwordMinLength }
|
|
8801
|
+
});
|
|
8802
|
+
}
|
|
8803
|
+
const tokenHash = hashOpaqueToken(token);
|
|
8804
|
+
const record = await this.store.findResetToken(tokenHash);
|
|
8805
|
+
if (!record || record.expiresAt <= Date.now()) {
|
|
8806
|
+
throw new InvalidTokenException({ message: "Invalid or expired reset token" });
|
|
8807
|
+
}
|
|
8808
|
+
await this.store.updatePassword(record.userId, await this.password.hash(newPassword));
|
|
8809
|
+
await this.store.clearResetToken(tokenHash);
|
|
8810
|
+
}
|
|
8811
|
+
};
|
|
8812
|
+
|
|
8446
8813
|
// src/auth/middleware.ts
|
|
8447
8814
|
function bearerToken(req) {
|
|
8448
8815
|
const header = req.header("authorization");
|
|
@@ -8545,6 +8912,53 @@ function makeAuthRouter(options) {
|
|
|
8545
8912
|
}
|
|
8546
8913
|
res.json(claims);
|
|
8547
8914
|
});
|
|
8915
|
+
if (options.activation) {
|
|
8916
|
+
const activation = options.activation;
|
|
8917
|
+
router.post(`${prefix}/activate`, async (req, res) => {
|
|
8918
|
+
const { token } = activationSchema.parse(req.body);
|
|
8919
|
+
const userId = await activation.activate(token);
|
|
8920
|
+
res.json({ activated: true, userId });
|
|
8921
|
+
});
|
|
8922
|
+
}
|
|
8923
|
+
if (options.passwordReset) {
|
|
8924
|
+
const reset = options.passwordReset;
|
|
8925
|
+
router.post(`${prefix}/password-reset/request`, async (req, res) => {
|
|
8926
|
+
const { email } = passwordResetRequestSchema.parse(req.body);
|
|
8927
|
+
const token = await reset.request(email);
|
|
8928
|
+
res.status(202).json({ requested: true, ...token ? { token } : {} });
|
|
8929
|
+
});
|
|
8930
|
+
router.post(`${prefix}/password-reset/confirm`, async (req, res) => {
|
|
8931
|
+
const { token, password } = passwordResetConfirmSchema.parse(req.body);
|
|
8932
|
+
await reset.confirm(token, password);
|
|
8933
|
+
res.json({ reset: true });
|
|
8934
|
+
});
|
|
8935
|
+
}
|
|
8936
|
+
if (options.mfa) {
|
|
8937
|
+
const mfa = options.mfa;
|
|
8938
|
+
const requireUser = (req) => {
|
|
8939
|
+
const claims = getAuth(req);
|
|
8940
|
+
if (!claims || typeof claims.sub !== "string") {
|
|
8941
|
+
throw new UnauthorizedException({ message: "Not authenticated" });
|
|
8942
|
+
}
|
|
8943
|
+
return claims.sub;
|
|
8944
|
+
};
|
|
8945
|
+
router.post(`${prefix}/mfa/enroll`, makeJwtAuthMiddleware(jwt), async (req, res) => {
|
|
8946
|
+
const claims = getAuth(req);
|
|
8947
|
+
const userId = requireUser(req);
|
|
8948
|
+
const label = typeof claims?.email === "string" ? claims.email : userId;
|
|
8949
|
+
res.json(await mfa.enroll(userId, label));
|
|
8950
|
+
});
|
|
8951
|
+
router.post(`${prefix}/mfa/confirm`, makeJwtAuthMiddleware(jwt), async (req, res) => {
|
|
8952
|
+
const { code } = mfaCodeSchema.parse(req.body);
|
|
8953
|
+
await mfa.confirm(requireUser(req), code);
|
|
8954
|
+
res.json({ enabled: true });
|
|
8955
|
+
});
|
|
8956
|
+
router.post(`${prefix}/mfa/disable`, makeJwtAuthMiddleware(jwt), async (req, res) => {
|
|
8957
|
+
const { code } = mfaCodeSchema.parse(req.body);
|
|
8958
|
+
await mfa.disable(requireUser(req), code);
|
|
8959
|
+
res.json({ enabled: false });
|
|
8960
|
+
});
|
|
8961
|
+
}
|
|
8548
8962
|
return router;
|
|
8549
8963
|
}
|
|
8550
8964
|
var logger2 = new JSONLogger("tempest_express_sdk.api.handlers");
|
|
@@ -8813,7 +9227,7 @@ function runServer(app, options = {}) {
|
|
|
8813
9227
|
}
|
|
8814
9228
|
|
|
8815
9229
|
// src/version.ts
|
|
8816
|
-
var VERSION = "0.
|
|
9230
|
+
var VERSION = "0.7.0";
|
|
8817
9231
|
|
|
8818
9232
|
Object.defineProperty(exports, "OpenAPIRegistry", {
|
|
8819
9233
|
enumerable: true,
|
|
@@ -8967,6 +9381,7 @@ Object.defineProperty(exports, "update", {
|
|
|
8967
9381
|
enumerable: true,
|
|
8968
9382
|
get: function () { return tempestDbJs.update; }
|
|
8969
9383
|
});
|
|
9384
|
+
exports.ActivationService = ActivationService;
|
|
8970
9385
|
exports.AdminSite = AdminSite;
|
|
8971
9386
|
exports.AppException = AppException;
|
|
8972
9387
|
exports.AttemptThrottle = AttemptThrottle;
|
|
@@ -8999,8 +9414,10 @@ exports.MemorySessionStore = MemorySessionStore;
|
|
|
8999
9414
|
exports.MemoryThrottleBackend = MemoryThrottleBackend;
|
|
9000
9415
|
exports.MessageCatalog = MessageCatalog;
|
|
9001
9416
|
exports.MetricsUtils = MetricsUtils;
|
|
9417
|
+
exports.MfaService = MfaService;
|
|
9002
9418
|
exports.NotFoundException = NotFoundException;
|
|
9003
9419
|
exports.PHONE_BR_PATTERN = PHONE_BR_PATTERN;
|
|
9420
|
+
exports.PasswordResetService = PasswordResetService;
|
|
9004
9421
|
exports.PasswordUtils = PasswordUtils;
|
|
9005
9422
|
exports.REQUEST_ID_HEADER = REQUEST_ID_HEADER;
|
|
9006
9423
|
exports.RabbitBroker = RabbitBroker;
|
|
@@ -9012,7 +9429,9 @@ exports.ServerSentEvent = ServerSentEvent;
|
|
|
9012
9429
|
exports.SessionService = SessionService;
|
|
9013
9430
|
exports.TOTPHelper = TOTPHelper;
|
|
9014
9431
|
exports.TaskManager = TaskManager;
|
|
9432
|
+
exports.TelegramProvider = TelegramProvider;
|
|
9015
9433
|
exports.TooManyRequestsException = TooManyRequestsException;
|
|
9434
|
+
exports.TwilioSmsProvider = TwilioSmsProvider;
|
|
9016
9435
|
exports.UF = UF;
|
|
9017
9436
|
exports.UnauthorizedException = UnauthorizedException;
|
|
9018
9437
|
exports.UserAuthService = UserAuthService;
|
|
@@ -9023,6 +9442,7 @@ exports.WebPushError = WebPushError;
|
|
|
9023
9442
|
exports.WebPushGoneError = WebPushGoneError;
|
|
9024
9443
|
exports.WebSocketHub = WebSocketHub;
|
|
9025
9444
|
exports.WhatsAppProvider = WhatsAppProvider;
|
|
9445
|
+
exports.activationSchema = activationSchema;
|
|
9026
9446
|
exports.attachWebSocketHub = attachWebSocketHub;
|
|
9027
9447
|
exports.authResponseSchema = authResponseSchema;
|
|
9028
9448
|
exports.baseAppSettingsSchema = baseAppSettingsSchema;
|
|
@@ -9077,8 +9497,11 @@ exports.makeFlagGuard = makeFlagGuard;
|
|
|
9077
9497
|
exports.makeHealthRouter = makeHealthRouter;
|
|
9078
9498
|
exports.makeJwtAuthMiddleware = makeJwtAuthMiddleware;
|
|
9079
9499
|
exports.makeSessionMiddleware = makeSessionMiddleware;
|
|
9500
|
+
exports.makeTwilioWebhookRouter = makeTwilioWebhookRouter;
|
|
9080
9501
|
exports.makeUnhandledExceptionHandler = makeUnhandledExceptionHandler;
|
|
9081
9502
|
exports.makeWhatsAppWebhookRouter = makeWhatsAppWebhookRouter;
|
|
9503
|
+
exports.mfaCodeSchema = mfaCodeSchema;
|
|
9504
|
+
exports.mfaEnrollResponseSchema = mfaEnrollResponseSchema;
|
|
9082
9505
|
exports.modifyDict = modifyDict;
|
|
9083
9506
|
exports.mountOpenApiJson = mountOpenApiJson;
|
|
9084
9507
|
exports.mountRedoc = mountRedoc;
|
|
@@ -9095,6 +9518,8 @@ exports.paginationFilterSchema = paginationFilterSchema;
|
|
|
9095
9518
|
exports.paginationSchema = paginationSchema;
|
|
9096
9519
|
exports.parseAcceptLanguage = parseAcceptLanguage;
|
|
9097
9520
|
exports.parseCookies = parseCookies;
|
|
9521
|
+
exports.passwordResetConfirmSchema = passwordResetConfirmSchema;
|
|
9522
|
+
exports.passwordResetRequestSchema = passwordResetRequestSchema;
|
|
9098
9523
|
exports.phoneBrField = phoneBrField;
|
|
9099
9524
|
exports.refreshSchema = refreshSchema;
|
|
9100
9525
|
exports.registerExceptionHandlers = registerExceptionHandlers;
|
|
@@ -9117,6 +9542,7 @@ exports.ufField = ufField;
|
|
|
9117
9542
|
exports.updatedByColumn = updatedByColumn;
|
|
9118
9543
|
exports.userPublicSchema = userPublicSchema;
|
|
9119
9544
|
exports.utcnow = utcnow;
|
|
9545
|
+
exports.validateTwilioSignature = validateTwilioSignature;
|
|
9120
9546
|
exports.verifyOpaqueToken = verifyOpaqueToken;
|
|
9121
9547
|
exports.webPushKeysSchema = webPushKeysSchema;
|
|
9122
9548
|
exports.webPushPayloadSchema = webPushPayloadSchema;
|