@goatlab/node-backend 0.2.5 → 0.4.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 +146 -14
- package/dist/container/Container.d.ts +113 -25
- package/dist/container/Container.js +391 -168
- package/dist/container/Container.js.map +1 -1
- package/dist/container/examples/batch-operations.example.d.ts +1 -0
- package/dist/container/examples/batch-operations.example.js +165 -0
- package/dist/container/examples/batch-operations.example.js.map +1 -0
- package/dist/container/helpers.d.ts +8 -0
- package/dist/container/helpers.js +22 -0
- package/dist/container/helpers.js.map +1 -1
- package/dist/container/types.d.ts +60 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/server/bootstraps/getExpressTrpcApp.d.ts +5 -1
- package/dist/server/bootstraps/getExpressTrpcApp.js +216 -12
- package/dist/server/bootstraps/getExpressTrpcApp.js.map +1 -1
- package/dist/server/middleware/memoryMonitor.example.d.ts +1 -0
- package/dist/server/middleware/memoryMonitor.example.js +109 -0
- package/dist/server/middleware/memoryMonitor.example.js.map +1 -0
- package/dist/server/middleware/memoryMonitor.middleware.d.ts +42 -0
- package/dist/server/middleware/memoryMonitor.middleware.js +134 -0
- package/dist/server/middleware/memoryMonitor.middleware.js.map +1 -0
- package/dist/server/middleware/productionError.middleware.d.ts +16 -0
- package/dist/server/middleware/productionError.middleware.js +94 -0
- package/dist/server/middleware/productionError.middleware.js.map +1 -0
- package/dist/server/middleware/security.middleware.d.ts +28 -0
- package/dist/server/middleware/security.middleware.js +151 -0
- package/dist/server/middleware/security.middleware.js.map +1 -0
- package/dist/server/services/secrets/examples/container-preload.example.d.ts +1 -0
- package/dist/server/services/secrets/examples/container-preload.example.js +148 -0
- package/dist/server/services/secrets/examples/container-preload.example.js.map +1 -0
- package/dist/server/services/secrets/index.d.ts +1 -0
- package/dist/server/services/secrets/index.js +6 -0
- package/dist/server/services/secrets/index.js.map +1 -0
- package/dist/server/services/secrets/secret.service.d.ts +48 -6
- package/dist/server/services/secrets/secret.service.js +280 -28
- package/dist/server/services/secrets/secret.service.js.map +1 -1
- package/dist/server/services/translations/translation.model.js +2 -1
- package/dist/server/services/translations/translation.model.js.map +1 -1
- package/dist/server/services/translations/translation.service.d.ts +8 -1
- package/dist/server/services/translations/translation.service.js +123 -13
- package/dist/server/services/translations/translation.service.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +13 -1
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sanitizeErrorForProduction = sanitizeErrorForProduction;
|
|
4
|
+
exports.productionErrorHandler = productionErrorHandler;
|
|
5
|
+
exports.asyncErrorHandler = asyncErrorHandler;
|
|
6
|
+
const js_utils_1 = require("@goatlab/js-utils");
|
|
7
|
+
/**
|
|
8
|
+
* Sanitize error messages for production environment
|
|
9
|
+
* Prevents leaking sensitive information in error responses
|
|
10
|
+
*/
|
|
11
|
+
function sanitizeErrorForProduction(error) {
|
|
12
|
+
const isProduction = process.env.NODE_ENV === 'prod';
|
|
13
|
+
if (!isProduction) {
|
|
14
|
+
return error; // In development, return full error details
|
|
15
|
+
}
|
|
16
|
+
// Clone the error to avoid mutating the original
|
|
17
|
+
const sanitizedError = { ...error };
|
|
18
|
+
// For 5xx errors, hide internal details
|
|
19
|
+
if (error.data?.httpStatusCode && error.data.httpStatusCode >= 500) {
|
|
20
|
+
sanitizedError.message = 'Internal Server Error';
|
|
21
|
+
sanitizedError.stack = undefined;
|
|
22
|
+
// Keep only safe data
|
|
23
|
+
sanitizedError.data = {
|
|
24
|
+
httpStatusCode: error.data.httpStatusCode,
|
|
25
|
+
errorId: error.data.errorId,
|
|
26
|
+
timestamp: new Date().toISOString()
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
else if (error.data?.httpStatusCode && error.data.httpStatusCode >= 400) {
|
|
30
|
+
// For 4xx errors, keep the message but remove stack traces
|
|
31
|
+
sanitizedError.stack = undefined;
|
|
32
|
+
// Remove any potentially sensitive data
|
|
33
|
+
if (sanitizedError.data) {
|
|
34
|
+
const { httpStatusCode, errorId, message, code } = sanitizedError.data;
|
|
35
|
+
sanitizedError.data = {
|
|
36
|
+
httpStatusCode,
|
|
37
|
+
errorId,
|
|
38
|
+
message: message || sanitizedError.message,
|
|
39
|
+
code,
|
|
40
|
+
timestamp: new Date().toISOString()
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return sanitizedError;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Production-ready error handler middleware
|
|
48
|
+
* Ensures no sensitive information is leaked in error responses
|
|
49
|
+
*/
|
|
50
|
+
function productionErrorHandler() {
|
|
51
|
+
return (err, req, res, next) => {
|
|
52
|
+
// If headers are already sent, delegate to default Express error handler
|
|
53
|
+
if (res.headersSent) {
|
|
54
|
+
return next(err);
|
|
55
|
+
}
|
|
56
|
+
// Convert to error object
|
|
57
|
+
const error = js_utils_1.Errors.anyToError(err);
|
|
58
|
+
const httpError = error;
|
|
59
|
+
// Sanitize the error for production
|
|
60
|
+
const sanitizedError = sanitizeErrorForProduction(httpError);
|
|
61
|
+
// Set default status code if not provided
|
|
62
|
+
const statusCode = sanitizedError.data?.httpStatusCode || 500;
|
|
63
|
+
// Log the original error (for debugging)
|
|
64
|
+
if (statusCode >= 500) {
|
|
65
|
+
console.error('Server error:', {
|
|
66
|
+
error: err,
|
|
67
|
+
request: {
|
|
68
|
+
method: req.method,
|
|
69
|
+
url: req.originalUrl,
|
|
70
|
+
ip: req.ip,
|
|
71
|
+
userAgent: req.get('user-agent')
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
// Send sanitized response
|
|
76
|
+
res.status(statusCode).json({
|
|
77
|
+
error: {
|
|
78
|
+
message: sanitizedError.message,
|
|
79
|
+
code: sanitizedError.data?.code,
|
|
80
|
+
errorId: sanitizedError.data?.errorId,
|
|
81
|
+
timestamp: sanitizedError.data?.timestamp || new Date().toISOString()
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Async error wrapper to catch errors in async route handlers
|
|
88
|
+
*/
|
|
89
|
+
function asyncErrorHandler(fn) {
|
|
90
|
+
return (req, res, next) => {
|
|
91
|
+
Promise.resolve(fn(req, res, next)).catch(next);
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=productionError.middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"productionError.middleware.js","sourceRoot":"","sources":["../../../src/server/middleware/productionError.middleware.ts"],"names":[],"mappings":";;AASA,gEAyCC;AAMD,wDAwCC;AAKD,8CAIC;AAvGD,gDAA0C;AAG1C;;;GAGG;AACH,SAAgB,0BAA0B,CACxC,KAA+B;IAE/B,MAAM,YAAY,GAAI,OAAO,CAAC,GAAG,CAAC,QAAwB,KAAK,MAAM,CAAA;IAErE,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,KAAK,CAAA,CAAC,4CAA4C;IAC3D,CAAC;IAED,iDAAiD;IACjD,MAAM,cAAc,GAAG,EAAE,GAAG,KAAK,EAAE,CAAA;IAEnC,wCAAwC;IACxC,IAAI,KAAK,CAAC,IAAI,EAAE,cAAc,IAAI,KAAK,CAAC,IAAI,CAAC,cAAc,IAAI,GAAG,EAAE,CAAC;QACnE,cAAc,CAAC,OAAO,GAAG,uBAAuB,CAAA;QAChD,cAAc,CAAC,KAAK,GAAG,SAAS,CAAA;QAEhC,sBAAsB;QACtB,cAAc,CAAC,IAAI,GAAG;YACpB,cAAc,EAAE,KAAK,CAAC,IAAI,CAAC,cAAc;YACzC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,OAAO;YAC3B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAA;IACH,CAAC;SAAM,IAAI,KAAK,CAAC,IAAI,EAAE,cAAc,IAAI,KAAK,CAAC,IAAI,CAAC,cAAc,IAAI,GAAG,EAAE,CAAC;QAC1E,2DAA2D;QAC3D,cAAc,CAAC,KAAK,GAAG,SAAS,CAAA;QAEhC,wCAAwC;QACxC,IAAI,cAAc,CAAC,IAAI,EAAE,CAAC;YACxB,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,cAAc,CAAC,IAAI,CAAA;YACtE,cAAc,CAAC,IAAI,GAAG;gBACpB,cAAc;gBACd,OAAO;gBACP,OAAO,EAAE,OAAO,IAAI,cAAc,CAAC,OAAO;gBAC1C,IAAI;gBACJ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAA;QACH,CAAC;IACH,CAAC;IAED,OAAO,cAAc,CAAA;AACvB,CAAC;AAED;;;GAGG;AACH,SAAgB,sBAAsB;IACpC,OAAO,CAAC,GAAQ,EAAE,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;QACnE,yEAAyE;QACzE,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;YACpB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAA;QAClB,CAAC;QAED,0BAA0B;QAC1B,MAAM,KAAK,GAAG,iBAAM,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;QACpC,MAAM,SAAS,GAAG,KAAiC,CAAA;QAEnD,oCAAoC;QACpC,MAAM,cAAc,GAAG,0BAA0B,CAAC,SAAS,CAAC,CAAA;QAE5D,0CAA0C;QAC1C,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,EAAE,cAAc,IAAI,GAAG,CAAA;QAE7D,yCAAyC;QACzC,IAAI,UAAU,IAAI,GAAG,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,eAAe,EAAE;gBAC7B,KAAK,EAAE,GAAG;gBACV,OAAO,EAAE;oBACP,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,GAAG,EAAE,GAAG,CAAC,WAAW;oBACpB,EAAE,EAAE,GAAG,CAAC,EAAE;oBACV,SAAS,EAAE,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC;iBACjC;aACF,CAAC,CAAA;QACJ,CAAC;QAED,0BAA0B;QAC1B,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC;YAC1B,KAAK,EAAE;gBACL,OAAO,EAAE,cAAc,CAAC,OAAO;gBAC/B,IAAI,EAAE,cAAc,CAAC,IAAI,EAAE,IAAI;gBAC/B,OAAO,EAAE,cAAc,CAAC,IAAI,EAAE,OAAO;gBACrC,SAAS,EAAE,cAAc,CAAC,IAAI,EAAE,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACtE;SACF,CAAC,CAAA;IACJ,CAAC,CAAA;AACH,CAAC;AAED;;GAEG;AACH,SAAgB,iBAAiB,CAAC,EAAY;IAC5C,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;QACzD,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACjD,CAAC,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { CorsOptions } from 'cors';
|
|
2
|
+
import type { HelmetOptions } from 'helmet';
|
|
3
|
+
import type { RateLimitRequestHandler } from 'express-rate-limit';
|
|
4
|
+
import rateLimit from 'express-rate-limit';
|
|
5
|
+
/**
|
|
6
|
+
* Get CORS configuration based on environment
|
|
7
|
+
*/
|
|
8
|
+
export declare function getCorsOptions(): CorsOptions;
|
|
9
|
+
/**
|
|
10
|
+
* Get Helmet configuration for enhanced security headers
|
|
11
|
+
*/
|
|
12
|
+
export declare function getHelmetOptions(): HelmetOptions;
|
|
13
|
+
/**
|
|
14
|
+
* Create rate limiter with default configuration
|
|
15
|
+
*/
|
|
16
|
+
export declare function createRateLimiter(options?: Partial<Parameters<typeof rateLimit>[0]>): RateLimitRequestHandler;
|
|
17
|
+
/**
|
|
18
|
+
* Create stricter rate limiter for authentication endpoints
|
|
19
|
+
*/
|
|
20
|
+
export declare function createAuthRateLimiter(): RateLimitRequestHandler;
|
|
21
|
+
/**
|
|
22
|
+
* Create rate limiter for API endpoints
|
|
23
|
+
*/
|
|
24
|
+
export declare function createApiRateLimiter(): RateLimitRequestHandler;
|
|
25
|
+
/**
|
|
26
|
+
* Additional security headers not covered by Helmet
|
|
27
|
+
*/
|
|
28
|
+
export declare function additionalSecurityHeaders(): (req: any, res: any, next: any) => void;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getCorsOptions = getCorsOptions;
|
|
4
|
+
exports.getHelmetOptions = getHelmetOptions;
|
|
5
|
+
exports.createRateLimiter = createRateLimiter;
|
|
6
|
+
exports.createAuthRateLimiter = createAuthRateLimiter;
|
|
7
|
+
exports.createApiRateLimiter = createApiRateLimiter;
|
|
8
|
+
exports.additionalSecurityHeaders = additionalSecurityHeaders;
|
|
9
|
+
const express_rate_limit_1 = require("express-rate-limit");
|
|
10
|
+
/**
|
|
11
|
+
* Get CORS configuration based on environment
|
|
12
|
+
*/
|
|
13
|
+
function getCorsOptions() {
|
|
14
|
+
const allowedOrigins = process.env.ALLOWED_ORIGINS?.split(',').map(origin => origin.trim()) || [];
|
|
15
|
+
// In development, allow localhost origins
|
|
16
|
+
if (process.env.NODE_ENV !== 'prod' && allowedOrigins.length === 0) {
|
|
17
|
+
allowedOrigins.push('http://localhost:3000', 'http://localhost:3001', 'http://localhost:5173');
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
origin: (origin, callback) => {
|
|
21
|
+
// Allow requests with no origin (like mobile apps or Postman)
|
|
22
|
+
if (!origin && process.env.NODE_ENV !== 'prod') {
|
|
23
|
+
return callback(null, true);
|
|
24
|
+
}
|
|
25
|
+
if (!origin || allowedOrigins.includes(origin)) {
|
|
26
|
+
callback(null, true);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
callback(new Error('Not allowed by CORS'));
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
credentials: true,
|
|
33
|
+
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
|
|
34
|
+
allowedHeaders: ['Content-Type', 'Authorization', 'X-Request-ID'],
|
|
35
|
+
exposedHeaders: [
|
|
36
|
+
'X-Request-ID',
|
|
37
|
+
'X-RateLimit-Limit',
|
|
38
|
+
'X-RateLimit-Remaining',
|
|
39
|
+
'X-RateLimit-Reset'
|
|
40
|
+
],
|
|
41
|
+
maxAge: 86400, // 24 hours
|
|
42
|
+
optionsSuccessStatus: 200 // Some legacy browsers choke on 204
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Get Helmet configuration for enhanced security headers
|
|
47
|
+
*/
|
|
48
|
+
function getHelmetOptions() {
|
|
49
|
+
const isDevelopment = process.env.NODE_ENV !== 'prod';
|
|
50
|
+
return {
|
|
51
|
+
contentSecurityPolicy: isDevelopment
|
|
52
|
+
? false
|
|
53
|
+
: {
|
|
54
|
+
directives: {
|
|
55
|
+
defaultSrc: ["'self'"],
|
|
56
|
+
scriptSrc: ["'self'", "'unsafe-inline'"], // Consider removing unsafe-inline in production
|
|
57
|
+
styleSrc: ["'self'", "'unsafe-inline'"],
|
|
58
|
+
imgSrc: ["'self'", 'data:', 'https:'],
|
|
59
|
+
connectSrc: ["'self'"],
|
|
60
|
+
fontSrc: ["'self'"],
|
|
61
|
+
objectSrc: ["'none'"],
|
|
62
|
+
mediaSrc: ["'self'"],
|
|
63
|
+
frameSrc: ["'none'"],
|
|
64
|
+
baseUri: ["'self'"],
|
|
65
|
+
formAction: ["'self'"],
|
|
66
|
+
frameAncestors: ["'none'"],
|
|
67
|
+
upgradeInsecureRequests: []
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
hsts: {
|
|
71
|
+
maxAge: 31536000, // 1 year
|
|
72
|
+
includeSubDomains: true,
|
|
73
|
+
preload: true
|
|
74
|
+
},
|
|
75
|
+
noSniff: true,
|
|
76
|
+
xssFilter: true,
|
|
77
|
+
referrerPolicy: { policy: 'strict-origin-when-cross-origin' },
|
|
78
|
+
permittedCrossDomainPolicies: false,
|
|
79
|
+
hidePoweredBy: true,
|
|
80
|
+
ieNoOpen: true,
|
|
81
|
+
frameguard: { action: 'deny' }
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Create rate limiter with default configuration
|
|
86
|
+
*/
|
|
87
|
+
function createRateLimiter(options) {
|
|
88
|
+
return (0, express_rate_limit_1.default)({
|
|
89
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
90
|
+
max: 100, // Limit each IP to 100 requests per windowMs
|
|
91
|
+
message: 'Too many requests from this IP, please try again later.',
|
|
92
|
+
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
|
|
93
|
+
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
|
|
94
|
+
skipSuccessfulRequests: false,
|
|
95
|
+
// Skip rate limiting validation errors in test environment
|
|
96
|
+
validate: process.env.NODE_ENV === 'test' ? false : undefined,
|
|
97
|
+
handler: (_req, res) => {
|
|
98
|
+
res.status(429).json({
|
|
99
|
+
error: {
|
|
100
|
+
code: 'RATE_LIMIT_EXCEEDED',
|
|
101
|
+
message: 'Too many requests, please try again later.',
|
|
102
|
+
retryAfter: res.getHeader('Retry-After')
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
},
|
|
106
|
+
...options
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Create stricter rate limiter for authentication endpoints
|
|
111
|
+
*/
|
|
112
|
+
function createAuthRateLimiter() {
|
|
113
|
+
return createRateLimiter({
|
|
114
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
115
|
+
max: 5, // Limit each IP to 5 requests per windowMs
|
|
116
|
+
skipSuccessfulRequests: true, // Don't count successful requests
|
|
117
|
+
message: 'Too many authentication attempts, please try again later.'
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Create rate limiter for API endpoints
|
|
122
|
+
*/
|
|
123
|
+
function createApiRateLimiter() {
|
|
124
|
+
const maxRequests = process.env.API_RATE_LIMIT
|
|
125
|
+
? parseInt(process.env.API_RATE_LIMIT, 10)
|
|
126
|
+
: 100;
|
|
127
|
+
return createRateLimiter({
|
|
128
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
129
|
+
max: maxRequests,
|
|
130
|
+
message: 'API rate limit exceeded, please try again later.'
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Additional security headers not covered by Helmet
|
|
135
|
+
*/
|
|
136
|
+
function additionalSecurityHeaders() {
|
|
137
|
+
return (req, res, next) => {
|
|
138
|
+
// Permissions Policy (formerly Feature Policy)
|
|
139
|
+
res.setHeader('Permissions-Policy', 'geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), accelerometer=()');
|
|
140
|
+
// Additional security headers
|
|
141
|
+
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
142
|
+
res.setHeader('X-Frame-Options', 'DENY');
|
|
143
|
+
res.setHeader('X-XSS-Protection', '1; mode=block');
|
|
144
|
+
// Clear site data on logout (if logout endpoint)
|
|
145
|
+
if (req.path === '/logout' || req.path === '/api/logout') {
|
|
146
|
+
res.setHeader('Clear-Site-Data', '"cache", "cookies", "storage"');
|
|
147
|
+
}
|
|
148
|
+
next();
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=security.middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.middleware.js","sourceRoot":"","sources":["../../../src/server/middleware/security.middleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Example: Using SecretService with preloading in Container
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const Container_1 = require("../../../../container/Container");
|
|
5
|
+
const secret_service_1 = require("../secret.service");
|
|
6
|
+
// Define your service factories (mock for example)
|
|
7
|
+
const factories = {
|
|
8
|
+
secrets: (secret_service_1.SecretService),
|
|
9
|
+
database: class MockDatabaseService {
|
|
10
|
+
tenantId;
|
|
11
|
+
config;
|
|
12
|
+
constructor(tenantId, config) {
|
|
13
|
+
this.tenantId = tenantId;
|
|
14
|
+
this.config = config;
|
|
15
|
+
}
|
|
16
|
+
async connect() { console.log('Connected to DB'); }
|
|
17
|
+
async query(sql) { return []; }
|
|
18
|
+
},
|
|
19
|
+
api: class MockApiService {
|
|
20
|
+
tenantId;
|
|
21
|
+
config;
|
|
22
|
+
constructor(tenantId, config) {
|
|
23
|
+
this.tenantId = tenantId;
|
|
24
|
+
this.config = config;
|
|
25
|
+
}
|
|
26
|
+
async getUser(userId, apiKey) { return { id: userId }; }
|
|
27
|
+
async processData(apiKey) { return { processed: true }; }
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
// Create container with preloading pattern
|
|
31
|
+
const container = new Container_1.Container(factories, async (preload, meta) => {
|
|
32
|
+
// Create secret service instance
|
|
33
|
+
const secretService = preload.secrets(meta.tenantId, {
|
|
34
|
+
provider: 'FILE', // or 'VAULT', 'ENV'
|
|
35
|
+
location: meta.secretsLocation,
|
|
36
|
+
encryptionKey: meta.encryptionKey,
|
|
37
|
+
vaultConfig: meta.vaultConfig
|
|
38
|
+
});
|
|
39
|
+
// Preload secrets before using them
|
|
40
|
+
await secretService.preload();
|
|
41
|
+
// Now we can use synchronous methods to get secrets
|
|
42
|
+
const dbConnectionString = secretService.getSecretSync('DB_CONNECTION_STRING');
|
|
43
|
+
const jwtSecret = secretService.getSecretSync('JWT_SECRET');
|
|
44
|
+
// Create other services using the preloaded secrets
|
|
45
|
+
const database = preload.database(meta.tenantId, meta.tenantId, {
|
|
46
|
+
connectionString: dbConnectionString
|
|
47
|
+
});
|
|
48
|
+
const api = preload.api(meta.tenantId, meta.tenantId, {
|
|
49
|
+
database,
|
|
50
|
+
jwtSecret
|
|
51
|
+
});
|
|
52
|
+
return {
|
|
53
|
+
secrets: secretService,
|
|
54
|
+
database,
|
|
55
|
+
api
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
// Usage example
|
|
59
|
+
async function processRequest(tenantMeta, userId) {
|
|
60
|
+
await container.bootstrap(tenantMeta, async () => {
|
|
61
|
+
const { api, secrets } = container.context;
|
|
62
|
+
// Secrets are already preloaded, so we can use sync methods
|
|
63
|
+
const apiKey = secrets.getSecretSync('API_KEY');
|
|
64
|
+
// Use services
|
|
65
|
+
const user = await api.getUser(userId, apiKey);
|
|
66
|
+
return user;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
// Example with multiple providers
|
|
70
|
+
async function multiProviderExample() {
|
|
71
|
+
// FILE provider for development
|
|
72
|
+
const devTenant = {
|
|
73
|
+
tenantId: 'dev-tenant',
|
|
74
|
+
secretsLocation: '/secrets/dev.json',
|
|
75
|
+
encryptionKey: 'dev-encryption-key-32chars'
|
|
76
|
+
};
|
|
77
|
+
// VAULT provider for production
|
|
78
|
+
const prodTenant = {
|
|
79
|
+
tenantId: 'prod-tenant',
|
|
80
|
+
secretsLocation: 'production/secrets',
|
|
81
|
+
encryptionKey: 'prod-encryption-key-32chars',
|
|
82
|
+
vaultConfig: {
|
|
83
|
+
endpoint: 'https://vault.company.com',
|
|
84
|
+
token: process.env.VAULT_TOKEN
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
// ENV provider for CI/CD
|
|
88
|
+
const ciTenant = {
|
|
89
|
+
tenantId: 'ci-tenant',
|
|
90
|
+
secretsLocation: 'CI', // Will look for CI_API_KEY, CI_DB_CONNECTION_STRING, etc.
|
|
91
|
+
encryptionKey: 'ci-encryption-key-32chars'
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
// Example with automatic invalidation (FILE provider)
|
|
95
|
+
async function fileWatchingExample() {
|
|
96
|
+
const container = new Container_1.Container(factories, async (preload, meta) => {
|
|
97
|
+
const secretService = preload.secrets(meta.tenantId, {
|
|
98
|
+
provider: 'FILE',
|
|
99
|
+
location: meta.secretsLocation,
|
|
100
|
+
encryptionKey: meta.encryptionKey,
|
|
101
|
+
cacheTTL: 60000 // 1 minute cache
|
|
102
|
+
});
|
|
103
|
+
// Enable automatic reload on file changes
|
|
104
|
+
await secretService.preload();
|
|
105
|
+
// Secrets will automatically reload if the file changes
|
|
106
|
+
return { secrets: secretService };
|
|
107
|
+
});
|
|
108
|
+
// The secret service will watch for file changes and reload automatically
|
|
109
|
+
}
|
|
110
|
+
// Example with batch operations
|
|
111
|
+
async function batchTenantProcessing() {
|
|
112
|
+
const tenants = [
|
|
113
|
+
{ tenantId: 'tenant1', secretsLocation: '/secrets/tenant1.json', encryptionKey: 'key1' },
|
|
114
|
+
{ tenantId: 'tenant2', secretsLocation: '/secrets/tenant2.json', encryptionKey: 'key2' },
|
|
115
|
+
{ tenantId: 'tenant3', secretsLocation: '/secrets/tenant3.json', encryptionKey: 'key3' }
|
|
116
|
+
];
|
|
117
|
+
const results = await container.bootstrapBatch(tenants.map(meta => ({
|
|
118
|
+
metadata: meta,
|
|
119
|
+
fn: async () => {
|
|
120
|
+
const { secrets, api } = container.context;
|
|
121
|
+
// Each tenant has its own preloaded secrets
|
|
122
|
+
const apiKey = secrets.getSecretSync('API_KEY');
|
|
123
|
+
// Process tenant data
|
|
124
|
+
return api.processData(apiKey);
|
|
125
|
+
}
|
|
126
|
+
})), {
|
|
127
|
+
concurrency: 5,
|
|
128
|
+
continueOnError: true,
|
|
129
|
+
onProgress: (completed, total) => {
|
|
130
|
+
console.log(`Processed ${completed}/${total} tenants`);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
// Check results
|
|
134
|
+
for (const result of results) {
|
|
135
|
+
if (result.status === 'success') {
|
|
136
|
+
console.log(`Tenant ${result.metadata.tenantId} processed successfully`);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
console.error(`Tenant ${result.metadata.tenantId} failed:`, result.error);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// Cleanup when done
|
|
144
|
+
async function cleanup() {
|
|
145
|
+
// Dispose all services (including secret watchers)
|
|
146
|
+
await container.disposeAll();
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=container-preload.example.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container-preload.example.js","sourceRoot":"","sources":["../../../../../src/server/services/secrets/examples/container-preload.example.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SecretService, SecretServiceConfig, SecretProvider, VaultConfig } from './secret.service';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SecretService = void 0;
|
|
4
|
+
var secret_service_1 = require("./secret.service");
|
|
5
|
+
Object.defineProperty(exports, "SecretService", { enumerable: true, get: function () { return secret_service_1.SecretService; } });
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/server/services/secrets/index.ts"],"names":[],"mappings":";;;AAAA,mDAAkG;AAAzF,+GAAA,aAAa,OAAA"}
|
|
@@ -5,17 +5,44 @@ export interface VaultConfig {
|
|
|
5
5
|
mount?: string;
|
|
6
6
|
namespace?: string;
|
|
7
7
|
}
|
|
8
|
+
export interface SecretServiceConfig {
|
|
9
|
+
provider: SecretProvider;
|
|
10
|
+
location: string;
|
|
11
|
+
encryptionKey: string;
|
|
12
|
+
vaultConfig?: VaultConfig;
|
|
13
|
+
cacheTTL?: number;
|
|
14
|
+
}
|
|
8
15
|
export declare class SecretService<SecretType> {
|
|
9
16
|
provider: SecretProvider;
|
|
10
17
|
location: string;
|
|
11
18
|
encryptionKey: string;
|
|
12
19
|
vaultConfig?: VaultConfig;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
cacheTTL: number;
|
|
21
|
+
protected preloadedSecrets?: SecretType;
|
|
22
|
+
protected isPreloaded: boolean;
|
|
23
|
+
private fileWatcher?;
|
|
24
|
+
constructor(config: SecretServiceConfig);
|
|
25
|
+
/**
|
|
26
|
+
* Preload secrets asynchronously for synchronous access later
|
|
27
|
+
* This method loads secrets once and stores them in the instance
|
|
28
|
+
*/
|
|
29
|
+
preload(): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Invalidate preloaded secrets and stop file watching
|
|
32
|
+
*/
|
|
33
|
+
invalidate(): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Set up file watching for automatic invalidation
|
|
36
|
+
*/
|
|
37
|
+
private setupFileWatcher;
|
|
38
|
+
/**
|
|
39
|
+
* Load secrets asynchronously with decryption for all providers
|
|
40
|
+
*/
|
|
41
|
+
private loadSecretsAsync;
|
|
42
|
+
private isCacheValid;
|
|
43
|
+
private setCache;
|
|
44
|
+
private getCache;
|
|
45
|
+
loadSecretsFromFileAsync(): Promise<SecretType>;
|
|
19
46
|
loadSecretsFromFile(): SecretType;
|
|
20
47
|
loadSecretsFromGCP(): SecretType;
|
|
21
48
|
loadEncryptionKeyFromGCP(): string;
|
|
@@ -24,9 +51,24 @@ export declare class SecretService<SecretType> {
|
|
|
24
51
|
storeSecretsToVault(secrets: Partial<SecretType>): Promise<void>;
|
|
25
52
|
loadSecrets(): SecretType | Promise<SecretType>;
|
|
26
53
|
loadEncryptionKey(): string;
|
|
54
|
+
getSecretAsync(secretName: keyof SecretType): Promise<string>;
|
|
55
|
+
getSecretJsonAsync<T = any>(secretName: keyof SecretType): Promise<T>;
|
|
27
56
|
getSecret(secretName: keyof SecretType): Promise<string>;
|
|
28
57
|
getSecretJson<T = any>(secretName: keyof SecretType): Promise<T>;
|
|
58
|
+
/**
|
|
59
|
+
* Get a secret synchronously (requires preload() to be called first)
|
|
60
|
+
*/
|
|
29
61
|
getSecretSync(secretName: keyof SecretType): string;
|
|
62
|
+
/**
|
|
63
|
+
* Get a JSON secret synchronously (requires preload() to be called first)
|
|
64
|
+
*/
|
|
30
65
|
getSecretJsonSync<T = any>(secretName: keyof SecretType): T;
|
|
66
|
+
getSecretSyncLegacy(secretName: keyof SecretType): string;
|
|
67
|
+
getSecretJsonSyncLegacy<T = any>(secretName: keyof SecretType): T;
|
|
31
68
|
static clearCache(): void;
|
|
69
|
+
static cleanupExpiredCache(): void;
|
|
70
|
+
/**
|
|
71
|
+
* Clean up resources (file watchers, etc.) when service is no longer needed
|
|
72
|
+
*/
|
|
73
|
+
dispose(): void;
|
|
32
74
|
}
|