@epztickets/common 1.64.0 → 1.65.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/build/events/subjects.d.ts +1 -0
- package/build/events/subjects.js +6 -0
- package/build/events/user-email-verification-requested-event.d.ts +12 -0
- package/build/events/user-email-verification-requested-event.js +2 -0
- package/build/index.d.ts +1 -0
- package/build/index.js +1 -0
- package/build/middlewares/current-user.js +53 -2
- package/package.json +1 -1
|
@@ -28,6 +28,7 @@ export declare enum Subjects {
|
|
|
28
28
|
UserDeleted = "events.user.deleted",
|
|
29
29
|
UserDeletionRequested = "events.user.deletion-requested",
|
|
30
30
|
UserDeletionRejected = "events.user.deletion-rejected",
|
|
31
|
+
UserEmailVerificationRequested = "events.user.email-verification-requested",
|
|
31
32
|
ConnectDisconnectRequested = "events.user.connect-disconnect-requested",
|
|
32
33
|
ConnectDisconnectApproved = "events.user.connect-disconnect-approved",
|
|
33
34
|
ConnectDisconnectRejected = "events.user.connect-disconnect-rejected"
|
package/build/events/subjects.js
CHANGED
|
@@ -45,6 +45,12 @@ var Subjects;
|
|
|
45
45
|
Subjects["UserDeleted"] = "events.user.deleted";
|
|
46
46
|
Subjects["UserDeletionRequested"] = "events.user.deletion-requested";
|
|
47
47
|
Subjects["UserDeletionRejected"] = "events.user.deletion-rejected";
|
|
48
|
+
// Auth publishes at signup (and on resend-verification) with the
|
|
49
|
+
// plaintext one-shot token + expiry. notifications-srv consumes
|
|
50
|
+
// and dispatches the verification email. The plaintext is in the
|
|
51
|
+
// event payload because the email is the ONE place it surfaces
|
|
52
|
+
// — auth's User row only has the SHA-256 hash.
|
|
53
|
+
Subjects["UserEmailVerificationRequested"] = "events.user.email-verification-requested";
|
|
48
54
|
// Owner-initiated "stop hosting" lifecycle. Mirrors the deletion
|
|
49
55
|
// request triplet — auth publishes Requested at submission, then
|
|
50
56
|
// either Approved (which IS the disconnect) or Rejected after admin
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Subjects } from "./subjects";
|
|
2
|
+
export interface UserEmailVerificationRequestedEvent {
|
|
3
|
+
subject: Subjects.UserEmailVerificationRequested;
|
|
4
|
+
data: {
|
|
5
|
+
userId: string;
|
|
6
|
+
email: string;
|
|
7
|
+
/** Plaintext verification token to embed in the email link. */
|
|
8
|
+
token: string;
|
|
9
|
+
/** ISO timestamp of when the token expires (24h after issue). */
|
|
10
|
+
expiresAt: string;
|
|
11
|
+
};
|
|
12
|
+
}
|
package/build/index.d.ts
CHANGED
|
@@ -45,6 +45,7 @@ export * from "./events/user-updated-event";
|
|
|
45
45
|
export * from "./events/user-deleted-event";
|
|
46
46
|
export * from "./events/user-deletion-requested-event";
|
|
47
47
|
export * from "./events/user-deletion-rejected-event";
|
|
48
|
+
export * from "./events/user-email-verification-requested-event";
|
|
48
49
|
export * from "./events/connect-disconnect-requested-event";
|
|
49
50
|
export * from "./events/connect-disconnect-approved-event";
|
|
50
51
|
export * from "./events/connect-disconnect-rejected-event";
|
package/build/index.js
CHANGED
|
@@ -64,6 +64,7 @@ __exportStar(require("./events/user-updated-event"), exports);
|
|
|
64
64
|
__exportStar(require("./events/user-deleted-event"), exports);
|
|
65
65
|
__exportStar(require("./events/user-deletion-requested-event"), exports);
|
|
66
66
|
__exportStar(require("./events/user-deletion-rejected-event"), exports);
|
|
67
|
+
__exportStar(require("./events/user-email-verification-requested-event"), exports);
|
|
67
68
|
__exportStar(require("./events/connect-disconnect-requested-event"), exports);
|
|
68
69
|
__exportStar(require("./events/connect-disconnect-approved-event"), exports);
|
|
69
70
|
__exportStar(require("./events/connect-disconnect-rejected-event"), exports);
|
|
@@ -5,15 +5,66 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.currentUser = void 0;
|
|
7
7
|
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
8
|
+
// Look up the public key for a given `kid` (key id, from the JWT
|
|
9
|
+
// header). Falls through to single-key JWT_PUBLIC_KEY if either no
|
|
10
|
+
// kid is present (legacy token issued before rotation was wired)
|
|
11
|
+
// or the keyed env var isn't set (still operating in single-key
|
|
12
|
+
// mode pre-rotation).
|
|
13
|
+
//
|
|
14
|
+
// Two supported env layouts:
|
|
15
|
+
//
|
|
16
|
+
// Single-key (legacy, default):
|
|
17
|
+
// JWT_PUBLIC_KEY=<pem>
|
|
18
|
+
//
|
|
19
|
+
// Multi-key (during/after rotation):
|
|
20
|
+
// JWT_PUBLIC_KEYS={"kid-1":"<pem>","kid-2":"<pem>"}
|
|
21
|
+
// JWT_PUBLIC_KEY=<pem> (still accepted as fallback)
|
|
22
|
+
//
|
|
23
|
+
// JWT_PUBLIC_KEYS holds a JSON object mapping kid → PEM. The PEMs
|
|
24
|
+
// have embedded newlines which is awkward in shell env vars; the
|
|
25
|
+
// production convention is to base64-encode each PEM in the JSON
|
|
26
|
+
// value and decode here. To keep this middleware compatible with
|
|
27
|
+
// plain-text PEMs too (the common case in tests + dev), we accept
|
|
28
|
+
// both: if a value contains "-----BEGIN" it's used as-is; otherwise
|
|
29
|
+
// we base64-decode it.
|
|
30
|
+
//
|
|
31
|
+
// The JSON parse + decode runs ON EACH REQUEST today. That's fine
|
|
32
|
+
// for current traffic; if it ever becomes hot, memoize at first use.
|
|
33
|
+
function lookupPublicKey(kid) {
|
|
34
|
+
var _a;
|
|
35
|
+
const mapJson = process.env.JWT_PUBLIC_KEYS;
|
|
36
|
+
if (kid && mapJson) {
|
|
37
|
+
try {
|
|
38
|
+
const map = JSON.parse(mapJson);
|
|
39
|
+
const value = map[kid];
|
|
40
|
+
if (value) {
|
|
41
|
+
return value.includes("-----BEGIN")
|
|
42
|
+
? value
|
|
43
|
+
: Buffer.from(value, "base64").toString("utf8");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
console.error("JWT_PUBLIC_KEYS is set but not valid JSON; falling back to JWT_PUBLIC_KEY", err);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return (_a = process.env.JWT_PUBLIC_KEY) !== null && _a !== void 0 ? _a : null;
|
|
51
|
+
}
|
|
8
52
|
const currentUser = (req, res, next) => {
|
|
9
53
|
var _a;
|
|
10
54
|
if (!((_a = req.session) === null || _a === void 0 ? void 0 : _a.jwt)) {
|
|
11
55
|
return next();
|
|
12
56
|
}
|
|
13
57
|
try {
|
|
14
|
-
|
|
58
|
+
// Decode without verifying to read the `kid` header so we can
|
|
59
|
+
// pick the right public key. The actual signature check happens
|
|
60
|
+
// in the verify() call below — decode is just for routing.
|
|
61
|
+
const decoded = jsonwebtoken_1.default.decode(req.session.jwt, { complete: true });
|
|
62
|
+
const headerKid = decoded && typeof decoded !== "string"
|
|
63
|
+
? decoded.header.kid
|
|
64
|
+
: undefined;
|
|
65
|
+
const publicKey = lookupPublicKey(headerKid);
|
|
15
66
|
if (!publicKey) {
|
|
16
|
-
console.error("
|
|
67
|
+
console.error(`JWT verify: no public key configured (kid="${headerKid !== null && headerKid !== void 0 ? headerKid : "none"}")`);
|
|
17
68
|
return next();
|
|
18
69
|
}
|
|
19
70
|
const payload = jsonwebtoken_1.default.verify(req.session.jwt, publicKey, {
|