podverse-helpers 5.1.26-alpha.0 → 5.1.27-alpha.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/dist/dtos/account/accountDataExport.d.ts +119 -0
- package/dist/dtos/account/accountDataExport.d.ts.map +1 -0
- package/dist/dtos/account/accountDataExport.js +2 -0
- package/dist/dtos/index.d.ts +1 -0
- package/dist/dtos/index.d.ts.map +1 -1
- package/dist/dtos/index.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/lib/accountMembership.d.ts +15 -0
- package/dist/lib/accountMembership.d.ts.map +1 -1
- package/dist/lib/accountMembership.js +20 -0
- package/dist/lib/constants/index.d.ts +2 -0
- package/dist/lib/constants/index.d.ts.map +1 -0
- package/dist/lib/constants/index.js +17 -0
- package/dist/lib/constants/locales.d.ts +10 -0
- package/dist/lib/constants/locales.d.ts.map +1 -0
- package/dist/lib/constants/locales.js +12 -0
- package/dist/lib/i18n/timeFormatter.d.ts.map +1 -1
- package/dist/lib/i18n/timeFormatter.js +2 -2
- package/dist/lib/requests/_request.d.ts.map +1 -1
- package/dist/lib/requests/_request.js +7 -4
- package/dist/lib/requests/api/_request.d.ts +38 -1
- package/dist/lib/requests/api/_request.d.ts.map +1 -1
- package/dist/lib/requests/api/_request.js +102 -3
- package/dist/lib/requests/api/account/account.d.ts +26 -1
- package/dist/lib/requests/api/account/account.d.ts.map +1 -1
- package/dist/lib/requests/api/account/account.js +147 -3
- package/dist/lib/requests/api/account/follow/account.d.ts +8 -0
- package/dist/lib/requests/api/account/follow/account.d.ts.map +1 -1
- package/dist/lib/requests/api/account/follow/account.js +39 -0
- package/dist/lib/requests/api/profile/profile.d.ts +16 -0
- package/dist/lib/requests/api/profile/profile.d.ts.map +1 -0
- package/dist/lib/requests/api/profile/profile.js +117 -0
- package/dist/lib/requests/api/queryParams.d.ts +14 -0
- package/dist/lib/requests/api/queryParams.d.ts.map +1 -1
- package/dist/lib/sharableStatus.d.ts +1 -0
- package/dist/lib/sharableStatus.d.ts.map +1 -1
- package/dist/lib/sharableStatus.js +11 -0
- package/dist/lib/validation/configValidation.d.ts +121 -0
- package/dist/lib/validation/configValidation.d.ts.map +1 -0
- package/dist/lib/validation/configValidation.js +204 -0
- package/dist/lib/validation/index.d.ts +2 -0
- package/dist/lib/validation/index.d.ts.map +1 -1
- package/dist/lib/validation/index.js +2 -0
- package/dist/lib/validation/startupValidation.d.ts +116 -0
- package/dist/lib/validation/startupValidation.d.ts.map +1 -0
- package/dist/lib/validation/startupValidation.js +497 -0
- package/dist/lib/validation/url.d.ts +36 -0
- package/dist/lib/validation/url.d.ts.map +1 -1
- package/dist/lib/validation/url.js +113 -0
- package/package.json +1 -4
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateRequired = validateRequired;
|
|
4
|
+
exports.validateOptional = validateOptional;
|
|
5
|
+
exports.validateConditionalOptional = validateConditionalOptional;
|
|
6
|
+
exports.getAllAvailableOrListMessage = getAllAvailableOrListMessage;
|
|
7
|
+
exports.displayValidationResultsSilent = displayValidationResultsSilent;
|
|
8
|
+
exports.validateLocale = validateLocale;
|
|
9
|
+
exports.validateSupportedLocalesList = validateSupportedLocalesList;
|
|
10
|
+
exports.validateOptionalNonEmpty = validateOptionalNonEmpty;
|
|
11
|
+
exports.validateBoolean = validateBoolean;
|
|
12
|
+
exports.validateWebProtocol = validateWebProtocol;
|
|
13
|
+
exports.validateLogLevel = validateLogLevel;
|
|
14
|
+
exports.validatePositiveNumber = validatePositiveNumber;
|
|
15
|
+
const locales_1 = require("../constants/locales");
|
|
16
|
+
/**
|
|
17
|
+
* Validates a required environment variable
|
|
18
|
+
* @param varName - The name of the environment variable to validate
|
|
19
|
+
* @param category - The category/group this variable belongs to (for display purposes)
|
|
20
|
+
* @returns ValidationResult indicating whether the variable is set and valid
|
|
21
|
+
*/
|
|
22
|
+
function validateRequired(varName, category) {
|
|
23
|
+
const value = process.env[varName];
|
|
24
|
+
const isSet = value !== undefined && value !== null && typeof value === 'string' && value.trim() !== '';
|
|
25
|
+
// Additional validation for numeric values
|
|
26
|
+
if (isSet && (varName.includes('PORT') || varName.includes('EXPIRATION') || varName.includes('CACHE_TTL'))) {
|
|
27
|
+
const numValue = Number(value);
|
|
28
|
+
if (isNaN(numValue) || numValue <= 0) {
|
|
29
|
+
return {
|
|
30
|
+
name: varName,
|
|
31
|
+
isSet: true,
|
|
32
|
+
isValid: false,
|
|
33
|
+
isRequired: true,
|
|
34
|
+
message: `Invalid number: "${value}"`,
|
|
35
|
+
category
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Additional validation for API_ALLOWED_CORS_ORIGINS (should not be empty)
|
|
40
|
+
if (varName === 'API_ALLOWED_CORS_ORIGINS' && isSet) {
|
|
41
|
+
const origins = value.split(',').map(origin => origin.trim()).filter(origin => origin !== '');
|
|
42
|
+
if (origins.length === 0) {
|
|
43
|
+
return {
|
|
44
|
+
name: varName,
|
|
45
|
+
isSet: true,
|
|
46
|
+
isValid: false,
|
|
47
|
+
isRequired: true,
|
|
48
|
+
message: 'Empty - must contain at least one origin',
|
|
49
|
+
category
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
name: varName,
|
|
55
|
+
isSet,
|
|
56
|
+
isValid: isSet,
|
|
57
|
+
isRequired: true,
|
|
58
|
+
message: isSet ? 'Set' : 'Missing or empty',
|
|
59
|
+
category
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Validates an optional environment variable
|
|
64
|
+
* @param varName - The name of the environment variable to validate
|
|
65
|
+
* @param category - The category/group this variable belongs to (for display purposes)
|
|
66
|
+
* @param defaultMessage - Optional message to display when variable is not set (defaults to "Skipped")
|
|
67
|
+
* @returns ValidationResult indicating whether the variable is set and valid (optional vars are always valid even if not set)
|
|
68
|
+
*/
|
|
69
|
+
function validateOptional(varName, category, defaultMessage = 'Skipped') {
|
|
70
|
+
const value = process.env[varName] || '';
|
|
71
|
+
const isSet = value !== '';
|
|
72
|
+
// Additional validation for numeric values if set
|
|
73
|
+
if (isSet && (varName.includes('PORT') || varName.includes('EXPIRATION') || varName.includes('CACHE_TTL'))) {
|
|
74
|
+
const numValue = Number(value);
|
|
75
|
+
if (isNaN(numValue) || numValue <= 0) {
|
|
76
|
+
return {
|
|
77
|
+
name: varName,
|
|
78
|
+
isSet: true,
|
|
79
|
+
isValid: false,
|
|
80
|
+
isRequired: false,
|
|
81
|
+
message: `Invalid number: "${value}"`,
|
|
82
|
+
category
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
name: varName,
|
|
88
|
+
isSet,
|
|
89
|
+
isValid: true, // Optional vars are always valid (even if not set)
|
|
90
|
+
isRequired: false,
|
|
91
|
+
message: isSet ? 'Set' : defaultMessage,
|
|
92
|
+
category
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Validates a conditionally optional environment variable (only logs if set but not needed)
|
|
97
|
+
* Returns null if variable is not set (so it won't be included in results)
|
|
98
|
+
* @param varName - The name of the environment variable to validate
|
|
99
|
+
* @param category - The category/group this variable belongs to (for display purposes)
|
|
100
|
+
* @returns ValidationResult if variable is set, null otherwise
|
|
101
|
+
*/
|
|
102
|
+
function validateConditionalOptional(varName, category) {
|
|
103
|
+
const value = process.env[varName] || '';
|
|
104
|
+
const isSet = value !== '';
|
|
105
|
+
// Only validate if the variable is set (if not set, don't include in results)
|
|
106
|
+
if (!isSet) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
// Additional validation for numeric values if set
|
|
110
|
+
if (varName.includes('PORT') || varName.includes('EXPIRATION') || varName.includes('CACHE_TTL')) {
|
|
111
|
+
const numValue = Number(value);
|
|
112
|
+
if (isNaN(numValue) || numValue <= 0) {
|
|
113
|
+
return {
|
|
114
|
+
name: varName,
|
|
115
|
+
isSet: true,
|
|
116
|
+
isValid: false,
|
|
117
|
+
isRequired: false,
|
|
118
|
+
message: `Invalid number: "${value}"`,
|
|
119
|
+
category
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
name: varName,
|
|
125
|
+
isSet: true,
|
|
126
|
+
isValid: true,
|
|
127
|
+
isRequired: false,
|
|
128
|
+
message: 'Set (not needed when signup mode is disabled)',
|
|
129
|
+
category
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Generates a validation error message for variables that accept "all-available" or comma-delimited list
|
|
134
|
+
* @param validValues - Array of valid values that can be used in the comma-delimited list
|
|
135
|
+
* @returns Error message string
|
|
136
|
+
*/
|
|
137
|
+
function getAllAvailableOrListMessage(validValues) {
|
|
138
|
+
return `must be "all-available" or comma-delimited list (valid values: ${validValues.join(', ')})`;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Displays validation results silently - only logs failures.
|
|
142
|
+
* This is intended for modules (not apps) that should not show validation output unless there are errors.
|
|
143
|
+
* @param summary - The validation summary to display
|
|
144
|
+
*/
|
|
145
|
+
function displayValidationResultsSilent(summary) {
|
|
146
|
+
// Only log if there are failures
|
|
147
|
+
if (summary.failed === 0 && summary.requiredMissing === 0) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
// Group results by category
|
|
151
|
+
const byCategory = summary.results.reduce((acc, result) => {
|
|
152
|
+
if (!acc[result.category]) {
|
|
153
|
+
acc[result.category] = [];
|
|
154
|
+
}
|
|
155
|
+
acc[result.category].push(result);
|
|
156
|
+
return acc;
|
|
157
|
+
}, {});
|
|
158
|
+
// Display failures by category
|
|
159
|
+
const categories = Object.keys(byCategory).sort();
|
|
160
|
+
for (const category of categories) {
|
|
161
|
+
const failures = byCategory[category].filter(r => !r.isValid);
|
|
162
|
+
if (failures.length > 0) {
|
|
163
|
+
console.error(`[${category}]`);
|
|
164
|
+
for (const result of failures) {
|
|
165
|
+
const requiredText = result.isRequired ? ' (required)' : ' (optional)';
|
|
166
|
+
console.error(` ✗ ${result.name}${requiredText} - ${result.message}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// Display summary of failures
|
|
171
|
+
if (summary.failed > 0) {
|
|
172
|
+
console.error('\n=== Validation Failures ===');
|
|
173
|
+
console.error(`Failed: ${summary.failed}`);
|
|
174
|
+
console.error(`Required Missing: ${summary.requiredMissing}`);
|
|
175
|
+
if (summary.requiredMissing > 0) {
|
|
176
|
+
console.error('\nThe following required environment variables are missing or invalid:');
|
|
177
|
+
summary.results
|
|
178
|
+
.filter(r => r.isRequired && !r.isValid)
|
|
179
|
+
.forEach(r => {
|
|
180
|
+
console.error(` - ${r.name}: ${r.message}`);
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Validates a single locale value against supported locales
|
|
187
|
+
* @param varName - The name of the environment variable to validate
|
|
188
|
+
* @param category - The category/group this variable belongs to (for display purposes)
|
|
189
|
+
* @param isRequired - Whether the variable is required (default: true)
|
|
190
|
+
* @returns ValidationResult indicating whether the locale is valid
|
|
191
|
+
*/
|
|
192
|
+
function validateLocale(varName, category, isRequired = true) {
|
|
193
|
+
const value = process.env[varName] || '';
|
|
194
|
+
const isSet = value !== '';
|
|
195
|
+
if (!isSet) {
|
|
196
|
+
return {
|
|
197
|
+
name: varName,
|
|
198
|
+
isSet: false,
|
|
199
|
+
isValid: !isRequired,
|
|
200
|
+
isRequired,
|
|
201
|
+
message: isRequired
|
|
202
|
+
? `Missing - must be one of: ${locales_1.SUPPORTED_LOCALES.join(', ')}`
|
|
203
|
+
: 'Skipped',
|
|
204
|
+
category
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
const trimmedValue = value.trim();
|
|
208
|
+
if (!locales_1.SUPPORTED_LOCALES.includes(trimmedValue)) {
|
|
209
|
+
return {
|
|
210
|
+
name: varName,
|
|
211
|
+
isSet: true,
|
|
212
|
+
isValid: false,
|
|
213
|
+
isRequired,
|
|
214
|
+
message: `Invalid locale: "${value}". Valid locales: ${locales_1.SUPPORTED_LOCALES.join(', ')}`,
|
|
215
|
+
category
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
return {
|
|
219
|
+
name: varName,
|
|
220
|
+
isSet: true,
|
|
221
|
+
isValid: true,
|
|
222
|
+
isRequired,
|
|
223
|
+
message: `Valid locale: ${trimmedValue}`,
|
|
224
|
+
category
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Validates NEXT_PUBLIC_FEATURES_SUPPORTED_LOCALES
|
|
229
|
+
* Must be "all-available" or comma-delimited list of valid locales
|
|
230
|
+
* @param varName - The name of the environment variable to validate (defaults to 'NEXT_PUBLIC_FEATURES_SUPPORTED_LOCALES')
|
|
231
|
+
* @param category - The category/group this variable belongs to (for display purposes)
|
|
232
|
+
* @returns ValidationResult indicating whether the supported locales list is valid
|
|
233
|
+
*/
|
|
234
|
+
function validateSupportedLocalesList(varName = 'NEXT_PUBLIC_FEATURES_SUPPORTED_LOCALES', category) {
|
|
235
|
+
const value = process.env[varName] || '';
|
|
236
|
+
const isSet = value !== '';
|
|
237
|
+
if (!isSet || value.trim() === '') {
|
|
238
|
+
return {
|
|
239
|
+
name: varName,
|
|
240
|
+
isSet: false,
|
|
241
|
+
isValid: false,
|
|
242
|
+
isRequired: true,
|
|
243
|
+
message: `Missing - ${getAllAvailableOrListMessage(locales_1.SUPPORTED_LOCALES)}`,
|
|
244
|
+
category
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
const trimmedValue = value.trim();
|
|
248
|
+
// Allow "all-available" as a special value
|
|
249
|
+
if (trimmedValue === 'all-available') {
|
|
250
|
+
return {
|
|
251
|
+
name: varName,
|
|
252
|
+
isSet: true,
|
|
253
|
+
isValid: true,
|
|
254
|
+
isRequired: true,
|
|
255
|
+
message: 'Set to "all-available"',
|
|
256
|
+
category
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
// Validate comma-delimited list of locales
|
|
260
|
+
const locales = trimmedValue.split(',').map(l => l.trim()).filter(Boolean);
|
|
261
|
+
if (locales.length === 0) {
|
|
262
|
+
return {
|
|
263
|
+
name: varName,
|
|
264
|
+
isSet: true,
|
|
265
|
+
isValid: false,
|
|
266
|
+
isRequired: true,
|
|
267
|
+
message: `Empty after parsing - ${getAllAvailableOrListMessage(locales_1.SUPPORTED_LOCALES)}`,
|
|
268
|
+
category
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
// Check that all locales are valid
|
|
272
|
+
const invalidLocales = locales.filter(locale => !locales_1.SUPPORTED_LOCALES.includes(locale));
|
|
273
|
+
if (invalidLocales.length > 0) {
|
|
274
|
+
return {
|
|
275
|
+
name: varName,
|
|
276
|
+
isSet: true,
|
|
277
|
+
isValid: false,
|
|
278
|
+
isRequired: true,
|
|
279
|
+
message: `Invalid locale(s): ${invalidLocales.join(', ')}. Valid locales: ${locales_1.SUPPORTED_LOCALES.join(', ')}`,
|
|
280
|
+
category
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
name: varName,
|
|
285
|
+
isSet: true,
|
|
286
|
+
isValid: true,
|
|
287
|
+
isRequired: true,
|
|
288
|
+
message: `Valid locales: ${locales.join(', ')}`,
|
|
289
|
+
category
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Validates an optional environment variable - if set, must not be empty
|
|
294
|
+
* @param varName - The name of the environment variable to validate
|
|
295
|
+
* @param category - The category/group this variable belongs to (for display purposes)
|
|
296
|
+
* @returns ValidationResult indicating whether the variable is valid (optional, but if set must not be empty)
|
|
297
|
+
*/
|
|
298
|
+
function validateOptionalNonEmpty(varName, category) {
|
|
299
|
+
const value = process.env[varName];
|
|
300
|
+
// If not set at all (undefined), it's valid (optional)
|
|
301
|
+
if (value === undefined || value === null) {
|
|
302
|
+
return {
|
|
303
|
+
name: varName,
|
|
304
|
+
isSet: false,
|
|
305
|
+
isValid: true,
|
|
306
|
+
isRequired: false,
|
|
307
|
+
message: 'Skipped',
|
|
308
|
+
category
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
// If set but empty or only whitespace, it's invalid
|
|
312
|
+
if (typeof value === 'string' && value.trim() === '') {
|
|
313
|
+
return {
|
|
314
|
+
name: varName,
|
|
315
|
+
isSet: true,
|
|
316
|
+
isValid: false,
|
|
317
|
+
isRequired: false,
|
|
318
|
+
message: 'Empty - if set, must not be empty',
|
|
319
|
+
category
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
// If set and has a value, it's valid
|
|
323
|
+
return {
|
|
324
|
+
name: varName,
|
|
325
|
+
isSet: true,
|
|
326
|
+
isValid: true,
|
|
327
|
+
isRequired: false,
|
|
328
|
+
message: 'Set',
|
|
329
|
+
category
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Validates a boolean environment variable - must be "true" or "false" if set
|
|
334
|
+
* @param varName - The name of the environment variable to validate
|
|
335
|
+
* @param category - The category/group this variable belongs to (for display purposes)
|
|
336
|
+
* @param isRequired - Whether the variable is required (default: false)
|
|
337
|
+
* @param defaultValue - Optional default value message if not set (e.g., "Use Default (false)")
|
|
338
|
+
* @returns ValidationResult indicating whether the boolean value is valid
|
|
339
|
+
*/
|
|
340
|
+
function validateBoolean(varName, category, isRequired = false, defaultValue) {
|
|
341
|
+
const value = process.env[varName];
|
|
342
|
+
const isSet = value !== undefined && value !== null && typeof value === 'string' && value.trim() !== '';
|
|
343
|
+
if (!isSet) {
|
|
344
|
+
return {
|
|
345
|
+
name: varName,
|
|
346
|
+
isSet: false,
|
|
347
|
+
isValid: !isRequired,
|
|
348
|
+
isRequired,
|
|
349
|
+
message: defaultValue || (isRequired ? 'Missing - must be "true" or "false"' : 'Skipped'),
|
|
350
|
+
category
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
const lowerValue = value.toLowerCase().trim();
|
|
354
|
+
if (lowerValue !== 'true' && lowerValue !== 'false') {
|
|
355
|
+
return {
|
|
356
|
+
name: varName,
|
|
357
|
+
isSet: true,
|
|
358
|
+
isValid: false,
|
|
359
|
+
isRequired,
|
|
360
|
+
message: `Invalid value: "${value}" - must be "true" or "false"`,
|
|
361
|
+
category
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
return {
|
|
365
|
+
name: varName,
|
|
366
|
+
isSet: true,
|
|
367
|
+
isValid: true,
|
|
368
|
+
isRequired,
|
|
369
|
+
message: `Set to ${lowerValue}`,
|
|
370
|
+
category
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Validates WEB_PROTOCOL - must be "http" or "https" if set
|
|
375
|
+
* @param varName - The name of the environment variable to validate (defaults to 'WEB_PROTOCOL')
|
|
376
|
+
* @param category - The category/group this variable belongs to (for display purposes)
|
|
377
|
+
* @param isRequired - Whether the variable is required (default: false)
|
|
378
|
+
* @returns ValidationResult indicating whether the protocol is valid
|
|
379
|
+
*/
|
|
380
|
+
function validateWebProtocol(varName = 'WEB_PROTOCOL', category, isRequired = false) {
|
|
381
|
+
const value = process.env[varName];
|
|
382
|
+
const isSet = value !== undefined && value !== null && typeof value === 'string' && value.trim() !== '';
|
|
383
|
+
if (!isSet) {
|
|
384
|
+
return {
|
|
385
|
+
name: varName,
|
|
386
|
+
isSet: false,
|
|
387
|
+
isValid: !isRequired,
|
|
388
|
+
isRequired,
|
|
389
|
+
message: isRequired ? 'Missing - must be "http" or "https"' : 'Skipped',
|
|
390
|
+
category
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
const lowerValue = value.toLowerCase().trim();
|
|
394
|
+
if (lowerValue !== 'http' && lowerValue !== 'https') {
|
|
395
|
+
return {
|
|
396
|
+
name: varName,
|
|
397
|
+
isSet: true,
|
|
398
|
+
isValid: false,
|
|
399
|
+
isRequired,
|
|
400
|
+
message: `Invalid protocol: "${value}" - must be "http" or "https"`,
|
|
401
|
+
category
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
return {
|
|
405
|
+
name: varName,
|
|
406
|
+
isSet: true,
|
|
407
|
+
isValid: true,
|
|
408
|
+
isRequired,
|
|
409
|
+
message: `Set to ${lowerValue}`,
|
|
410
|
+
category
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Validates LOG_LEVEL - must be a valid winston log level
|
|
415
|
+
* @param varName - The name of the environment variable to validate (defaults to 'LOG_LEVEL')
|
|
416
|
+
* @param category - The category/group this variable belongs to (for display purposes)
|
|
417
|
+
* @param isRequired - Whether the variable is required (default: true)
|
|
418
|
+
* @param validLevels - Optional array of valid log levels (defaults to winston levels)
|
|
419
|
+
* @returns ValidationResult indicating whether the log level is valid
|
|
420
|
+
*/
|
|
421
|
+
function validateLogLevel(varName = 'LOG_LEVEL', category, isRequired = true, validLevels = ['error', 'warn', 'info', 'debug', 'verbose', 'silly', 'silent']) {
|
|
422
|
+
const value = process.env[varName];
|
|
423
|
+
const isSet = value !== undefined && value !== null && typeof value === 'string' && value.trim() !== '';
|
|
424
|
+
if (!isSet) {
|
|
425
|
+
return {
|
|
426
|
+
name: varName,
|
|
427
|
+
isSet: false,
|
|
428
|
+
isValid: !isRequired,
|
|
429
|
+
isRequired,
|
|
430
|
+
message: isRequired ? `Missing or empty - must be a valid log level (${validLevels.join(', ')})` : 'Skipped',
|
|
431
|
+
category
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
const lowerValue = value.toLowerCase().trim();
|
|
435
|
+
if (!validLevels.includes(lowerValue)) {
|
|
436
|
+
return {
|
|
437
|
+
name: varName,
|
|
438
|
+
isSet: true,
|
|
439
|
+
isValid: false,
|
|
440
|
+
isRequired,
|
|
441
|
+
message: `Invalid log level: "${value}" - must be one of: ${validLevels.join(', ')}`,
|
|
442
|
+
category
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
return {
|
|
446
|
+
name: varName,
|
|
447
|
+
isSet: true,
|
|
448
|
+
isValid: true,
|
|
449
|
+
isRequired,
|
|
450
|
+
message: `Valid log level: ${lowerValue}`,
|
|
451
|
+
category
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Validates a positive number environment variable
|
|
456
|
+
* @param varName - The name of the environment variable to validate
|
|
457
|
+
* @param category - The category/group this variable belongs to (for display purposes)
|
|
458
|
+
* @param isRequired - Whether the variable is required (default: false)
|
|
459
|
+
* @param min - Optional minimum value (default: 1)
|
|
460
|
+
* @param max - Optional maximum value (no limit if not specified)
|
|
461
|
+
* @returns ValidationResult indicating whether the number is valid
|
|
462
|
+
*/
|
|
463
|
+
function validatePositiveNumber(varName, category, isRequired = false, min = 1, max) {
|
|
464
|
+
const value = process.env[varName];
|
|
465
|
+
const isSet = value !== undefined && value !== null && typeof value === 'string' && value.trim() !== '';
|
|
466
|
+
if (!isSet) {
|
|
467
|
+
return {
|
|
468
|
+
name: varName,
|
|
469
|
+
isSet: false,
|
|
470
|
+
isValid: !isRequired,
|
|
471
|
+
isRequired,
|
|
472
|
+
message: isRequired ? `Missing - must be a positive number${min > 1 ? ` (min: ${min})` : ''}${max ? ` (max: ${max})` : ''}` : 'Skipped',
|
|
473
|
+
category
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
const numValue = Number(value);
|
|
477
|
+
if (isNaN(numValue) || numValue < min || (max !== undefined && numValue > max)) {
|
|
478
|
+
const rangeMsg = max !== undefined ? ` between ${min} and ${max}` : ` >= ${min}`;
|
|
479
|
+
return {
|
|
480
|
+
name: varName,
|
|
481
|
+
isSet: true,
|
|
482
|
+
isValid: false,
|
|
483
|
+
isRequired,
|
|
484
|
+
message: `Invalid number: "${value}" - must be a positive number${rangeMsg}`,
|
|
485
|
+
category
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
const rangeMsg = max !== undefined ? ` (${min}-${max})` : ` (min: ${min})`;
|
|
489
|
+
return {
|
|
490
|
+
name: varName,
|
|
491
|
+
isSet: true,
|
|
492
|
+
isValid: true,
|
|
493
|
+
isRequired,
|
|
494
|
+
message: `Valid number: ${numValue}${rangeMsg}`,
|
|
495
|
+
category
|
|
496
|
+
};
|
|
497
|
+
}
|
|
@@ -15,4 +15,40 @@ export declare function validateHttpOrHttpsUrl(url?: string | null): {
|
|
|
15
15
|
isValid: boolean;
|
|
16
16
|
error?: string;
|
|
17
17
|
};
|
|
18
|
+
/**
|
|
19
|
+
* Checks if an IP address is in a private IP range.
|
|
20
|
+
* Useful for SSRF protection in any application.
|
|
21
|
+
*
|
|
22
|
+
* @param ip - The IP address to check (IPv4 format)
|
|
23
|
+
* @returns true if the IP is in a private range, false otherwise
|
|
24
|
+
*/
|
|
25
|
+
export declare function isPrivateIP(ip: string): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Checks if a hostname is a localhost variant.
|
|
28
|
+
* Useful for SSRF protection in any application.
|
|
29
|
+
*
|
|
30
|
+
* @param hostname - The hostname to check
|
|
31
|
+
* @returns true if the hostname is a localhost variant, false otherwise
|
|
32
|
+
*/
|
|
33
|
+
export declare function isLocalhost(hostname: string): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Validates a URL for SSRF (Server-Side Request Forgery) vulnerabilities.
|
|
36
|
+
* Checks for private IPs, localhost, and dangerous protocols.
|
|
37
|
+
* Useful for any application that needs to validate external URLs.
|
|
38
|
+
*
|
|
39
|
+
* @param url - The URL to validate
|
|
40
|
+
* @param options - Optional configuration
|
|
41
|
+
* @param options.allowPrivateIPs - If true, allows private IP addresses (default: false)
|
|
42
|
+
* @param options.allowLocalhost - If true, allows localhost URLs (default: false)
|
|
43
|
+
* @param options.allowedProtocols - Array of allowed protocols (default: ['http:', 'https:'])
|
|
44
|
+
* @returns Object with isValid boolean and optional error message
|
|
45
|
+
*/
|
|
46
|
+
export declare function validateUrlForSSRF(url: string | null, options?: {
|
|
47
|
+
allowPrivateIPs?: boolean;
|
|
48
|
+
allowLocalhost?: boolean;
|
|
49
|
+
allowedProtocols?: string[];
|
|
50
|
+
}): {
|
|
51
|
+
isValid: boolean;
|
|
52
|
+
error?: string;
|
|
53
|
+
};
|
|
18
54
|
//# sourceMappingURL=url.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../../../src/lib/validation/url.ts"],"names":[],"mappings":"AAAA,wBAAgB,cAAc,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAM/D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAyB1F;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAsBhG"}
|
|
1
|
+
{"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../../../src/lib/validation/url.ts"],"names":[],"mappings":"AAAA,wBAAgB,cAAc,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAM/D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAyB1F;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAsBhG;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CA4B/C;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAarD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,OAAO,GAAE;IACP,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB,GACL;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CA2DtC"}
|
|
@@ -3,6 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.isValidHttpUrl = isValidHttpUrl;
|
|
4
4
|
exports.validateHttpsUrl = validateHttpsUrl;
|
|
5
5
|
exports.validateHttpOrHttpsUrl = validateHttpOrHttpsUrl;
|
|
6
|
+
exports.isPrivateIP = isPrivateIP;
|
|
7
|
+
exports.isLocalhost = isLocalhost;
|
|
8
|
+
exports.validateUrlForSSRF = validateUrlForSSRF;
|
|
6
9
|
function isValidHttpUrl(url) {
|
|
7
10
|
if (!url) {
|
|
8
11
|
return null;
|
|
@@ -59,3 +62,113 @@ function validateHttpOrHttpsUrl(url) {
|
|
|
59
62
|
return { isValid: false, error: 'Invalid URL format' };
|
|
60
63
|
}
|
|
61
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Checks if an IP address is in a private IP range.
|
|
67
|
+
* Useful for SSRF protection in any application.
|
|
68
|
+
*
|
|
69
|
+
* @param ip - The IP address to check (IPv4 format)
|
|
70
|
+
* @returns true if the IP is in a private range, false otherwise
|
|
71
|
+
*/
|
|
72
|
+
function isPrivateIP(ip) {
|
|
73
|
+
// IPv4 private ranges
|
|
74
|
+
// 10.0.0.0/8
|
|
75
|
+
if (/^10\./.test(ip)) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
// 172.16.0.0/12 (172.16.0.0 - 172.31.255.255)
|
|
79
|
+
if (/^172\.(1[6-9]|2[0-9]|3[0-1])\./.test(ip)) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
// 192.168.0.0/16
|
|
83
|
+
if (/^192\.168\./.test(ip)) {
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
// 127.0.0.0/8 (localhost)
|
|
87
|
+
if (/^127\./.test(ip)) {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
// 169.254.0.0/16 (link-local)
|
|
91
|
+
if (/^169\.254\./.test(ip)) {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Checks if a hostname is a localhost variant.
|
|
98
|
+
* Useful for SSRF protection in any application.
|
|
99
|
+
*
|
|
100
|
+
* @param hostname - The hostname to check
|
|
101
|
+
* @returns true if the hostname is a localhost variant, false otherwise
|
|
102
|
+
*/
|
|
103
|
+
function isLocalhost(hostname) {
|
|
104
|
+
const lower = hostname.toLowerCase();
|
|
105
|
+
return (lower === 'localhost' ||
|
|
106
|
+
lower === '127.0.0.1' ||
|
|
107
|
+
lower === '::1' ||
|
|
108
|
+
lower.startsWith('127.') ||
|
|
109
|
+
lower.startsWith('0.0.0.0') ||
|
|
110
|
+
lower === '[::1]' ||
|
|
111
|
+
lower.startsWith('[::1]') ||
|
|
112
|
+
lower.startsWith('fe80:') ||
|
|
113
|
+
lower.startsWith('[fe80:'));
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Validates a URL for SSRF (Server-Side Request Forgery) vulnerabilities.
|
|
117
|
+
* Checks for private IPs, localhost, and dangerous protocols.
|
|
118
|
+
* Useful for any application that needs to validate external URLs.
|
|
119
|
+
*
|
|
120
|
+
* @param url - The URL to validate
|
|
121
|
+
* @param options - Optional configuration
|
|
122
|
+
* @param options.allowPrivateIPs - If true, allows private IP addresses (default: false)
|
|
123
|
+
* @param options.allowLocalhost - If true, allows localhost URLs (default: false)
|
|
124
|
+
* @param options.allowedProtocols - Array of allowed protocols (default: ['http:', 'https:'])
|
|
125
|
+
* @returns Object with isValid boolean and optional error message
|
|
126
|
+
*/
|
|
127
|
+
function validateUrlForSSRF(url, options = {}) {
|
|
128
|
+
if (!url) {
|
|
129
|
+
return { isValid: false, error: 'URL is required' };
|
|
130
|
+
}
|
|
131
|
+
const { allowPrivateIPs = false, allowLocalhost = false, allowedProtocols = ['http:', 'https:'], } = options;
|
|
132
|
+
try {
|
|
133
|
+
const parsedUrl = new URL(url);
|
|
134
|
+
// Check protocol
|
|
135
|
+
if (!allowedProtocols.includes(parsedUrl.protocol)) {
|
|
136
|
+
return { isValid: false, error: `Protocol ${parsedUrl.protocol} is not allowed` };
|
|
137
|
+
}
|
|
138
|
+
// Block file:// and data: protocols by default
|
|
139
|
+
if (parsedUrl.protocol === 'file:' || parsedUrl.protocol === 'data:') {
|
|
140
|
+
return { isValid: false, error: 'Invalid protocol' };
|
|
141
|
+
}
|
|
142
|
+
// Check for localhost variants
|
|
143
|
+
if (!allowLocalhost && isLocalhost(parsedUrl.hostname)) {
|
|
144
|
+
return { isValid: false, error: 'Localhost URLs are not allowed' };
|
|
145
|
+
}
|
|
146
|
+
// Check for private IP addresses
|
|
147
|
+
if (!allowPrivateIPs) {
|
|
148
|
+
// Check if hostname is an IP address
|
|
149
|
+
const ipRegex = /^(\d{1,3}\.){3}\d{1,3}$/;
|
|
150
|
+
if (ipRegex.test(parsedUrl.hostname)) {
|
|
151
|
+
if (isPrivateIP(parsedUrl.hostname)) {
|
|
152
|
+
return { isValid: false, error: 'Private IP addresses are not allowed' };
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// Also check hostname string directly (in case it's not a valid IP format but still private)
|
|
156
|
+
if (isPrivateIP(parsedUrl.hostname)) {
|
|
157
|
+
return { isValid: false, error: 'Private IP addresses are not allowed' };
|
|
158
|
+
}
|
|
159
|
+
// Check for IPv6 localhost addresses
|
|
160
|
+
if (parsedUrl.hostname.includes(':')) {
|
|
161
|
+
if (parsedUrl.hostname.startsWith('::1') ||
|
|
162
|
+
parsedUrl.hostname.startsWith('[::1]') ||
|
|
163
|
+
parsedUrl.hostname.startsWith('fe80:') ||
|
|
164
|
+
parsedUrl.hostname.startsWith('[fe80:')) {
|
|
165
|
+
return { isValid: false, error: 'Localhost IPv6 addresses are not allowed' };
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return { isValid: true };
|
|
170
|
+
}
|
|
171
|
+
catch (_a) {
|
|
172
|
+
return { isValid: false, error: 'Invalid URL format' };
|
|
173
|
+
}
|
|
174
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "podverse-helpers",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.27-alpha.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -37,8 +37,5 @@
|
|
|
37
37
|
"ts-node": "^10.9.2",
|
|
38
38
|
"typescript": "^5.9.2",
|
|
39
39
|
"typescript-eslint": "^8.44.0"
|
|
40
|
-
},
|
|
41
|
-
"overrides": {
|
|
42
|
-
"diff": "^8.0.3"
|
|
43
40
|
}
|
|
44
41
|
}
|