@levrbet/shared 0.1.87 → 0.1.88
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/server/auth/kms.js
CHANGED
|
@@ -5,32 +5,21 @@
|
|
|
5
5
|
import { GenerateMacCommand, KMSClient, VerifyCommand, VerifyMacCommand, } from "@aws-sdk/client-kms";
|
|
6
6
|
import { randomBytes } from "crypto";
|
|
7
7
|
import { kmsEnvConfig } from "../config/dotenv";
|
|
8
|
-
import { getRevokedApiKey } from "../oracle/redis-cache-manager/cache.keys.utils"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
const assumedRole = await stsClient.send(new AssumeRoleCommand({
|
|
14
|
-
RoleArn: "arn:aws:iam::905418397427:role/levr-v1-ecs-task-execution-dev",
|
|
15
|
-
RoleSessionName: "kms-session",
|
|
16
|
-
}));
|
|
17
|
-
if (!assumedRole.Credentials) {
|
|
18
|
-
throw new Error("Failed to assume role for KMS access");
|
|
19
|
-
}
|
|
20
|
-
if (!assumedRole.Credentials.AccessKeyId ||
|
|
21
|
-
!assumedRole.Credentials.SecretAccessKey ||
|
|
22
|
-
!assumedRole.Credentials.SessionToken) {
|
|
23
|
-
throw new Error("Incomplete credentials received from assumed role");
|
|
24
|
-
}
|
|
25
|
-
const client = new KMSClient({
|
|
8
|
+
// import { getRevokedApiKey } from "../oracle/redis-cache-manager/cache.keys.utils"
|
|
9
|
+
// Initialize KMS client with proper region and credentials
|
|
10
|
+
function getKMSClient() {
|
|
11
|
+
// Use environment variables for AWS credentials (will use default AWS credential chain)
|
|
12
|
+
const config = {
|
|
26
13
|
region: "ap-south-1",
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
14
|
+
};
|
|
15
|
+
// Only add credentials if both access key and secret are defined
|
|
16
|
+
if (process.env.AWS_ACCESS_KEY_ID && process.env.AWS_SECRET_ACCESS_KEY) {
|
|
17
|
+
config.credentials = {
|
|
18
|
+
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
|
19
|
+
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return new KMSClient(config);
|
|
34
23
|
}
|
|
35
24
|
/**
|
|
36
25
|
* Generates a new API key using AWS KMS
|
|
@@ -42,7 +31,7 @@ async function createKMSClientWithRole() {
|
|
|
42
31
|
export const generateApiKey = async (userId) => {
|
|
43
32
|
const keyId = randomBytes(8).toString("hex"); // Unique key identifier
|
|
44
33
|
const payload = `${userId}:${keyId}`;
|
|
45
|
-
const client =
|
|
34
|
+
const client = getKMSClient();
|
|
46
35
|
const { Mac } = await client.send(new GenerateMacCommand({
|
|
47
36
|
KeyId: kmsEnvConfig.HMAC_KEY_ALIAS,
|
|
48
37
|
Message: Buffer.from(payload),
|
|
@@ -66,11 +55,12 @@ export const validateApiKey = async (apiKey, redis) => {
|
|
|
66
55
|
const [payload, signature] = apiKey.split(".");
|
|
67
56
|
const [, keyId] = payload.split(":");
|
|
68
57
|
// 1. Check if key is revoked in Redis
|
|
69
|
-
const isRevoked = await redis.get(getRevokedApiKey(keyId))
|
|
58
|
+
// const isRevoked = await redis.get(getRevokedApiKey(keyId as string)) // possibly save this to prisma too
|
|
59
|
+
let isRevoked = "1";
|
|
70
60
|
if (isRevoked == "1") {
|
|
71
61
|
return { isValid: false, reason: "Key revoked" };
|
|
72
62
|
}
|
|
73
|
-
const client =
|
|
63
|
+
const client = getKMSClient();
|
|
74
64
|
const { MacValid } = await client.send(new VerifyMacCommand({
|
|
75
65
|
KeyId: kmsEnvConfig.HMAC_KEY_ALIAS,
|
|
76
66
|
Message: Buffer.from(payload),
|
|
@@ -91,7 +81,7 @@ export const revokeKey = async (keyId, apiKey) => {
|
|
|
91
81
|
if (providedKeyId !== keyId) {
|
|
92
82
|
throw new Error("Key ID mismatch during revocation");
|
|
93
83
|
}
|
|
94
|
-
const client =
|
|
84
|
+
const client = getKMSClient();
|
|
95
85
|
// 2. Verify KMS signature before revocation
|
|
96
86
|
const { SignatureValid } = await client.send(new VerifyCommand({
|
|
97
87
|
KeyId: kmsEnvConfig.HMAC_KEY_ALIAS,
|
|
@@ -117,7 +107,7 @@ export const generateHmacSignature = async (payload) => {
|
|
|
117
107
|
Message: Buffer.from(payload),
|
|
118
108
|
MacAlgorithm: "HMAC_SHA_384",
|
|
119
109
|
});
|
|
120
|
-
const client =
|
|
110
|
+
const client = getKMSClient();
|
|
121
111
|
const response = await client.send(command);
|
|
122
112
|
if (!response.Mac) {
|
|
123
113
|
throw new Error("Failed to generate HMAC signature");
|
|
@@ -135,7 +125,7 @@ export const verifyHmacSignature = async (payload, signature) => {
|
|
|
135
125
|
Mac: Buffer.from(signature, "base64"),
|
|
136
126
|
MacAlgorithm: "HMAC_SHA_384",
|
|
137
127
|
});
|
|
138
|
-
const client =
|
|
128
|
+
const client = getKMSClient();
|
|
139
129
|
const response = await client.send(command);
|
|
140
130
|
return response.MacValid || false;
|
|
141
131
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kms.js","sourceRoot":"","sources":["../../../src/server/auth/kms.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,aAAa,EAAE,gBAAgB,GAAG,MAAM,qBAAqB,CAAA;AACrG,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAA;AAEpC,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC/C,
|
|
1
|
+
{"version":3,"file":"kms.js","sourceRoot":"","sources":["../../../src/server/auth/kms.ts"],"names":[],"mappings":"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"}
|
|
@@ -29,7 +29,13 @@ export const levrSharedConfig = Config.init(levrSharedSchema);
|
|
|
29
29
|
export const relayerSchema = z.object({
|
|
30
30
|
RELAYER_ACCESS_TOKEN: z.uuid(),
|
|
31
31
|
});
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
// Initialize KMS config from environment variables
|
|
33
|
+
export const kmsEnvConfig = {
|
|
34
|
+
HMAC_KEY_ALIAS: process.env.HMAC_KEY_ALIAS || 'alias/levr-server-to-server-auth-hmac',
|
|
35
|
+
CLOUDFLARE_JWK_URL: process.env.CLOUDFLARE_JWK_URL || '',
|
|
36
|
+
CLOUDFLARE_ISSUER: process.env.CLOUDFLARE_ISSUER || '',
|
|
37
|
+
CLOUDFLARE_AUDIENCE: process.env.CLOUDFLARE_AUDIENCE || '',
|
|
38
|
+
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID || '',
|
|
39
|
+
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY || '',
|
|
40
|
+
};
|
|
35
41
|
//# sourceMappingURL=dotenv.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dotenv.js","sourceRoot":"","sources":["../../../src/server/config/dotenv.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AACtE,OAAO,eAAe,CAAA;AACtB,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,yCAAyC;AACzC,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,0BAA0B,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7C,2BAA2B,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9C,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACpC,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;CAC5B,CAAC,CAAA;AAEF,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9B,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;CAC5B,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9B,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACjC,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACrC,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACpC,mBAAmB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CACzC,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,+BAA+B,CAAC;CACpD,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,+BAA+B,CAAC;IACjD,uBAAuB,EAAE,wBAAwB;CACpD,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;AAE7D,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,oBAAoB,EAAE,CAAC,CAAC,IAAI,EAAE;CACjC,CAAC,CAAA;AAEF,
|
|
1
|
+
{"version":3,"file":"dotenv.js","sourceRoot":"","sources":["../../../src/server/config/dotenv.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AACtE,OAAO,eAAe,CAAA;AACtB,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,yCAAyC;AACzC,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,0BAA0B,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7C,2BAA2B,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9C,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACpC,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;CAC5B,CAAC,CAAA;AAEF,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9B,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;CAC5B,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9B,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACjC,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACrC,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACpC,mBAAmB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CACzC,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,+BAA+B,CAAC;CACpD,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,+BAA+B,CAAC;IACjD,uBAAuB,EAAE,wBAAwB;CACpD,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;AAE7D,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,oBAAoB,EAAE,CAAC,CAAC,IAAI,EAAE;CACjC,CAAC,CAAA;AAEF,mDAAmD;AACnD,MAAM,CAAC,MAAM,YAAY,GAAG;IACxB,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,uCAAuC;IACrF,kBAAkB,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,EAAE;IACxD,iBAAiB,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE;IACtD,mBAAmB,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,EAAE;IAC1D,iBAAiB,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE;IACtD,qBAAqB,EAAE,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,EAAE;CACpC,CAAA"}
|