mbkauthe 1.0.22 → 1.0.24
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/main.js +105 -20
- package/lib/validateSessionAndRole.js +1 -1
- package/package.json +6 -2
- package/vercel.json +15 -0
- package/.github/workflows/apisec-scan.yml +0 -71
package/lib/main.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import express from "express";
|
|
1
|
+
import express, { json } from "express";
|
|
2
2
|
import crypto from "crypto";
|
|
3
3
|
import session from "express-session";
|
|
4
4
|
import pgSession from "connect-pg-simple";
|
|
@@ -8,6 +8,7 @@ import { authenticate } from "./validateSessionAndRole.js";
|
|
|
8
8
|
import fetch from 'node-fetch';
|
|
9
9
|
import cookieParser from "cookie-parser";
|
|
10
10
|
import bcrypt from 'bcrypt';
|
|
11
|
+
import rateLimit from 'express-rate-limit';
|
|
11
12
|
|
|
12
13
|
import { createRequire } from "module";
|
|
13
14
|
const require = createRequire(import.meta.url);
|
|
@@ -20,18 +21,6 @@ dotenv.config();
|
|
|
20
21
|
const mbkautheVar = JSON.parse(process.env.mbkautheVar);
|
|
21
22
|
|
|
22
23
|
const router = express.Router();
|
|
23
|
-
let COOKIE_EXPIRE_TIME = 2 * 24 * 60 * 60 * 1000; // 2 days
|
|
24
|
-
|
|
25
|
-
try {
|
|
26
|
-
const parsedExpireTime = parseInt(mbkautheVar.COOKIE_EXPIRE_TIME, 10);
|
|
27
|
-
if (!isNaN(parsedExpireTime) && parsedExpireTime > 0) {
|
|
28
|
-
COOKIE_EXPIRE_TIME = parsedExpireTime * 24 * 60 * 60 * 1000;
|
|
29
|
-
} else {
|
|
30
|
-
console.warn("Invalid COOKIE_EXPIRE_TIME, using default value");
|
|
31
|
-
}
|
|
32
|
-
} catch (error) {
|
|
33
|
-
console.log("Error parsing COOKIE_EXPIRE_TIME:", error);
|
|
34
|
-
}
|
|
35
24
|
|
|
36
25
|
// Enable CORS for subdomains
|
|
37
26
|
router.use((req, res, next) => {
|
|
@@ -49,6 +38,46 @@ router.use(express.json());
|
|
|
49
38
|
router.use(express.urlencoded({ extended: true }));
|
|
50
39
|
router.use(cookieParser());
|
|
51
40
|
|
|
41
|
+
// Add rate limiting for sensitive operations
|
|
42
|
+
const LoginLimit = rateLimit({
|
|
43
|
+
windowMs: 1 * 60 * 1000,
|
|
44
|
+
max: 8,
|
|
45
|
+
message: { success: false, message: "Too many attempts, please try again later" },
|
|
46
|
+
skip: (req) => {
|
|
47
|
+
return !!req.session.user;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
router.use((req, res, next) => {
|
|
52
|
+
// Don't allow embedding in iframes
|
|
53
|
+
res.setHeader('X-Frame-Options', 'DENY');
|
|
54
|
+
|
|
55
|
+
// Prevent MIME type sniffing
|
|
56
|
+
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
57
|
+
|
|
58
|
+
// Enable XSS protection
|
|
59
|
+
res.setHeader('X-XSS-Protection', '1; mode=block');
|
|
60
|
+
|
|
61
|
+
// Referrer policy
|
|
62
|
+
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
|
|
63
|
+
|
|
64
|
+
// Content Security Policy
|
|
65
|
+
const csp = [
|
|
66
|
+
"default-src 'self'",
|
|
67
|
+
"script-src 'self' 'unsafe-inline' https://www.google.com https://www.gstatic.com",
|
|
68
|
+
"style-src 'self' 'unsafe-inline'",
|
|
69
|
+
"img-src 'self' data:",
|
|
70
|
+
"connect-src 'self' https://www.google.com",
|
|
71
|
+
"frame-src https://www.google.com",
|
|
72
|
+
"form-action 'self'"
|
|
73
|
+
].join('; ');
|
|
74
|
+
|
|
75
|
+
res.setHeader('Content-Security-Policy', csp);
|
|
76
|
+
|
|
77
|
+
next();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
|
|
52
81
|
// Configure session with proper domain settings for cross-subdomain sharing
|
|
53
82
|
const sessionConfig = {
|
|
54
83
|
store: new PgSession({
|
|
@@ -61,7 +90,7 @@ const sessionConfig = {
|
|
|
61
90
|
saveUninitialized: false,
|
|
62
91
|
proxy: true, // Trust the reverse proxy
|
|
63
92
|
cookie: {
|
|
64
|
-
maxAge: COOKIE_EXPIRE_TIME,
|
|
93
|
+
maxAge: mbkautheVar.COOKIE_EXPIRE_TIME,
|
|
65
94
|
domain: mbkautheVar.IS_DEPLOYED === 'true' ? `.${mbkautheVar.DOMAIN}` : undefined,
|
|
66
95
|
httpOnly: true,
|
|
67
96
|
secure: mbkautheVar.IS_DEPLOYED === 'true' ? 'auto' : false, // 'auto' respects X-Forwarded-Proto
|
|
@@ -98,7 +127,7 @@ router.use(async (req, res, next) => {
|
|
|
98
127
|
|
|
99
128
|
// Set consistent cookie options for all cookies
|
|
100
129
|
const getCookieOptions = () => ({
|
|
101
|
-
maxAge: COOKIE_EXPIRE_TIME,
|
|
130
|
+
maxAge: mbkautheVar.COOKIE_EXPIRE_TIME,
|
|
102
131
|
domain: mbkautheVar.IS_DEPLOYED === 'true' ? `.${mbkautheVar.DOMAIN}` : undefined,
|
|
103
132
|
secure: mbkautheVar.IS_DEPLOYED === 'true' ? 'auto' : false,
|
|
104
133
|
sameSite: 'lax',
|
|
@@ -144,7 +173,7 @@ router.post("/mbkauthe/api/terminateAllSessions", authenticate(mbkautheVar.Main_
|
|
|
144
173
|
}
|
|
145
174
|
});
|
|
146
175
|
|
|
147
|
-
router.post("/mbkauthe/api/login", async (req, res) => {
|
|
176
|
+
router.post("/mbkauthe/api/login", LoginLimit, async (req, res) => {
|
|
148
177
|
console.log("Login request received");
|
|
149
178
|
|
|
150
179
|
const { username, password, token, recaptcha } = req.body;
|
|
@@ -325,13 +354,69 @@ router.post("/mbkauthe/api/logout", async (req, res) => {
|
|
|
325
354
|
});
|
|
326
355
|
|
|
327
356
|
// Return package.json data of mbkauthe
|
|
328
|
-
router.get("/mbkauthe/package", (_, res) => {
|
|
329
|
-
|
|
357
|
+
router.get("/mbkauthe/package", async (_, res) => {
|
|
358
|
+
try {
|
|
359
|
+
const response = await fetch("https://mbkauthe.mbktechstudio.com/mbkauthe/package");
|
|
360
|
+
const latestPackageData = await response.json();
|
|
361
|
+
res.status(200).send(`
|
|
362
|
+
<html>
|
|
363
|
+
<head>
|
|
364
|
+
<title>Package Information</title>
|
|
365
|
+
</head>
|
|
366
|
+
<body>
|
|
367
|
+
<h1>Package Information</h1>
|
|
368
|
+
<p><strong>Current Version:</strong> ${JSON.stringify(packageJson, null, 2)}</p>
|
|
369
|
+
<p><strong>Latest Version:</strong> ${JSON.stringify(latestPackageData, null, 2)}</p>
|
|
370
|
+
</body>
|
|
371
|
+
</html>
|
|
372
|
+
`);
|
|
373
|
+
} catch (err) {
|
|
374
|
+
res.status(200).send(`
|
|
375
|
+
<html>
|
|
376
|
+
<head>
|
|
377
|
+
<title>Package Information</title>
|
|
378
|
+
</head>
|
|
379
|
+
<body>
|
|
380
|
+
<h1>Package Information</h1>
|
|
381
|
+
<p><strong>Current Version:</strong> ${JSON.stringify(packageJson, null, 2)}</p>
|
|
382
|
+
<p><strong>Latest Version:</strong> Failed to fetch latest package data, Erro:${err.message}</p>
|
|
383
|
+
</body>
|
|
384
|
+
</html>
|
|
385
|
+
`);
|
|
386
|
+
}
|
|
330
387
|
});
|
|
331
388
|
|
|
332
389
|
// Return version number of mbkauthe
|
|
333
|
-
router.get(["/mbkauthe/version", "/mbkauthe/v"], (_, res) => {
|
|
334
|
-
|
|
390
|
+
router.get(["/mbkauthe/version", "/mbkauthe/v"], async(_, res) => {
|
|
391
|
+
try {
|
|
392
|
+
const response = await fetch("https://mbkauthe.mbktechstudio.com/mbkauthe/version");
|
|
393
|
+
const latestPackageData = await response.json();
|
|
394
|
+
res.status(200).send(`
|
|
395
|
+
<html>
|
|
396
|
+
<head>
|
|
397
|
+
<title>Version Information</title>
|
|
398
|
+
</head>
|
|
399
|
+
<body>
|
|
400
|
+
<h1>Package Information</h1>
|
|
401
|
+
<p><strong>Current Version:</strong> ${JSON.stringify(packageJson.version, null, 2)}</p>
|
|
402
|
+
<p><strong>Latest Version:</strong> ${JSON.stringify(latestPackageData, null, 2)}</p>
|
|
403
|
+
</body>
|
|
404
|
+
</html>
|
|
405
|
+
`);
|
|
406
|
+
} catch (err) {
|
|
407
|
+
res.status(200).send(`
|
|
408
|
+
<html>
|
|
409
|
+
<head>
|
|
410
|
+
<title>Package Information</title>
|
|
411
|
+
</head>
|
|
412
|
+
<body>
|
|
413
|
+
<h1>Package Information</h1>
|
|
414
|
+
<p><strong>Current Version:</strong> ${JSON.stringify(packageJson.version, null, 2)}</p>
|
|
415
|
+
<p><strong>Latest Version:</strong> Failed to fetch latest package data, Erro:${err.message}</p>
|
|
416
|
+
</body>
|
|
417
|
+
</html>
|
|
418
|
+
`);
|
|
419
|
+
}
|
|
335
420
|
});
|
|
336
421
|
|
|
337
422
|
// Return package-lock.json data of mbkauthe from project the package is installed in
|
|
@@ -3,7 +3,7 @@ const mbkautheVar = JSON.parse(process.env.mbkautheVar);
|
|
|
3
3
|
|
|
4
4
|
// Get consistent cookie options
|
|
5
5
|
const getCookieOptions = () => ({
|
|
6
|
-
maxAge: COOKIE_EXPIRE_TIME,
|
|
6
|
+
maxAge: mbkautheVar.COOKIE_EXPIRE_TIME,
|
|
7
7
|
domain: mbkautheVar.IS_DEPLOYED === 'true' ? `.${mbkautheVar.DOMAIN}` : undefined,
|
|
8
8
|
secure: mbkautheVar.IS_DEPLOYED === 'true' ? 'auto' : false,
|
|
9
9
|
sameSite: 'lax',
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mbkauthe",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.24",
|
|
4
4
|
"description": "MBKTechStudio's reusable authentication system for Node.js applications.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"test": "set test=true&&
|
|
8
|
+
"test": "set test=true&& nodemon index.js"
|
|
9
9
|
},
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|
|
@@ -31,8 +31,12 @@
|
|
|
31
31
|
"cookie-parser": "^1.4.7",
|
|
32
32
|
"dotenv": "^16.4.7",
|
|
33
33
|
"express": "^5.1.0",
|
|
34
|
+
"express-rate-limit": "^7.5.0",
|
|
34
35
|
"express-session": "^1.18.1",
|
|
35
36
|
"node-fetch": "^3.3.2",
|
|
36
37
|
"pg": "^8.14.1"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"nodemon": "^2.0.22"
|
|
37
41
|
}
|
|
38
42
|
}
|
package/vercel.json
ADDED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
# This workflow uses actions that are not certified by GitHub.
|
|
2
|
-
# They are provided by a third-party and are governed by
|
|
3
|
-
# separate terms of service, privacy policy, and support
|
|
4
|
-
# documentation.
|
|
5
|
-
|
|
6
|
-
# APIsec addresses the critical need to secure APIs before they reach production.
|
|
7
|
-
# APIsec provides the industry’s only automated and continuous API testing platform that uncovers security vulnerabilities and logic flaws in APIs.
|
|
8
|
-
# Clients rely on APIsec to evaluate every update and release, ensuring that no APIs go to production with vulnerabilities.
|
|
9
|
-
|
|
10
|
-
# How to Get Started with APIsec.ai
|
|
11
|
-
# 1. Schedule a demo at https://www.apisec.ai/request-a-demo .
|
|
12
|
-
#
|
|
13
|
-
# 2. Register your account at https://cloud.apisec.ai/#/signup .
|
|
14
|
-
#
|
|
15
|
-
# 3. Register your API . See the video (https://www.youtube.com/watch?v=MK3Xo9Dbvac) to get up and running with APIsec quickly.
|
|
16
|
-
#
|
|
17
|
-
# 4. Get GitHub Actions scan attributes from APIsec Project -> Configurations -> Integrations -> CI-CD -> GitHub Actions
|
|
18
|
-
#
|
|
19
|
-
# apisec-run-scan
|
|
20
|
-
#
|
|
21
|
-
# This action triggers the on-demand scans for projects registered in APIsec.
|
|
22
|
-
# If your GitHub account allows code scanning alerts, you can then upload the sarif file generated by this action to show the scan findings.
|
|
23
|
-
# Else you can view the scan results from the project home page in APIsec Platform.
|
|
24
|
-
# The link to view the scan results is also displayed on the console on successful completion of action.
|
|
25
|
-
|
|
26
|
-
# This is a starter workflow to help you get started with APIsec-Scan Actions
|
|
27
|
-
|
|
28
|
-
name: APIsec
|
|
29
|
-
|
|
30
|
-
# Controls when the workflow will run
|
|
31
|
-
on:
|
|
32
|
-
# Triggers the workflow on push or pull request events but only for the "main" branch
|
|
33
|
-
# Customize trigger events based on your DevSecOps processes.
|
|
34
|
-
push:
|
|
35
|
-
branches: [ "main" ]
|
|
36
|
-
pull_request:
|
|
37
|
-
branches: [ "main" ]
|
|
38
|
-
schedule:
|
|
39
|
-
- cron: '44 15 * * 0'
|
|
40
|
-
|
|
41
|
-
# Allows you to run this workflow manually from the Actions tab
|
|
42
|
-
workflow_dispatch:
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
permissions:
|
|
46
|
-
contents: read
|
|
47
|
-
|
|
48
|
-
jobs:
|
|
49
|
-
|
|
50
|
-
Trigger_APIsec_scan:
|
|
51
|
-
permissions:
|
|
52
|
-
security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
|
|
53
|
-
actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status
|
|
54
|
-
runs-on: ubuntu-latest
|
|
55
|
-
|
|
56
|
-
steps:
|
|
57
|
-
- name: APIsec scan
|
|
58
|
-
uses: apisec-inc/apisec-run-scan@025432089674a28ba8fb55f8ab06c10215e772ea
|
|
59
|
-
with:
|
|
60
|
-
# The APIsec username with which the scans will be executed
|
|
61
|
-
apisec-username: ${{ secrets.apisec_username }}
|
|
62
|
-
# The Password of the APIsec user with which the scans will be executed
|
|
63
|
-
apisec-password: ${{ secrets.apisec_password}}
|
|
64
|
-
# The name of the project for security scan
|
|
65
|
-
apisec-project: "VAmPI"
|
|
66
|
-
# The name of the sarif format result file The file is written only if this property is provided.
|
|
67
|
-
sarif-result-file: "apisec-results.sarif"
|
|
68
|
-
- name: Import results
|
|
69
|
-
uses: github/codeql-action/upload-sarif@v3
|
|
70
|
-
with:
|
|
71
|
-
sarif_file: ./apisec-results.sarif
|