mbkauthe 3.2.0 โ 3.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 +26 -6
- package/docs/api.md +0 -2
- package/docs/db.md +2 -2
- package/index.d.ts +2 -10
- package/lib/middleware/index.js +0 -2
- package/lib/routes/auth.js +6 -8
- package/lib/routes/oauth.js +1 -4
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -119,24 +119,44 @@ app.get('/admin', validateSession, checkRolePermission(['SuperAdmin']), (req, re
|
|
|
119
119
|
app.listen(3000);
|
|
120
120
|
```
|
|
121
121
|
|
|
122
|
-
## ๐งช Testing
|
|
123
122
|
|
|
124
|
-
|
|
123
|
+
## ๐งช Testing & Git Hooks
|
|
124
|
+
|
|
125
|
+
MBKAuthe includes comprehensive test coverage for all authentication features. **A pre-commit hook is provided to ensure code quality:**
|
|
126
|
+
|
|
127
|
+
### Pre-commit Hook (Automatic Test Runner)
|
|
128
|
+
|
|
129
|
+
- Located at `scripts/pre-commit` and `scripts/pre-commit` (Node.js, cross-platform)
|
|
130
|
+
- Starts the dev server, runs all tests, and blocks commits if any test fails
|
|
131
|
+
- The dev server is automatically stopped after tests complete
|
|
132
|
+
- Ensures you never commit code that breaks tests
|
|
133
|
+
|
|
134
|
+
### Git Hook Setup
|
|
135
|
+
|
|
136
|
+
Hooks are auto-configured every time you run `npm run dev`, `npm test`, or `npm run test:watch` (see `scripts/setup-hooks.js`).
|
|
137
|
+
|
|
138
|
+
If you ever need to manually set up hooks:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
node scripts/setup-hooks.js
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Running Tests
|
|
125
145
|
|
|
126
146
|
```bash
|
|
127
|
-
# Run all tests
|
|
147
|
+
# Run all tests (auto-configures hooks)
|
|
128
148
|
npm test
|
|
129
149
|
|
|
130
|
-
# Run tests in watch mode (auto-
|
|
150
|
+
# Run tests in watch mode (auto-configures hooks)
|
|
131
151
|
npm run test:watch
|
|
132
152
|
|
|
133
|
-
# Run with development flags
|
|
153
|
+
# Run with development flags (auto-configures hooks)
|
|
134
154
|
npm run dev
|
|
135
155
|
```
|
|
136
156
|
|
|
137
157
|
**Test Coverage:**
|
|
138
158
|
- โ
Authentication flows (login, 2FA, logout)
|
|
139
|
-
- โ
OAuth integration (GitHub)
|
|
159
|
+
- โ
OAuth integration (GitHub)
|
|
140
160
|
- โ
Session management and security
|
|
141
161
|
- โ
Role-based access control
|
|
142
162
|
- โ
API endpoints and error handling
|
package/docs/api.md
CHANGED
|
@@ -764,9 +764,7 @@ app.get('/protected', validateSession, (req, res) => {
|
|
|
764
764
|
req.session.user = {
|
|
765
765
|
id: 1, // User ID
|
|
766
766
|
username: "john.doe", // Username
|
|
767
|
-
UserName: "john.doe", // Username (alias)
|
|
768
767
|
role: "NormalUser", // User role
|
|
769
|
-
Role: "NormalUser", // User role (alias)
|
|
770
768
|
sessionId: "abc123...", // 64-char hex session ID
|
|
771
769
|
}
|
|
772
770
|
```
|
package/docs/db.md
CHANGED
|
@@ -43,7 +43,7 @@ CREATE TABLE user_github (
|
|
|
43
43
|
user_name VARCHAR(50) REFERENCES "Users"("UserName"),
|
|
44
44
|
github_id VARCHAR(255) UNIQUE,
|
|
45
45
|
github_username VARCHAR(255),
|
|
46
|
-
access_token
|
|
46
|
+
access_token TEXT,
|
|
47
47
|
created_at TimeStamp WITH TIME ZONE DEFAULT NOW(),
|
|
48
48
|
updated_at TimeStamp WITH TIME ZONE DEFAULT NOW()
|
|
49
49
|
);
|
|
@@ -58,7 +58,7 @@ CREATE TABLE user_google (
|
|
|
58
58
|
user_name VARCHAR(50) REFERENCES "Users"("UserName"),
|
|
59
59
|
google_id VARCHAR(255) UNIQUE,
|
|
60
60
|
google_email VARCHAR(255),
|
|
61
|
-
access_token
|
|
61
|
+
access_token TEXT,
|
|
62
62
|
created_at TimeStamp WITH TIME ZONE DEFAULT NOW(),
|
|
63
63
|
updated_at TimeStamp WITH TIME ZONE DEFAULT NOW()
|
|
64
64
|
);
|
package/index.d.ts
CHANGED
|
@@ -11,9 +11,7 @@ declare global {
|
|
|
11
11
|
interface Request {
|
|
12
12
|
user?: {
|
|
13
13
|
username: string;
|
|
14
|
-
UserName: string;
|
|
15
14
|
role: 'SuperAdmin' | 'NormalUser' | 'Guest';
|
|
16
|
-
Role: 'SuperAdmin' | 'NormalUser' | 'Guest';
|
|
17
15
|
};
|
|
18
16
|
userRole?: 'SuperAdmin' | 'NormalUser' | 'Guest';
|
|
19
17
|
}
|
|
@@ -22,20 +20,17 @@ declare global {
|
|
|
22
20
|
user?: {
|
|
23
21
|
id: number;
|
|
24
22
|
username: string;
|
|
25
|
-
UserName: string;
|
|
26
23
|
role: 'SuperAdmin' | 'NormalUser' | 'Guest';
|
|
27
|
-
Role: 'SuperAdmin' | 'NormalUser' | 'Guest';
|
|
28
24
|
sessionId: string;
|
|
29
25
|
allowedApps?: string[];
|
|
30
26
|
};
|
|
31
27
|
preAuthUser?: {
|
|
32
28
|
id: number;
|
|
33
29
|
username: string;
|
|
34
|
-
UserName?: string;
|
|
35
30
|
role: 'SuperAdmin' | 'NormalUser' | 'Guest';
|
|
36
|
-
Role?: 'SuperAdmin' | 'NormalUser' | 'Guest';
|
|
37
31
|
loginMethod?: 'password' | 'github' | 'google';
|
|
38
32
|
redirectUrl?: string | null;
|
|
33
|
+
allowedApps?: string[];
|
|
39
34
|
};
|
|
40
35
|
oauthRedirect?: string;
|
|
41
36
|
oauthCsrfToken?: string;
|
|
@@ -80,9 +75,7 @@ declare module 'mbkauthe' {
|
|
|
80
75
|
export interface SessionUser {
|
|
81
76
|
id: number;
|
|
82
77
|
username: string;
|
|
83
|
-
UserName: string;
|
|
84
78
|
role: UserRole;
|
|
85
|
-
Role: UserRole;
|
|
86
79
|
sessionId: string;
|
|
87
80
|
allowedApps?: string[];
|
|
88
81
|
}
|
|
@@ -90,9 +83,8 @@ declare module 'mbkauthe' {
|
|
|
90
83
|
export interface PreAuthUser {
|
|
91
84
|
id: number;
|
|
92
85
|
username: string;
|
|
93
|
-
UserName?: string;
|
|
94
86
|
role: UserRole;
|
|
95
|
-
|
|
87
|
+
allowedApps?: string[];
|
|
96
88
|
loginMethod?: 'password' | 'github' | 'google';
|
|
97
89
|
redirectUrl?: string | null;
|
|
98
90
|
}
|
package/lib/middleware/index.js
CHANGED
|
@@ -81,9 +81,7 @@ export async function sessionRestorationMiddleware(req, res, next) {
|
|
|
81
81
|
req.session.user = {
|
|
82
82
|
id: user.id,
|
|
83
83
|
username: user.UserName,
|
|
84
|
-
UserName: user.UserName,
|
|
85
84
|
role: user.Role,
|
|
86
|
-
Role: user.Role,
|
|
87
85
|
sessionId: normalizedSessionId,
|
|
88
86
|
allowedApps: user.AllowedApps,
|
|
89
87
|
};
|
package/lib/routes/auth.js
CHANGED
|
@@ -103,7 +103,6 @@ export async function checkTrustedDevice(req, username) {
|
|
|
103
103
|
id: deviceUser.id,
|
|
104
104
|
username: username,
|
|
105
105
|
role: deviceUser.Role,
|
|
106
|
-
Role: deviceUser.Role,
|
|
107
106
|
allowedApps: deviceUser.AllowedApps,
|
|
108
107
|
};
|
|
109
108
|
}
|
|
@@ -166,9 +165,7 @@ export async function completeLoginProcess(req, res, user, redirectUrl = null, t
|
|
|
166
165
|
req.session.user = {
|
|
167
166
|
id: user.id,
|
|
168
167
|
username: username,
|
|
169
|
-
UserName: username,
|
|
170
168
|
role: user.role || user.Role,
|
|
171
|
-
Role: user.role || user.Role,
|
|
172
169
|
sessionId,
|
|
173
170
|
allowedApps: user.allowedApps || user.AllowedApps,
|
|
174
171
|
};
|
|
@@ -346,7 +343,6 @@ router.post("/api/login", LoginLimit, async (req, res) => {
|
|
|
346
343
|
id: user.id,
|
|
347
344
|
username: user.UserName,
|
|
348
345
|
role: user.Role,
|
|
349
|
-
Role: user.Role,
|
|
350
346
|
allowedApps: user.AllowedApps,
|
|
351
347
|
};
|
|
352
348
|
const requestedRedirect = typeof redirect === 'string' && redirect.startsWith('/') && !redirect.startsWith('//') ? redirect : null;
|
|
@@ -360,7 +356,7 @@ router.post("/api/login", LoginLimit, async (req, res) => {
|
|
|
360
356
|
id: user.id,
|
|
361
357
|
username: user.UserName,
|
|
362
358
|
role: user.Role,
|
|
363
|
-
|
|
359
|
+
allowedApps: user.AllowedApps,
|
|
364
360
|
redirectUrl: requestedRedirect
|
|
365
361
|
};
|
|
366
362
|
console.log(`[mbkauthe] 2FA required for user: ${trimmedUsername}`);
|
|
@@ -372,7 +368,6 @@ router.post("/api/login", LoginLimit, async (req, res) => {
|
|
|
372
368
|
id: user.id,
|
|
373
369
|
username: user.UserName,
|
|
374
370
|
role: user.Role,
|
|
375
|
-
Role: user.Role,
|
|
376
371
|
allowedApps: user.AllowedApps,
|
|
377
372
|
};
|
|
378
373
|
const requestedRedirect = typeof redirect === 'string' && redirect.startsWith('/') && !redirect.startsWith('//') ? redirect : null;
|
|
@@ -443,7 +438,10 @@ router.post("/api/verify-2fa", TwoFALimit, csrfProtection, async (req, res) => {
|
|
|
443
438
|
const shouldTrustDevice = trustDevice === true || trustDevice === 'true';
|
|
444
439
|
|
|
445
440
|
try {
|
|
446
|
-
|
|
441
|
+
// Use cached allowedApps from preAuthUser to avoid extra database join
|
|
442
|
+
const cachedAllowedApps = req.session.preAuthUser?.allowedApps;
|
|
443
|
+
|
|
444
|
+
const query = `SELECT tfa."TwoFASecret" FROM "TwoFA" tfa WHERE tfa."UserName" = $1`;
|
|
447
445
|
const twoFAResult = await dblogin.query({ name: 'verify-2fa-secret', text: query, values: [username] });
|
|
448
446
|
|
|
449
447
|
if (twoFAResult.rows.length === 0 || !twoFAResult.rows[0].TwoFASecret) {
|
|
@@ -453,7 +451,7 @@ router.post("/api/verify-2fa", TwoFALimit, csrfProtection, async (req, res) => {
|
|
|
453
451
|
}
|
|
454
452
|
|
|
455
453
|
const sharedSecret = twoFAResult.rows[0].TwoFASecret;
|
|
456
|
-
const allowedApps =
|
|
454
|
+
const allowedApps = cachedAllowedApps;
|
|
457
455
|
const tokenValidates = speakeasy.totp.verify({
|
|
458
456
|
secret: sharedSecret,
|
|
459
457
|
encoding: "base32",
|
package/lib/routes/oauth.js
CHANGED
|
@@ -355,9 +355,8 @@ const createOAuthCallback = (provider, strategy) => {
|
|
|
355
355
|
req.session.preAuthUser = {
|
|
356
356
|
id: user.id,
|
|
357
357
|
username: user.UserName,
|
|
358
|
-
UserName: user.UserName,
|
|
359
358
|
role: user.Role,
|
|
360
|
-
|
|
359
|
+
allowedApps: user.AllowedApps,
|
|
361
360
|
loginMethod: provider.toLowerCase(),
|
|
362
361
|
redirectUrl: oauthRedirect || null
|
|
363
362
|
};
|
|
@@ -387,9 +386,7 @@ const handleOAuthRedirect = async (req, res, user, type) => {
|
|
|
387
386
|
const userForSession = {
|
|
388
387
|
id: user.id,
|
|
389
388
|
username: user.UserName,
|
|
390
|
-
UserName: user.UserName,
|
|
391
389
|
role: user.Role,
|
|
392
|
-
Role: user.Role,
|
|
393
390
|
allowedApps: user.AllowedApps,
|
|
394
391
|
};
|
|
395
392
|
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mbkauthe",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "MBKTech's reusable authentication system for Node.js applications.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"types": "index.d.ts",
|
|
8
8
|
"scripts": {
|
|
9
|
-
"dev": "cross-env test=dev nodemon index.js",
|
|
10
|
-
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
|
11
|
-
"test:watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch"
|
|
9
|
+
"dev": "node scripts/setup-hooks.js && cross-env test=dev nodemon index.js",
|
|
10
|
+
"test": "node scripts/setup-hooks.js && node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
|
11
|
+
"test:watch": "node scripts/setup-hooks.js && node --experimental-vm-modules node_modules/jest/bin/jest.js --watch"
|
|
12
12
|
},
|
|
13
13
|
"repository": {
|
|
14
14
|
"type": "git",
|