@riocrypto/common-server 1.0.2195 → 1.0.2196

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);
@@ -20,148 +20,173 @@ const auth_1 = require("../models/auth");
20
20
  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
+ const logger_1 = __importDefault(require("../services/logger"));
23
24
  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
- }
25
+ var _a, _b;
26
+ // Start performance monitoring
27
+ const logger = logger_1.default.getLogger();
28
+ const startTime = Date.now();
29
+ // Early return for public routes
30
+ if (authorizationTypes.includes(common_1.AuthorizationType.Public)) {
31
+ next();
32
+ return;
34
33
  }
34
+ // Prepare promises for parallel execution
35
+ const promises = [];
36
+ // Check for cluster API key - only if needed
35
37
  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();
38
+ const apiKey = req.header("x-cluster-api-key");
39
+ if (apiKey) {
40
+ promises.push((() => __awaiter(void 0, void 0, void 0, function* () {
41
+ const CLUSTER_API_KEY = yield secret_manager_client_1.secretManagerClient.getSecretValue("CLUSTER_API_KEY");
42
+ if (!CLUSTER_API_KEY) {
43
+ throw new common_1.SecretManagerError();
44
+ }
45
+ if (apiKey === CLUSTER_API_KEY) {
46
+ req.validClusterApiKey = true;
47
+ }
48
+ }))());
40
49
  }
41
- if (apiKey === CLUSTER_API_KEY) {
42
- req.validClusterApiKey = true;
50
+ }
51
+ // Check for genesis admin key - only if needed
52
+ if (authorizationTypes.includes(common_1.AuthorizationType.GenesisAdmin)) {
53
+ const apiKey = req.header("x-genesis-api-key");
54
+ if (apiKey) {
55
+ promises.push((() => __awaiter(void 0, void 0, void 0, function* () {
56
+ const GENESIS_ADMIN_KEY = yield secret_manager_client_1.secretManagerClient.getSecretValue("GENESIS_ADMIN_KEY");
57
+ if (!GENESIS_ADMIN_KEY) {
58
+ throw new common_1.SecretManagerError();
59
+ }
60
+ if (apiKey === GENESIS_ADMIN_KEY) {
61
+ req.validGenisisAdminKey = true;
62
+ }
63
+ }))());
43
64
  }
44
65
  }
66
+ // Check for admin auth - only if needed
45
67
  if (authorizationTypes.includes(common_1.AuthorizationType.AdminAuth)) {
46
68
  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");
69
+ const adminAccessToken = (_a = req.cookies) === null || _a === void 0 ? void 0 : _a.adminAccessToken;
70
+ if (adminApiKey || adminAccessToken) {
71
+ promises.push((() => __awaiter(void 0, void 0, void 0, function* () {
72
+ const AdminAuth = yield (0, admin_auth_1.buildAdminAuth)(mongoose);
73
+ if (adminApiKey) {
74
+ try {
75
+ const hashedAdminApiKey = yield apiKey_1.ApiKey.toHash(adminApiKey);
76
+ const adminAuth = yield AdminAuth.findOne({
77
+ "apiKeys.value": hashedAdminApiKey,
78
+ });
79
+ if (adminAuth) {
80
+ req.adminAuth = adminAuth;
81
+ }
82
+ }
83
+ catch (err) { }
65
84
  }
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;
85
+ else if (adminAccessToken) {
86
+ try {
87
+ const ADMIN_ACCESS_TOKEN_SECRET = yield secret_manager_client_1.secretManagerClient.getSecretValue("ADMIN_ACCESS_TOKEN_SECRET");
88
+ if (!ADMIN_ACCESS_TOKEN_SECRET) {
89
+ throw new Error("Unable to get ADMIN_ACCESS_TOKEN_SECRET");
90
+ }
91
+ const payload = jsonwebtoken_1.default.verify(adminAccessToken, ADMIN_ACCESS_TOKEN_SECRET);
92
+ const adminAuth = yield AdminAuth.findById(payload.id);
93
+ if (adminAuth) {
94
+ req.adminAuth = adminAuth;
95
+ }
96
+ }
97
+ catch (err) { }
70
98
  }
71
- }
72
- catch (err) { }
99
+ }))());
73
100
  }
74
101
  }
75
- if (authorizationTypes.includes(common_1.AuthorizationType.Auth) ||
102
+ // Check for user auth - only if needed
103
+ const needsUserOrAuth = authorizationTypes.includes(common_1.AuthorizationType.Auth) ||
76
104
  authorizationTypes.includes(common_1.AuthorizationType.UserNoKYC) ||
77
- authorizationTypes.includes(common_1.AuthorizationType.User)) {
105
+ authorizationTypes.includes(common_1.AuthorizationType.User);
106
+ if (needsUserOrAuth) {
78
107
  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;
108
+ const accessToken = (_b = req.cookies) === null || _b === void 0 ? void 0 : _b.accessToken;
109
+ if (apiKey || accessToken) {
110
+ promises.push((() => __awaiter(void 0, void 0, void 0, function* () {
111
+ var _c, _d, _e, _f, _g, _h;
112
+ const Auth = yield (0, auth_1.buildAuth)(mongoose);
113
+ let authId = null;
114
+ if (apiKey) {
115
+ try {
116
+ const hashedApiKey = yield apiKey_1.ApiKey.toHash(apiKey);
117
+ const auth = yield Auth.findOne({
118
+ "apiKeys.value": hashedApiKey,
119
+ });
120
+ if (auth) {
121
+ req.auth = auth;
122
+ authId = auth.id;
123
+ }
124
+ }
125
+ catch (err) { }
102
126
  }
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;
127
+ else if (accessToken) {
128
+ try {
129
+ const ACCESS_TOKEN_SECRET = yield secret_manager_client_1.secretManagerClient.getSecretValue("ACCESS_TOKEN_SECRET");
130
+ if (!ACCESS_TOKEN_SECRET) {
131
+ throw new common_1.SecretManagerError();
132
+ }
133
+ const payload = jsonwebtoken_1.default.verify(accessToken, ACCESS_TOKEN_SECRET);
134
+ const auth = yield Auth.findById(payload.id);
135
+ if (auth) {
136
+ req.auth = auth;
137
+ authId = auth.id;
138
+ }
118
139
  }
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;
140
+ catch (err) { }
141
+ }
142
+ // Only fetch user if we need it and we have an auth ID
143
+ const needsUser = authorizationTypes.includes(common_1.AuthorizationType.UserNoKYC) ||
144
+ authorizationTypes.includes(common_1.AuthorizationType.User);
145
+ if (needsUser && authId) {
146
+ try {
147
+ const User = yield (0, user_1.buildUser)(mongoose);
148
+ const user = yield User.findOne({
149
+ authIds: { $in: [authId] },
150
+ });
151
+ if (user) {
152
+ if (authorizationTypes.includes(common_1.AuthorizationType.UserNoKYC)) {
153
+ req.user = user;
154
+ }
155
+ else if (authorizationTypes.includes(common_1.AuthorizationType.User)) {
156
+ 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 ||
157
+ ((_f = (_e = user.onboarding) === null || _e === void 0 ? void 0 : _e.PE) === null || _f === void 0 ? void 0 : _f.status) === common_1.OnboardingStatus.Approved ||
158
+ ((_h = (_g = user.onboarding) === null || _g === void 0 ? void 0 : _g.US) === null || _h === void 0 ? void 0 : _h.status) === common_1.OnboardingStatus.Approved) {
159
+ req.user = user;
160
+ }
161
+ }
124
162
  }
125
163
  }
164
+ catch (err) { }
126
165
  }
127
- }
128
- catch (err) { }
166
+ }))());
129
167
  }
130
168
  }
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) {
169
+ // Wait for all promises to complete
170
+ yield Promise.all(promises);
171
+ // Check authorization results and proceed if authorized
172
+ if ((authorizationTypes.includes(common_1.AuthorizationType.Cluster) &&
173
+ req.validClusterApiKey) ||
174
+ (authorizationTypes.includes(common_1.AuthorizationType.GenesisAdmin) &&
175
+ req.validGenisisAdminKey) ||
176
+ (authorizationTypes.includes(common_1.AuthorizationType.Auth) && req.auth) ||
177
+ (authorizationTypes.includes(common_1.AuthorizationType.AdminAuth) &&
178
+ req.adminAuth) ||
179
+ ((authorizationTypes.includes(common_1.AuthorizationType.User) ||
180
+ authorizationTypes.includes(common_1.AuthorizationType.UserNoKYC)) &&
181
+ req.user)) {
182
+ const endTime = Date.now();
183
+ logger.info(`Authorization completed in ${endTime - startTime}ms`);
162
184
  next();
163
185
  return;
164
186
  }
187
+ // Log unauthorized attempt
188
+ const endTime = Date.now();
189
+ logger.info(`Authorization failed in ${endTime - startTime}ms`);
165
190
  throw new common_1.NotAuthorizedError();
166
191
  });
167
192
  exports.authorize = authorize;
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.2196",
4
4
  "description": "",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",