zet-lib 2.0.2 → 3.0.1
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/lib/csrf.js +129 -0
- package/lib/generatorApi.js +1 -1
- package/lib/index.js +2 -1
- package/lib/views/router.txt +1 -2
- package/lib/views/zgenerator/routerApp.ejs +1 -1
- package/lib/zAppRouter.js +1 -1
- package/lib/zGeneratorRouter.js +1 -1
- package/lib/zMenuRouter.js +1 -1
- package/lib/zPage.js +1 -1
- package/lib/zRoleRouter.js +1 -1
- package/lib/zViewGenerator.js +1 -1
- package/package.json +1 -2
package/lib/csrf.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const crypto = require('crypto');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* CSRF Protection Middleware
|
|
7
|
+
* Compatible with csurf API for easy migration
|
|
8
|
+
*
|
|
9
|
+
* @param {Object} options - Configuration options
|
|
10
|
+
* @param {Boolean} options.cookie - Use cookie-based storage (default: false, uses session)
|
|
11
|
+
* @param {String} options.cookieKey - Cookie name for secret (default: '_csrf')
|
|
12
|
+
* @param {String} options.value - Function to get token from request (default: reads from body/query/header)
|
|
13
|
+
* @param {Boolean} options.ignoreMethods - HTTP methods to ignore (default: ['GET', 'HEAD', 'OPTIONS'])
|
|
14
|
+
* @param {String} options.secretLength - Length of secret (default: 24)
|
|
15
|
+
*/
|
|
16
|
+
function csrf(options = {}) {
|
|
17
|
+
const opts = {
|
|
18
|
+
cookie: options.cookie !== undefined ? options.cookie : false,
|
|
19
|
+
cookieKey: options.cookieKey || '_csrf',
|
|
20
|
+
value: options.value || defaultValue,
|
|
21
|
+
ignoreMethods: options.ignoreMethods || ['GET', 'HEAD', 'OPTIONS'],
|
|
22
|
+
secretLength: options.secretLength || 24
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// Generate a secret for cookie-based storage
|
|
26
|
+
function generateSecret() {
|
|
27
|
+
return crypto.randomBytes(opts.secretLength).toString('base64');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Generate CSRF token from secret
|
|
31
|
+
function generateToken(secret) {
|
|
32
|
+
return crypto
|
|
33
|
+
.createHash('sha1')
|
|
34
|
+
.update(secret + 'csrfSecret')
|
|
35
|
+
.digest('base64');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Get secret from cookie or session
|
|
39
|
+
function getSecret(req) {
|
|
40
|
+
if (opts.cookie) {
|
|
41
|
+
return req.cookies && req.cookies[opts.cookieKey];
|
|
42
|
+
} else {
|
|
43
|
+
return req.session && req.session._csrfSecret;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Set secret in cookie or session
|
|
48
|
+
function setSecret(req, res, secret) {
|
|
49
|
+
if (opts.cookie) {
|
|
50
|
+
// Set cookie if not already set
|
|
51
|
+
if (!req.cookies || !req.cookies[opts.cookieKey]) {
|
|
52
|
+
res.cookie(opts.cookieKey, secret, {
|
|
53
|
+
httpOnly: true,
|
|
54
|
+
secure: process.env.NODE_ENV === 'production',
|
|
55
|
+
sameSite: 'strict',
|
|
56
|
+
maxAge: 86400000 // 24 hours
|
|
57
|
+
});
|
|
58
|
+
// Also set in req.cookies for immediate access
|
|
59
|
+
if (!req.cookies) {
|
|
60
|
+
req.cookies = {};
|
|
61
|
+
}
|
|
62
|
+
req.cookies[opts.cookieKey] = secret;
|
|
63
|
+
}
|
|
64
|
+
} else {
|
|
65
|
+
if (!req.session) {
|
|
66
|
+
throw new Error('Session is required when cookie option is false');
|
|
67
|
+
}
|
|
68
|
+
if (!req.session._csrfSecret) {
|
|
69
|
+
req.session._csrfSecret = secret;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Default function to get token from request
|
|
75
|
+
function defaultValue(req) {
|
|
76
|
+
return (req.body && req.body._csrf) ||
|
|
77
|
+
(req.query && req.query._csrf) ||
|
|
78
|
+
(req.headers['csrf-token']) ||
|
|
79
|
+
(req.headers['xsrf-token']) ||
|
|
80
|
+
(req.headers['x-csrf-token']) ||
|
|
81
|
+
(req.headers['x-xsrf-token']);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Middleware function
|
|
85
|
+
return function csrfMiddleware(req, res, next) {
|
|
86
|
+
// Get or create secret
|
|
87
|
+
let secret = getSecret(req);
|
|
88
|
+
if (!secret) {
|
|
89
|
+
secret = generateSecret();
|
|
90
|
+
setSecret(req, res, secret);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Attach csrfToken method to request
|
|
94
|
+
req.csrfToken = function csrfToken() {
|
|
95
|
+
return generateToken(getSecret(req));
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// Skip CSRF validation for ignored methods
|
|
99
|
+
if (opts.ignoreMethods.indexOf(req.method) !== -1) {
|
|
100
|
+
return next();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Skip CSRF validation for AJAX calls (X-Requested-With header)
|
|
104
|
+
// This allows AJAX calls without token refresh
|
|
105
|
+
if (req.headers['x-requested-with'] === 'XMLHttpRequest' || req.xhr) {
|
|
106
|
+
return next();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Get token from request
|
|
110
|
+
const token = opts.value(req);
|
|
111
|
+
const secretValue = getSecret(req);
|
|
112
|
+
const expectedToken = generateToken(secretValue);
|
|
113
|
+
|
|
114
|
+
// Validate token
|
|
115
|
+
if (!token || token !== expectedToken) {
|
|
116
|
+
const err = new Error('Invalid CSRF token');
|
|
117
|
+
err.status = 403;
|
|
118
|
+
err.code = 'EBADCSRFTOKEN';
|
|
119
|
+
return next(err);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Token is valid, continue
|
|
123
|
+
next();
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Export the csrf function
|
|
128
|
+
module.exports = csrf;
|
|
129
|
+
|
package/lib/generatorApi.js
CHANGED
|
@@ -3,7 +3,7 @@ const router = express.Router();
|
|
|
3
3
|
const generatorApp = require("./generatorApp");
|
|
4
4
|
const configGenerator = require('./config_generator');
|
|
5
5
|
|
|
6
|
-
const csrf = require('
|
|
6
|
+
const csrf = require('./csrf');
|
|
7
7
|
const Model = require("./Model");
|
|
8
8
|
const fs = require('fs-extra');
|
|
9
9
|
//const {connection, Util} = require('zet-lib');
|
package/lib/index.js
CHANGED
|
@@ -28,7 +28,8 @@ const coreModules = {
|
|
|
28
28
|
zPage: require("./zPage"),
|
|
29
29
|
zTester: require("./zTester"),
|
|
30
30
|
zCache: require("./zCache"),
|
|
31
|
-
zDropbox: require("./zDropbox")
|
|
31
|
+
zDropbox: require("./zDropbox"),
|
|
32
|
+
csrf: require("./csrf")
|
|
32
33
|
};
|
|
33
34
|
|
|
34
35
|
// Heavy dependencies - lazy loaded (only when accessed)
|
package/lib/views/router.txt
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
const router = require('express').Router();
|
|
2
|
-
const csrf = require('
|
|
2
|
+
const {Util, access, connection, moduleLib, zDebug, zRoute, zRole, zDataTable, zForm, csrf} = require('zet-lib');
|
|
3
3
|
const csrfProtection = csrf({cookie: true});
|
|
4
|
-
const {Util, access, connection, moduleLib, zDebug, zRoute, zRole, zDataTable, zForm} = require('zet-lib');
|
|
5
4
|
const MYMODEL = require('./../models/[[[TABLE_NAME]]]');
|
|
6
5
|
|
|
7
6
|
router.get('/', async (req, res) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const router = require('express').Router();
|
|
2
|
-
const csrf = require('
|
|
2
|
+
const {csrf} = require('zet-lib');
|
|
3
3
|
const csrfProtection = csrf({cookie: true});
|
|
4
4
|
const {Util, access, connection, moduleLib, zDebug, zRoute, zRole, zDataTable, zForm} = require('zet-lib');
|
|
5
5
|
const MYMODEL = require('./../models/[[[TABLE_NAME]]]');
|
package/lib/zAppRouter.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require("dotenv").config();
|
|
2
2
|
const express = require("express");
|
|
3
3
|
const router = express.Router();
|
|
4
|
-
const csrf = require("
|
|
4
|
+
const csrf = require("./csrf");
|
|
5
5
|
const csrfProtection = csrf({ cookie: true });
|
|
6
6
|
const zRoute = require("./zRoute");
|
|
7
7
|
const connection = require("./connection");
|
package/lib/zGeneratorRouter.js
CHANGED
package/lib/zMenuRouter.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const express = require('express');
|
|
2
2
|
const router = express.Router();
|
|
3
|
-
const csrf = require('
|
|
3
|
+
const csrf = require('./csrf');
|
|
4
4
|
const csrfProtection = csrf({cookie: true});
|
|
5
5
|
const fs = require('fs-extra');
|
|
6
6
|
//const {Util, connection, zRole, zCache } = require('zet-lib');
|
package/lib/zPage.js
CHANGED
|
@@ -52,7 +52,7 @@ zpage.build = async (req, res) => {
|
|
|
52
52
|
|
|
53
53
|
zpage.coreCode = () => {
|
|
54
54
|
return `const router = require('express').Router();
|
|
55
|
-
const csrf = require('
|
|
55
|
+
const {csrf} = require('zet-lib');
|
|
56
56
|
const csrfProtection = csrf({cookie: true});
|
|
57
57
|
const fs = require('fs-extra');
|
|
58
58
|
const qs = require('qs');
|
package/lib/zRoleRouter.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const express = require('express')
|
|
2
2
|
const router = express.Router()
|
|
3
3
|
// setup route middlewares
|
|
4
|
-
const csrf = require('
|
|
4
|
+
const csrf = require('./csrf')
|
|
5
5
|
const bodyParser = require('body-parser')
|
|
6
6
|
const path = require('path')
|
|
7
7
|
const parseForm = bodyParser.urlencoded({ extended: true })
|
package/lib/zViewGenerator.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zet-lib",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "zet is a library that part of zet generator.",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=18"
|
|
@@ -30,7 +30,6 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"axios": "^1.7.9",
|
|
32
32
|
"convert-excel-to-json": "^1.7.0",
|
|
33
|
-
"csurf": "^1.11.0",
|
|
34
33
|
"dotenv": "^16.5.0",
|
|
35
34
|
"dropbox": "^10.34.0",
|
|
36
35
|
"ejs": "^3.1.10",
|