nextjs-secure 0.2.0 → 0.3.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 +115 -0
- package/dist/headers.cjs +277 -7
- package/dist/headers.cjs.map +1 -1
- package/dist/headers.d.cts +162 -25
- package/dist/headers.d.ts +162 -25
- package/dist/headers.js +267 -6
- package/dist/headers.js.map +1 -1
- package/dist/index.cjs +280 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +271 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { D as Duration, N as NextRequest } from './memory-Dauy-IH3.cjs';
|
|
2
2
|
export { E as ErrorResponse, k as MemoryStore, M as MemoryStoreOptions, q as Middleware, n as RateLimitAlgorithm, f as RateLimitConfig, s as RateLimitIdentifier, b as RateLimitInfo, a as RateLimitStore, j as RedisStoreOptions, o as SecureContext, p as SecureHandler, U as UpstashStoreOptions, d as checkRateLimit, e as clearAllRateLimits, l as createMemoryStore, c as createRateLimiter, m as getGlobalMemoryStore, g as getRateLimitStatus, r as resetRateLimit, w as withRateLimit } from './memory-Dauy-IH3.cjs';
|
|
3
3
|
export { CSRFConfig, CSRFCookieOptions, CSRFToken, createToken as createCSRFToken, generateCSRF, tokensMatch, validateCSRF, verifyToken as verifyCSRFToken, withCSRF } from './csrf.cjs';
|
|
4
|
+
export { ContentSecurityPolicy, PRESET_API, PRESET_RELAXED, PRESET_STRICT, PermissionsPolicy, ReferrerPolicy, SecurityHeadersConfig, SecurityHeadersPreset, StrictTransportSecurity, XFrameOptions, buildCSP, buildHSTS, buildPermissionsPolicy, createSecurityHeaders, createSecurityHeadersObject, getPreset, withSecurityHeaders } from './headers.cjs';
|
|
4
5
|
import 'next/server';
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -302,6 +303,6 @@ declare function getGeoInfo(request: NextRequest): {
|
|
|
302
303
|
/**
|
|
303
304
|
* Package version
|
|
304
305
|
*/
|
|
305
|
-
declare const VERSION = "0.
|
|
306
|
+
declare const VERSION = "0.3.0";
|
|
306
307
|
|
|
307
308
|
export { AuthenticationError, AuthorizationError, ConfigurationError, CsrfError, Duration, NextRequest, RateLimitError, SecureError, VERSION, ValidationError, anonymizeIp, formatDuration, getClientIp, getGeoInfo, isLocalhost, isPrivateIp, isSecureError, isValidIp, normalizeIp, nowInMs, nowInSeconds, parseDuration, sleep, toSecureError };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { D as Duration, N as NextRequest } from './memory-Dauy-IH3.js';
|
|
2
2
|
export { E as ErrorResponse, k as MemoryStore, M as MemoryStoreOptions, q as Middleware, n as RateLimitAlgorithm, f as RateLimitConfig, s as RateLimitIdentifier, b as RateLimitInfo, a as RateLimitStore, j as RedisStoreOptions, o as SecureContext, p as SecureHandler, U as UpstashStoreOptions, d as checkRateLimit, e as clearAllRateLimits, l as createMemoryStore, c as createRateLimiter, m as getGlobalMemoryStore, g as getRateLimitStatus, r as resetRateLimit, w as withRateLimit } from './memory-Dauy-IH3.js';
|
|
3
3
|
export { CSRFConfig, CSRFCookieOptions, CSRFToken, createToken as createCSRFToken, generateCSRF, tokensMatch, validateCSRF, verifyToken as verifyCSRFToken, withCSRF } from './csrf.js';
|
|
4
|
+
export { ContentSecurityPolicy, PRESET_API, PRESET_RELAXED, PRESET_STRICT, PermissionsPolicy, ReferrerPolicy, SecurityHeadersConfig, SecurityHeadersPreset, StrictTransportSecurity, XFrameOptions, buildCSP, buildHSTS, buildPermissionsPolicy, createSecurityHeaders, createSecurityHeadersObject, getPreset, withSecurityHeaders } from './headers.js';
|
|
4
5
|
import 'next/server';
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -302,6 +303,6 @@ declare function getGeoInfo(request: NextRequest): {
|
|
|
302
303
|
/**
|
|
303
304
|
* Package version
|
|
304
305
|
*/
|
|
305
|
-
declare const VERSION = "0.
|
|
306
|
+
declare const VERSION = "0.3.0";
|
|
306
307
|
|
|
307
308
|
export { AuthenticationError, AuthorizationError, ConfigurationError, CsrfError, Duration, NextRequest, RateLimitError, SecureError, VERSION, ValidationError, anonymizeIp, formatDuration, getClientIp, getGeoInfo, isLocalhost, isPrivateIp, isSecureError, isValidIp, normalizeIp, nowInMs, nowInSeconds, parseDuration, sleep, toSecureError };
|
package/dist/index.js
CHANGED
|
@@ -1176,9 +1176,278 @@ async function validateCSRF(req, config = {}) {
|
|
|
1176
1176
|
return { valid: true };
|
|
1177
1177
|
}
|
|
1178
1178
|
|
|
1179
|
+
// src/middleware/headers/builder.ts
|
|
1180
|
+
function buildCSP(policy) {
|
|
1181
|
+
const directives = [];
|
|
1182
|
+
const directiveMap = {
|
|
1183
|
+
defaultSrc: "default-src",
|
|
1184
|
+
scriptSrc: "script-src",
|
|
1185
|
+
styleSrc: "style-src",
|
|
1186
|
+
imgSrc: "img-src",
|
|
1187
|
+
fontSrc: "font-src",
|
|
1188
|
+
connectSrc: "connect-src",
|
|
1189
|
+
mediaSrc: "media-src",
|
|
1190
|
+
objectSrc: "object-src",
|
|
1191
|
+
frameSrc: "frame-src",
|
|
1192
|
+
childSrc: "child-src",
|
|
1193
|
+
workerSrc: "worker-src",
|
|
1194
|
+
frameAncestors: "frame-ancestors",
|
|
1195
|
+
formAction: "form-action",
|
|
1196
|
+
baseUri: "base-uri",
|
|
1197
|
+
manifestSrc: "manifest-src",
|
|
1198
|
+
reportUri: "report-uri",
|
|
1199
|
+
reportTo: "report-to"
|
|
1200
|
+
};
|
|
1201
|
+
for (const [key, directive] of Object.entries(directiveMap)) {
|
|
1202
|
+
const value = policy[key];
|
|
1203
|
+
if (value !== void 0 && value !== false) {
|
|
1204
|
+
if (Array.isArray(value)) {
|
|
1205
|
+
directives.push(`${directive} ${value.join(" ")}`);
|
|
1206
|
+
} else if (typeof value === "string") {
|
|
1207
|
+
directives.push(`${directive} ${value}`);
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
if (policy.upgradeInsecureRequests) {
|
|
1212
|
+
directives.push("upgrade-insecure-requests");
|
|
1213
|
+
}
|
|
1214
|
+
if (policy.blockAllMixedContent) {
|
|
1215
|
+
directives.push("block-all-mixed-content");
|
|
1216
|
+
}
|
|
1217
|
+
return directives.join("; ");
|
|
1218
|
+
}
|
|
1219
|
+
function buildHSTS(config) {
|
|
1220
|
+
let value = `max-age=${config.maxAge}`;
|
|
1221
|
+
if (config.includeSubDomains) {
|
|
1222
|
+
value += "; includeSubDomains";
|
|
1223
|
+
}
|
|
1224
|
+
if (config.preload) {
|
|
1225
|
+
value += "; preload";
|
|
1226
|
+
}
|
|
1227
|
+
return value;
|
|
1228
|
+
}
|
|
1229
|
+
function buildPermissionsPolicy(policy) {
|
|
1230
|
+
const directives = [];
|
|
1231
|
+
const featureMap = {
|
|
1232
|
+
accelerometer: "accelerometer",
|
|
1233
|
+
ambientLightSensor: "ambient-light-sensor",
|
|
1234
|
+
autoplay: "autoplay",
|
|
1235
|
+
battery: "battery",
|
|
1236
|
+
camera: "camera",
|
|
1237
|
+
displayCapture: "display-capture",
|
|
1238
|
+
documentDomain: "document-domain",
|
|
1239
|
+
encryptedMedia: "encrypted-media",
|
|
1240
|
+
fullscreen: "fullscreen",
|
|
1241
|
+
geolocation: "geolocation",
|
|
1242
|
+
gyroscope: "gyroscope",
|
|
1243
|
+
magnetometer: "magnetometer",
|
|
1244
|
+
microphone: "microphone",
|
|
1245
|
+
midi: "midi",
|
|
1246
|
+
payment: "payment",
|
|
1247
|
+
pictureInPicture: "picture-in-picture",
|
|
1248
|
+
publicKeyCredentialsGet: "publickey-credentials-get",
|
|
1249
|
+
screenWakeLock: "screen-wake-lock",
|
|
1250
|
+
syncXhr: "sync-xhr",
|
|
1251
|
+
usb: "usb",
|
|
1252
|
+
webShare: "web-share",
|
|
1253
|
+
xrSpatialTracking: "xr-spatial-tracking"
|
|
1254
|
+
};
|
|
1255
|
+
for (const [key, feature] of Object.entries(featureMap)) {
|
|
1256
|
+
const origins = policy[key];
|
|
1257
|
+
if (origins !== void 0) {
|
|
1258
|
+
if (origins.length === 0) {
|
|
1259
|
+
directives.push(`${feature}=()`);
|
|
1260
|
+
} else {
|
|
1261
|
+
const formatted = origins.map((o) => o === "self" ? "self" : `"${o}"`).join(" ");
|
|
1262
|
+
directives.push(`${feature}=(${formatted})`);
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
return directives.join(", ");
|
|
1267
|
+
}
|
|
1268
|
+
var PRESET_STRICT = {
|
|
1269
|
+
contentSecurityPolicy: {
|
|
1270
|
+
defaultSrc: ["'self'"],
|
|
1271
|
+
scriptSrc: ["'self'"],
|
|
1272
|
+
styleSrc: ["'self'"],
|
|
1273
|
+
imgSrc: ["'self'", "data:"],
|
|
1274
|
+
fontSrc: ["'self'"],
|
|
1275
|
+
objectSrc: ["'none'"],
|
|
1276
|
+
frameAncestors: ["'none'"],
|
|
1277
|
+
formAction: ["'self'"],
|
|
1278
|
+
baseUri: ["'self'"],
|
|
1279
|
+
upgradeInsecureRequests: true
|
|
1280
|
+
},
|
|
1281
|
+
strictTransportSecurity: {
|
|
1282
|
+
maxAge: 31536e3,
|
|
1283
|
+
// 1 year
|
|
1284
|
+
includeSubDomains: true,
|
|
1285
|
+
preload: true
|
|
1286
|
+
},
|
|
1287
|
+
xFrameOptions: "DENY",
|
|
1288
|
+
xContentTypeOptions: true,
|
|
1289
|
+
xDnsPrefetchControl: "off",
|
|
1290
|
+
xDownloadOptions: true,
|
|
1291
|
+
xPermittedCrossDomainPolicies: "none",
|
|
1292
|
+
referrerPolicy: "strict-origin-when-cross-origin",
|
|
1293
|
+
crossOriginOpenerPolicy: "same-origin",
|
|
1294
|
+
crossOriginEmbedderPolicy: "require-corp",
|
|
1295
|
+
crossOriginResourcePolicy: "same-origin",
|
|
1296
|
+
permissionsPolicy: {
|
|
1297
|
+
camera: [],
|
|
1298
|
+
microphone: [],
|
|
1299
|
+
geolocation: [],
|
|
1300
|
+
payment: []
|
|
1301
|
+
},
|
|
1302
|
+
originAgentCluster: true
|
|
1303
|
+
};
|
|
1304
|
+
var PRESET_RELAXED = {
|
|
1305
|
+
contentSecurityPolicy: {
|
|
1306
|
+
defaultSrc: ["'self'"],
|
|
1307
|
+
scriptSrc: ["'self'", "'unsafe-inline'", "'unsafe-eval'"],
|
|
1308
|
+
styleSrc: ["'self'", "'unsafe-inline'"],
|
|
1309
|
+
imgSrc: ["'self'", "data:", "blob:", "https:"],
|
|
1310
|
+
fontSrc: ["'self'", "https:", "data:"],
|
|
1311
|
+
connectSrc: ["'self'", "https:", "wss:"],
|
|
1312
|
+
frameSrc: ["'self'"]
|
|
1313
|
+
},
|
|
1314
|
+
strictTransportSecurity: {
|
|
1315
|
+
maxAge: 86400,
|
|
1316
|
+
// 1 day
|
|
1317
|
+
includeSubDomains: false
|
|
1318
|
+
},
|
|
1319
|
+
xFrameOptions: "SAMEORIGIN",
|
|
1320
|
+
xContentTypeOptions: true,
|
|
1321
|
+
referrerPolicy: "no-referrer-when-downgrade"
|
|
1322
|
+
};
|
|
1323
|
+
var PRESET_API = {
|
|
1324
|
+
contentSecurityPolicy: {
|
|
1325
|
+
defaultSrc: ["'none'"],
|
|
1326
|
+
frameAncestors: ["'none'"]
|
|
1327
|
+
},
|
|
1328
|
+
strictTransportSecurity: {
|
|
1329
|
+
maxAge: 31536e3,
|
|
1330
|
+
includeSubDomains: true
|
|
1331
|
+
},
|
|
1332
|
+
xFrameOptions: "DENY",
|
|
1333
|
+
xContentTypeOptions: true,
|
|
1334
|
+
referrerPolicy: "no-referrer",
|
|
1335
|
+
crossOriginResourcePolicy: "same-origin"
|
|
1336
|
+
};
|
|
1337
|
+
function getPreset(name) {
|
|
1338
|
+
switch (name) {
|
|
1339
|
+
case "strict":
|
|
1340
|
+
return PRESET_STRICT;
|
|
1341
|
+
case "relaxed":
|
|
1342
|
+
return PRESET_RELAXED;
|
|
1343
|
+
case "api":
|
|
1344
|
+
return PRESET_API;
|
|
1345
|
+
default:
|
|
1346
|
+
return PRESET_STRICT;
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
function buildHeaders(config) {
|
|
1350
|
+
const headers = new Headers();
|
|
1351
|
+
if (config.contentSecurityPolicy) {
|
|
1352
|
+
const csp = buildCSP(config.contentSecurityPolicy);
|
|
1353
|
+
if (csp) headers.set("Content-Security-Policy", csp);
|
|
1354
|
+
}
|
|
1355
|
+
if (config.strictTransportSecurity) {
|
|
1356
|
+
headers.set("Strict-Transport-Security", buildHSTS(config.strictTransportSecurity));
|
|
1357
|
+
}
|
|
1358
|
+
if (config.xFrameOptions) {
|
|
1359
|
+
headers.set("X-Frame-Options", config.xFrameOptions);
|
|
1360
|
+
}
|
|
1361
|
+
if (config.xContentTypeOptions) {
|
|
1362
|
+
headers.set("X-Content-Type-Options", "nosniff");
|
|
1363
|
+
}
|
|
1364
|
+
if (config.xDnsPrefetchControl) {
|
|
1365
|
+
headers.set("X-DNS-Prefetch-Control", config.xDnsPrefetchControl);
|
|
1366
|
+
}
|
|
1367
|
+
if (config.xDownloadOptions) {
|
|
1368
|
+
headers.set("X-Download-Options", "noopen");
|
|
1369
|
+
}
|
|
1370
|
+
if (config.xPermittedCrossDomainPolicies) {
|
|
1371
|
+
headers.set("X-Permitted-Cross-Domain-Policies", config.xPermittedCrossDomainPolicies);
|
|
1372
|
+
}
|
|
1373
|
+
if (config.referrerPolicy) {
|
|
1374
|
+
const value = Array.isArray(config.referrerPolicy) ? config.referrerPolicy.join(", ") : config.referrerPolicy;
|
|
1375
|
+
headers.set("Referrer-Policy", value);
|
|
1376
|
+
}
|
|
1377
|
+
if (config.crossOriginOpenerPolicy) {
|
|
1378
|
+
headers.set("Cross-Origin-Opener-Policy", config.crossOriginOpenerPolicy);
|
|
1379
|
+
}
|
|
1380
|
+
if (config.crossOriginEmbedderPolicy) {
|
|
1381
|
+
headers.set("Cross-Origin-Embedder-Policy", config.crossOriginEmbedderPolicy);
|
|
1382
|
+
}
|
|
1383
|
+
if (config.crossOriginResourcePolicy) {
|
|
1384
|
+
headers.set("Cross-Origin-Resource-Policy", config.crossOriginResourcePolicy);
|
|
1385
|
+
}
|
|
1386
|
+
if (config.permissionsPolicy) {
|
|
1387
|
+
const pp = buildPermissionsPolicy(config.permissionsPolicy);
|
|
1388
|
+
if (pp) headers.set("Permissions-Policy", pp);
|
|
1389
|
+
}
|
|
1390
|
+
if (config.originAgentCluster) {
|
|
1391
|
+
headers.set("Origin-Agent-Cluster", "?1");
|
|
1392
|
+
}
|
|
1393
|
+
return headers;
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
// src/middleware/headers/middleware.ts
|
|
1397
|
+
function mergeConfigs(base, custom) {
|
|
1398
|
+
return {
|
|
1399
|
+
...base,
|
|
1400
|
+
...custom,
|
|
1401
|
+
// Deep merge CSP if both exist
|
|
1402
|
+
contentSecurityPolicy: custom.contentSecurityPolicy === false ? false : custom.contentSecurityPolicy ? base.contentSecurityPolicy ? { ...base.contentSecurityPolicy, ...custom.contentSecurityPolicy } : custom.contentSecurityPolicy : base.contentSecurityPolicy,
|
|
1403
|
+
// Deep merge HSTS if both exist
|
|
1404
|
+
strictTransportSecurity: custom.strictTransportSecurity === false ? false : custom.strictTransportSecurity ? base.strictTransportSecurity ? { ...base.strictTransportSecurity, ...custom.strictTransportSecurity } : custom.strictTransportSecurity : base.strictTransportSecurity,
|
|
1405
|
+
// Deep merge Permissions-Policy if both exist
|
|
1406
|
+
permissionsPolicy: custom.permissionsPolicy === false ? false : custom.permissionsPolicy ? base.permissionsPolicy ? { ...base.permissionsPolicy, ...custom.permissionsPolicy } : custom.permissionsPolicy : base.permissionsPolicy
|
|
1407
|
+
};
|
|
1408
|
+
}
|
|
1409
|
+
function withSecurityHeaders(handler, options = {}) {
|
|
1410
|
+
const { preset, config, override = false } = options;
|
|
1411
|
+
let baseConfig = preset ? getPreset(preset) : PRESET_STRICT;
|
|
1412
|
+
if (config) {
|
|
1413
|
+
baseConfig = mergeConfigs(baseConfig, config);
|
|
1414
|
+
}
|
|
1415
|
+
const securityHeaders = buildHeaders(baseConfig);
|
|
1416
|
+
return async (req) => {
|
|
1417
|
+
const response = await handler(req);
|
|
1418
|
+
const newHeaders = new Headers(response.headers);
|
|
1419
|
+
securityHeaders.forEach((value, key) => {
|
|
1420
|
+
if (override || !newHeaders.has(key)) {
|
|
1421
|
+
newHeaders.set(key, value);
|
|
1422
|
+
}
|
|
1423
|
+
});
|
|
1424
|
+
return new Response(response.body, {
|
|
1425
|
+
status: response.status,
|
|
1426
|
+
statusText: response.statusText,
|
|
1427
|
+
headers: newHeaders
|
|
1428
|
+
});
|
|
1429
|
+
};
|
|
1430
|
+
}
|
|
1431
|
+
function createSecurityHeaders(options = {}) {
|
|
1432
|
+
const { preset, config } = options;
|
|
1433
|
+
let baseConfig = preset ? getPreset(preset) : PRESET_STRICT;
|
|
1434
|
+
if (config) {
|
|
1435
|
+
baseConfig = mergeConfigs(baseConfig, config);
|
|
1436
|
+
}
|
|
1437
|
+
return buildHeaders(baseConfig);
|
|
1438
|
+
}
|
|
1439
|
+
function createSecurityHeadersObject(options = {}) {
|
|
1440
|
+
const headers = createSecurityHeaders(options);
|
|
1441
|
+
const obj = {};
|
|
1442
|
+
headers.forEach((value, key) => {
|
|
1443
|
+
obj[key] = value;
|
|
1444
|
+
});
|
|
1445
|
+
return obj;
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1179
1448
|
// src/index.ts
|
|
1180
|
-
var VERSION = "0.
|
|
1449
|
+
var VERSION = "0.3.0";
|
|
1181
1450
|
|
|
1182
|
-
export { AuthenticationError, AuthorizationError, ConfigurationError, CsrfError, MemoryStore, RateLimitError, SecureError, VERSION, ValidationError, anonymizeIp, checkRateLimit, clearAllRateLimits, createToken as createCSRFToken, createMemoryStore, createRateLimiter, formatDuration, generateCSRF, getClientIp, getGeoInfo, getGlobalMemoryStore, getRateLimitStatus, isLocalhost, isPrivateIp, isSecureError, isValidIp, normalizeIp, nowInMs, nowInSeconds, parseDuration, resetRateLimit, sleep, toSecureError, tokensMatch, validateCSRF, verifyToken as verifyCSRFToken, withCSRF, withRateLimit };
|
|
1451
|
+
export { AuthenticationError, AuthorizationError, ConfigurationError, CsrfError, MemoryStore, PRESET_API, PRESET_RELAXED, PRESET_STRICT, RateLimitError, SecureError, VERSION, ValidationError, anonymizeIp, buildCSP, buildHSTS, buildPermissionsPolicy, checkRateLimit, clearAllRateLimits, createToken as createCSRFToken, createMemoryStore, createRateLimiter, createSecurityHeaders, createSecurityHeadersObject, formatDuration, generateCSRF, getClientIp, getGeoInfo, getGlobalMemoryStore, getPreset, getRateLimitStatus, isLocalhost, isPrivateIp, isSecureError, isValidIp, normalizeIp, nowInMs, nowInSeconds, parseDuration, resetRateLimit, sleep, toSecureError, tokensMatch, validateCSRF, verifyToken as verifyCSRFToken, withCSRF, withRateLimit, withSecurityHeaders };
|
|
1183
1452
|
//# sourceMappingURL=index.js.map
|
|
1184
1453
|
//# sourceMappingURL=index.js.map
|