podverse-helpers 5.1.26-alpha.0 → 5.1.28-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.
Files changed (55) hide show
  1. package/dist/dtos/account/accountDataExport.d.ts +119 -0
  2. package/dist/dtos/account/accountDataExport.d.ts.map +1 -0
  3. package/dist/dtos/account/accountDataExport.js +2 -0
  4. package/dist/dtos/index.d.ts +1 -0
  5. package/dist/dtos/index.d.ts.map +1 -1
  6. package/dist/dtos/index.js +1 -0
  7. package/dist/index.d.ts +1 -0
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +1 -0
  10. package/dist/lib/accountMembership.d.ts +15 -0
  11. package/dist/lib/accountMembership.d.ts.map +1 -1
  12. package/dist/lib/accountMembership.js +20 -0
  13. package/dist/lib/constants/index.d.ts +3 -0
  14. package/dist/lib/constants/index.d.ts.map +1 -0
  15. package/dist/lib/constants/index.js +18 -0
  16. package/dist/lib/constants/locales.d.ts +10 -0
  17. package/dist/lib/constants/locales.d.ts.map +1 -0
  18. package/dist/lib/constants/locales.js +12 -0
  19. package/dist/lib/constants/serverEnv.d.ts +11 -0
  20. package/dist/lib/constants/serverEnv.d.ts.map +1 -0
  21. package/dist/lib/constants/serverEnv.js +15 -0
  22. package/dist/lib/i18n/timeFormatter.d.ts.map +1 -1
  23. package/dist/lib/i18n/timeFormatter.js +2 -2
  24. package/dist/lib/requests/_request.d.ts.map +1 -1
  25. package/dist/lib/requests/_request.js +7 -4
  26. package/dist/lib/requests/api/_request.d.ts +38 -1
  27. package/dist/lib/requests/api/_request.d.ts.map +1 -1
  28. package/dist/lib/requests/api/_request.js +102 -3
  29. package/dist/lib/requests/api/account/account.d.ts +26 -1
  30. package/dist/lib/requests/api/account/account.d.ts.map +1 -1
  31. package/dist/lib/requests/api/account/account.js +147 -3
  32. package/dist/lib/requests/api/account/follow/account.d.ts +8 -0
  33. package/dist/lib/requests/api/account/follow/account.d.ts.map +1 -1
  34. package/dist/lib/requests/api/account/follow/account.js +39 -0
  35. package/dist/lib/requests/api/profile/profile.d.ts +16 -0
  36. package/dist/lib/requests/api/profile/profile.d.ts.map +1 -0
  37. package/dist/lib/requests/api/profile/profile.js +117 -0
  38. package/dist/lib/requests/api/queryParams.d.ts +14 -0
  39. package/dist/lib/requests/api/queryParams.d.ts.map +1 -1
  40. package/dist/lib/sharableStatus.d.ts +1 -0
  41. package/dist/lib/sharableStatus.d.ts.map +1 -1
  42. package/dist/lib/sharableStatus.js +11 -0
  43. package/dist/lib/validation/configValidation.d.ts +121 -0
  44. package/dist/lib/validation/configValidation.d.ts.map +1 -0
  45. package/dist/lib/validation/configValidation.js +204 -0
  46. package/dist/lib/validation/index.d.ts +2 -0
  47. package/dist/lib/validation/index.d.ts.map +1 -1
  48. package/dist/lib/validation/index.js +2 -0
  49. package/dist/lib/validation/startupValidation.d.ts +116 -0
  50. package/dist/lib/validation/startupValidation.d.ts.map +1 -0
  51. package/dist/lib/validation/startupValidation.js +497 -0
  52. package/dist/lib/validation/url.d.ts +36 -0
  53. package/dist/lib/validation/url.d.ts.map +1 -1
  54. package/dist/lib/validation/url.js +113 -0
  55. 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.26-alpha.0",
3
+ "version": "5.1.28-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
  }