@riocrypto/common-server 1.0.2195 → 1.0.2197

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.
@@ -4,8 +4,26 @@ declare class SecretManagerClient {
4
4
  private env;
5
5
  client: SecretManagerServiceClient;
6
6
  projectId: string;
7
+ private secretCache;
8
+ private readonly POLL_INTERVAL_MS;
7
9
  constructor(env: RioEnv);
10
+ /**
11
+ * Get a secret value from cache or fetch it from Secret Manager
12
+ * Once fetched, the secret will be cached and automatically refreshed every 15 seconds
13
+ */
8
14
  getSecretValue(secretId: string): Promise<string | null>;
15
+ /**
16
+ * Fetch a secret value directly from Secret Manager without using the cache
17
+ */
18
+ private fetchSecretValue;
19
+ /**
20
+ * Set up cache entry with polling for a secret
21
+ */
22
+ private setupCacheWithPolling;
23
+ /**
24
+ * Clear the cache for a specific secret or all secrets
25
+ */
26
+ clearCache(secretId?: string): void;
9
27
  }
10
28
  export declare const secretManagerClient: SecretManagerClient;
11
29
  export {};
@@ -39,6 +39,8 @@ const fs = __importStar(require("fs"));
39
39
  class SecretManagerClient {
40
40
  constructor(env) {
41
41
  this.env = env;
42
+ this.secretCache = new Map();
43
+ this.POLL_INTERVAL_MS = 15 * 1000; // 15 seconds
42
44
  const secretFilePath = "/etc/secrets/secret-manager/secret-manager-service-account-key.json";
43
45
  const secretFileContents = fs.readFileSync(secretFilePath, "utf8");
44
46
  const secretData = JSON.parse(secretFileContents);
@@ -53,7 +55,29 @@ class SecretManagerClient {
53
55
  },
54
56
  });
55
57
  }
58
+ /**
59
+ * Get a secret value from cache or fetch it from Secret Manager
60
+ * Once fetched, the secret will be cached and automatically refreshed every 15 seconds
61
+ */
56
62
  getSecretValue(secretId) {
63
+ return __awaiter(this, void 0, void 0, function* () {
64
+ // Check if the secret is already in the cache
65
+ const cachedSecret = this.secretCache.get(secretId);
66
+ if (cachedSecret) {
67
+ return cachedSecret.value;
68
+ }
69
+ // If not in cache, fetch it and set up polling
70
+ const value = yield this.fetchSecretValue(secretId);
71
+ if (value) {
72
+ this.setupCacheWithPolling(secretId, value);
73
+ }
74
+ return value;
75
+ });
76
+ }
77
+ /**
78
+ * Fetch a secret value directly from Secret Manager without using the cache
79
+ */
80
+ fetchSecretValue(secretId) {
57
81
  var _a, _b;
58
82
  return __awaiter(this, void 0, void 0, function* () {
59
83
  let file;
@@ -102,5 +126,65 @@ class SecretManagerClient {
102
126
  return null;
103
127
  });
104
128
  }
129
+ /**
130
+ * Set up cache entry with polling for a secret
131
+ */
132
+ setupCacheWithPolling(secretId, initialValue) {
133
+ // Only set up polling in non-test environments
134
+ if (process.env.NODE_ENV === "test") {
135
+ // For test environments, just cache the value without polling
136
+ this.secretCache.set(secretId, {
137
+ value: initialValue,
138
+ pollingInterval: null,
139
+ });
140
+ return;
141
+ }
142
+ // Set up polling interval to refresh the secret
143
+ const pollingInterval = setInterval(() => __awaiter(this, void 0, void 0, function* () {
144
+ try {
145
+ const newValue = yield this.fetchSecretValue(secretId);
146
+ if (newValue) {
147
+ const currentCached = this.secretCache.get(secretId);
148
+ // Only update and log if the value has changed
149
+ if (currentCached && currentCached.value !== newValue) {
150
+ console.info(`Secret ${secretId} has been updated`);
151
+ this.secretCache.set(secretId, {
152
+ value: newValue,
153
+ pollingInterval: currentCached.pollingInterval,
154
+ });
155
+ }
156
+ }
157
+ }
158
+ catch (error) {
159
+ console.error(`Error polling secret ${secretId}:`, error);
160
+ }
161
+ }), this.POLL_INTERVAL_MS);
162
+ // Store the initial value and polling interval
163
+ this.secretCache.set(secretId, {
164
+ value: initialValue,
165
+ pollingInterval,
166
+ });
167
+ }
168
+ /**
169
+ * Clear the cache for a specific secret or all secrets
170
+ */
171
+ clearCache(secretId) {
172
+ if (secretId) {
173
+ const cached = this.secretCache.get(secretId);
174
+ if (cached && cached.pollingInterval) {
175
+ clearInterval(cached.pollingInterval);
176
+ }
177
+ this.secretCache.delete(secretId);
178
+ }
179
+ else {
180
+ // Clear all cached secrets
181
+ this.secretCache.forEach((cached) => {
182
+ if (cached.pollingInterval) {
183
+ clearInterval(cached.pollingInterval);
184
+ }
185
+ });
186
+ this.secretCache.clear();
187
+ }
188
+ }
105
189
  }
106
190
  exports.secretManagerClient = new SecretManagerClient(process.env.RIO_ENV || process.env.NEXT_PUBLIC_RIO_ENV);
@@ -21,144 +21,160 @@ const apiKey_1 = require("../services/apiKey");
21
21
  const secret_manager_client_1 = require("../clients/secret-manager-client");
22
22
  const admin_auth_1 = require("../models/admin-auth");
23
23
  const authorize = (req, res, next, mongoose, authorizationTypes) => __awaiter(void 0, void 0, void 0, function* () {
24
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
25
- if (authorizationTypes.includes(common_1.AuthorizationType.GenesisAdmin)) {
26
- let apiKey = req.header("x-genesis-api-key");
27
- const GENESIS_ADMIN_KEY = yield secret_manager_client_1.secretManagerClient.getSecretValue("GENESIS_ADMIN_KEY");
28
- if (!GENESIS_ADMIN_KEY) {
29
- throw new common_1.SecretManagerError();
30
- }
31
- if (apiKey === GENESIS_ADMIN_KEY) {
32
- req.validGenisisAdminKey = true;
33
- }
24
+ var _a, _b;
25
+ // Early return for public routes
26
+ if (authorizationTypes.includes(common_1.AuthorizationType.Public)) {
27
+ next();
28
+ return;
34
29
  }
30
+ // Prepare promises for parallel execution
31
+ const promises = [];
32
+ // Check for cluster API key - only if needed
35
33
  if (authorizationTypes.includes(common_1.AuthorizationType.Cluster)) {
36
- let apiKey = req.header("x-cluster-api-key");
37
- const CLUSTER_API_KEY = yield secret_manager_client_1.secretManagerClient.getSecretValue("CLUSTER_API_KEY");
38
- if (!CLUSTER_API_KEY) {
39
- throw new common_1.SecretManagerError();
34
+ const apiKey = req.header("x-cluster-api-key");
35
+ if (apiKey) {
36
+ promises.push((() => __awaiter(void 0, void 0, void 0, function* () {
37
+ const CLUSTER_API_KEY = yield secret_manager_client_1.secretManagerClient.getSecretValue("CLUSTER_API_KEY");
38
+ if (!CLUSTER_API_KEY) {
39
+ throw new common_1.SecretManagerError();
40
+ }
41
+ if (apiKey === CLUSTER_API_KEY) {
42
+ req.validClusterApiKey = true;
43
+ }
44
+ }))());
40
45
  }
41
- if (apiKey === CLUSTER_API_KEY) {
42
- req.validClusterApiKey = true;
46
+ }
47
+ // Check for genesis admin key - only if needed
48
+ if (authorizationTypes.includes(common_1.AuthorizationType.GenesisAdmin)) {
49
+ const apiKey = req.header("x-genesis-api-key");
50
+ if (apiKey) {
51
+ promises.push((() => __awaiter(void 0, void 0, void 0, function* () {
52
+ const GENESIS_ADMIN_KEY = yield secret_manager_client_1.secretManagerClient.getSecretValue("GENESIS_ADMIN_KEY");
53
+ if (!GENESIS_ADMIN_KEY) {
54
+ throw new common_1.SecretManagerError();
55
+ }
56
+ if (apiKey === GENESIS_ADMIN_KEY) {
57
+ req.validGenisisAdminKey = true;
58
+ }
59
+ }))());
43
60
  }
44
61
  }
62
+ // Check for admin auth - only if needed
45
63
  if (authorizationTypes.includes(common_1.AuthorizationType.AdminAuth)) {
46
64
  const adminApiKey = req.header("x-admin-api-key");
47
- const AdminAuth = yield (0, admin_auth_1.buildAdminAuth)(mongoose);
48
- if (adminApiKey) {
49
- try {
50
- const hashedAdminApiKey = yield apiKey_1.ApiKey.toHash(adminApiKey);
51
- const adminAuth = yield AdminAuth.findOne({
52
- "apiKeys.value": hashedAdminApiKey,
53
- });
54
- if (adminAuth) {
55
- req.adminAuth = adminAuth;
56
- }
57
- }
58
- catch (err) { }
59
- }
60
- else if ((_a = req.cookies) === null || _a === void 0 ? void 0 : _a.adminAccessToken) {
61
- try {
62
- const ADMIN_ACCESS_TOKEN_SECRET = yield secret_manager_client_1.secretManagerClient.getSecretValue("ADMIN_ACCESS_TOKEN_SECRET");
63
- if (!ADMIN_ACCESS_TOKEN_SECRET) {
64
- throw new Error("Unable to get ADMIN_ACCESS_TOKEN_SECRET");
65
+ const adminAccessToken = (_a = req.cookies) === null || _a === void 0 ? void 0 : _a.adminAccessToken;
66
+ if (adminApiKey || adminAccessToken) {
67
+ promises.push((() => __awaiter(void 0, void 0, void 0, function* () {
68
+ const AdminAuth = yield (0, admin_auth_1.buildAdminAuth)(mongoose);
69
+ if (adminApiKey) {
70
+ try {
71
+ const hashedAdminApiKey = yield apiKey_1.ApiKey.toHash(adminApiKey);
72
+ const adminAuth = yield AdminAuth.findOne({
73
+ "apiKeys.value": hashedAdminApiKey,
74
+ });
75
+ if (adminAuth) {
76
+ req.adminAuth = adminAuth;
77
+ }
78
+ }
79
+ catch (err) { }
65
80
  }
66
- const payload = jsonwebtoken_1.default.verify(req.cookies.adminAccessToken, ADMIN_ACCESS_TOKEN_SECRET);
67
- const adminAuth = yield AdminAuth.findById(payload.id);
68
- if (adminAuth) {
69
- req.adminAuth = adminAuth;
81
+ else if (adminAccessToken) {
82
+ try {
83
+ const ADMIN_ACCESS_TOKEN_SECRET = yield secret_manager_client_1.secretManagerClient.getSecretValue("ADMIN_ACCESS_TOKEN_SECRET");
84
+ if (!ADMIN_ACCESS_TOKEN_SECRET) {
85
+ throw new Error("Unable to get ADMIN_ACCESS_TOKEN_SECRET");
86
+ }
87
+ const payload = jsonwebtoken_1.default.verify(adminAccessToken, ADMIN_ACCESS_TOKEN_SECRET);
88
+ const adminAuth = yield AdminAuth.findById(payload.id);
89
+ if (adminAuth) {
90
+ req.adminAuth = adminAuth;
91
+ }
92
+ }
93
+ catch (err) { }
70
94
  }
71
- }
72
- catch (err) { }
95
+ }))());
73
96
  }
74
97
  }
75
- if (authorizationTypes.includes(common_1.AuthorizationType.Auth) ||
98
+ // Check for user auth - only if needed
99
+ const needsUserOrAuth = authorizationTypes.includes(common_1.AuthorizationType.Auth) ||
76
100
  authorizationTypes.includes(common_1.AuthorizationType.UserNoKYC) ||
77
- authorizationTypes.includes(common_1.AuthorizationType.User)) {
101
+ authorizationTypes.includes(common_1.AuthorizationType.User);
102
+ if (needsUserOrAuth) {
78
103
  const apiKey = req.header("x-api-key");
79
- const Auth = yield (0, auth_1.buildAuth)(mongoose);
80
- if (apiKey) {
81
- try {
82
- const hashedApiKey = yield apiKey_1.ApiKey.toHash(apiKey);
83
- const auth = yield Auth.findOne({
84
- "apiKeys.value": hashedApiKey,
85
- });
86
- if (auth) {
87
- req.auth = auth;
88
- }
89
- }
90
- catch (err) { }
91
- }
92
- else if ((_b = req.cookies) === null || _b === void 0 ? void 0 : _b.accessToken) {
93
- try {
94
- const ACCESS_TOKEN_SECRET = yield secret_manager_client_1.secretManagerClient.getSecretValue("ACCESS_TOKEN_SECRET");
95
- if (!ACCESS_TOKEN_SECRET) {
96
- throw new common_1.SecretManagerError();
97
- }
98
- const payload = jsonwebtoken_1.default.verify(req.cookies.accessToken, ACCESS_TOKEN_SECRET);
99
- const auth = yield Auth.findById(payload.id);
100
- if (auth) {
101
- req.auth = auth;
104
+ const accessToken = (_b = req.cookies) === null || _b === void 0 ? void 0 : _b.accessToken;
105
+ if (apiKey || accessToken) {
106
+ promises.push((() => __awaiter(void 0, void 0, void 0, function* () {
107
+ var _c, _d, _e, _f, _g, _h;
108
+ const Auth = yield (0, auth_1.buildAuth)(mongoose);
109
+ let authId = null;
110
+ if (apiKey) {
111
+ try {
112
+ const hashedApiKey = yield apiKey_1.ApiKey.toHash(apiKey);
113
+ const auth = yield Auth.findOne({
114
+ "apiKeys.value": hashedApiKey,
115
+ });
116
+ if (auth) {
117
+ req.auth = auth;
118
+ authId = auth.id;
119
+ }
120
+ }
121
+ catch (err) { }
102
122
  }
103
- }
104
- catch (err) { }
105
- }
106
- }
107
- if (authorizationTypes.includes(common_1.AuthorizationType.UserNoKYC) ||
108
- authorizationTypes.includes(common_1.AuthorizationType.User)) {
109
- if (req.auth) {
110
- try {
111
- const User = yield (0, user_1.buildUser)(mongoose);
112
- const user = yield User.findOne({
113
- authIds: { $in: [(_c = req.auth) === null || _c === void 0 ? void 0 : _c.id] },
114
- });
115
- if (user) {
116
- if (authorizationTypes.includes(common_1.AuthorizationType.UserNoKYC)) {
117
- req.user = user;
123
+ else if (accessToken) {
124
+ try {
125
+ const ACCESS_TOKEN_SECRET = yield secret_manager_client_1.secretManagerClient.getSecretValue("ACCESS_TOKEN_SECRET");
126
+ if (!ACCESS_TOKEN_SECRET) {
127
+ throw new common_1.SecretManagerError();
128
+ }
129
+ const payload = jsonwebtoken_1.default.verify(accessToken, ACCESS_TOKEN_SECRET);
130
+ const auth = yield Auth.findById(payload.id);
131
+ if (auth) {
132
+ req.auth = auth;
133
+ authId = auth.id;
134
+ }
118
135
  }
119
- else {
120
- if (((_e = (_d = user.onboarding) === null || _d === void 0 ? void 0 : _d.MX) === null || _e === void 0 ? void 0 : _e.status) === common_1.OnboardingStatus.Approved ||
121
- ((_g = (_f = user.onboarding) === null || _f === void 0 ? void 0 : _f.PE) === null || _g === void 0 ? void 0 : _g.status) === common_1.OnboardingStatus.Approved ||
122
- ((_j = (_h = user.onboarding) === null || _h === void 0 ? void 0 : _h.US) === null || _j === void 0 ? void 0 : _j.status) === common_1.OnboardingStatus.Approved) {
123
- req.user = user;
136
+ catch (err) { }
137
+ }
138
+ // Only fetch user if we need it and we have an auth ID
139
+ const needsUser = authorizationTypes.includes(common_1.AuthorizationType.UserNoKYC) ||
140
+ authorizationTypes.includes(common_1.AuthorizationType.User);
141
+ if (needsUser && authId) {
142
+ try {
143
+ const User = yield (0, user_1.buildUser)(mongoose);
144
+ const user = yield User.findOne({
145
+ authIds: { $in: [authId] },
146
+ });
147
+ if (user) {
148
+ if (authorizationTypes.includes(common_1.AuthorizationType.UserNoKYC)) {
149
+ req.user = user;
150
+ }
151
+ else if (authorizationTypes.includes(common_1.AuthorizationType.User)) {
152
+ if (((_d = (_c = user.onboarding) === null || _c === void 0 ? void 0 : _c.MX) === null || _d === void 0 ? void 0 : _d.status) === common_1.OnboardingStatus.Approved ||
153
+ ((_f = (_e = user.onboarding) === null || _e === void 0 ? void 0 : _e.PE) === null || _f === void 0 ? void 0 : _f.status) === common_1.OnboardingStatus.Approved ||
154
+ ((_h = (_g = user.onboarding) === null || _g === void 0 ? void 0 : _g.US) === null || _h === void 0 ? void 0 : _h.status) === common_1.OnboardingStatus.Approved) {
155
+ req.user = user;
156
+ }
157
+ }
124
158
  }
125
159
  }
160
+ catch (err) { }
126
161
  }
127
- }
128
- catch (err) { }
162
+ }))());
129
163
  }
130
164
  }
131
- if (authorizationTypes.includes(common_1.AuthorizationType.Public)) {
132
- next();
133
- return;
134
- }
135
- if (authorizationTypes.includes(common_1.AuthorizationType.Cluster) &&
136
- req.validClusterApiKey) {
137
- next();
138
- return;
139
- }
140
- if (authorizationTypes.includes(common_1.AuthorizationType.GenesisAdmin) &&
141
- req.validGenisisAdminKey) {
142
- next();
143
- return;
144
- }
145
- if (authorizationTypes.includes(common_1.AuthorizationType.Auth) && req.auth) {
146
- next();
147
- return;
148
- }
149
- if (authorizationTypes.includes(common_1.AuthorizationType.AdminAuth) &&
150
- req.adminAuth) {
151
- next();
152
- return;
153
- }
154
- if ((authorizationTypes.includes(common_1.AuthorizationType.User) ||
155
- authorizationTypes.includes(common_1.AuthorizationType.UserNoKYC)) &&
156
- req.user) {
157
- next();
158
- return;
159
- }
160
- if (authorizationTypes.includes(common_1.AuthorizationType.AdminAuth) &&
161
- req.adminAuth) {
165
+ // Wait for all promises to complete
166
+ yield Promise.all(promises);
167
+ // Check authorization results and proceed if authorized
168
+ if ((authorizationTypes.includes(common_1.AuthorizationType.Cluster) &&
169
+ req.validClusterApiKey) ||
170
+ (authorizationTypes.includes(common_1.AuthorizationType.GenesisAdmin) &&
171
+ req.validGenisisAdminKey) ||
172
+ (authorizationTypes.includes(common_1.AuthorizationType.Auth) && req.auth) ||
173
+ (authorizationTypes.includes(common_1.AuthorizationType.AdminAuth) &&
174
+ req.adminAuth) ||
175
+ ((authorizationTypes.includes(common_1.AuthorizationType.User) ||
176
+ authorizationTypes.includes(common_1.AuthorizationType.UserNoKYC)) &&
177
+ req.user)) {
162
178
  next();
163
179
  return;
164
180
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riocrypto/common-server",
3
- "version": "1.0.2195",
3
+ "version": "1.0.2197",
4
4
  "description": "",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",