mbkauthe 2.1.0 → 2.2.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/lib/config.js ADDED
@@ -0,0 +1,199 @@
1
+ import dotenv from "dotenv";
2
+ import crypto from "crypto";
3
+ import { createRequire } from "module";
4
+
5
+ dotenv.config();
6
+
7
+ // Comprehensive validation function
8
+ function validateConfiguration() {
9
+ const errors = [];
10
+
11
+ // Parse and validate mbkautheVar
12
+ let mbkautheVar;
13
+ try {
14
+ if (!process.env.mbkautheVar) {
15
+ errors.push("process.env.mbkautheVar is not defined");
16
+ throw new Error("Configuration validation failed");
17
+ }
18
+ mbkautheVar = JSON.parse(process.env.mbkautheVar);
19
+ } catch (error) {
20
+ if (error.message === "Configuration validation failed") {
21
+ throw new Error(`[mbkauthe] Configuration Error:\n - ${errors.join('\n - ')}`);
22
+ }
23
+ errors.push("Invalid JSON in process.env.mbkautheVar");
24
+ throw new Error(`[mbkauthe] Configuration Error:\n - ${errors.join('\n - ')}`);
25
+ }
26
+
27
+ if (!mbkautheVar || typeof mbkautheVar !== 'object') {
28
+ errors.push("mbkautheVar must be a valid object");
29
+ throw new Error(`[mbkauthe] Configuration Error:\n - ${errors.join('\n - ')}`);
30
+ }
31
+
32
+ // Validate required keys
33
+ // COOKIE_EXPIRE_TIME is not required but if provided must be valid, COOKIE_EXPIRE_TIME by default is 2 days
34
+ // loginRedirectURL is not required but if provided must be valid, loginRedirectURL by default is /dashboard
35
+ const requiredKeys = ["APP_NAME", "Main_SECRET_TOKEN", "SESSION_SECRET_KEY", "IS_DEPLOYED", "LOGIN_DB",
36
+ "MBKAUTH_TWO_FA_ENABLE", "DOMAIN"];
37
+
38
+ requiredKeys.forEach(key => {
39
+ if (!mbkautheVar[key] || (typeof mbkautheVar[key] === 'string' && mbkautheVar[key].trim() === '')) {
40
+ errors.push(`mbkautheVar.${key} is required and cannot be empty`);
41
+ }
42
+ });
43
+
44
+ // Validate IS_DEPLOYED value
45
+ if (mbkautheVar.IS_DEPLOYED && !['true', 'false', 'f'].includes(mbkautheVar.IS_DEPLOYED)) {
46
+ errors.push("mbkautheVar.IS_DEPLOYED must be either 'true' or 'false' or 'f'");
47
+ }
48
+
49
+ // Validate MBKAUTH_TWO_FA_ENABLE value
50
+ if (mbkautheVar.MBKAUTH_TWO_FA_ENABLE && !['true', 'false', 'f'].includes(mbkautheVar.MBKAUTH_TWO_FA_ENABLE.toLowerCase())) {
51
+ errors.push("mbkautheVar.MBKAUTH_TWO_FA_ENABLE must be either 'true' or 'false' or 'f'");
52
+ }
53
+
54
+ // Validate GITHUB_LOGIN_ENABLED value
55
+ if (mbkautheVar.GITHUB_LOGIN_ENABLED && !['true', 'false', 'f'].includes(mbkautheVar.GITHUB_LOGIN_ENABLED.toLowerCase())) {
56
+ errors.push("mbkautheVar.GITHUB_LOGIN_ENABLED must be either 'true' or 'false' or 'f'");
57
+ }
58
+
59
+ // Validate GitHub login configuration
60
+ if (mbkautheVar.GITHUB_LOGIN_ENABLED === "true") {
61
+ if (!mbkautheVar.GITHUB_CLIENT_ID || mbkautheVar.GITHUB_CLIENT_ID.trim() === '') {
62
+ errors.push("mbkautheVar.GITHUB_CLIENT_ID is required when GITHUB_LOGIN_ENABLED is 'true'");
63
+ }
64
+ if (!mbkautheVar.GITHUB_CLIENT_SECRET || mbkautheVar.GITHUB_CLIENT_SECRET.trim() === '') {
65
+ errors.push("mbkautheVar.GITHUB_CLIENT_SECRET is required when GITHUB_LOGIN_ENABLED is 'true'");
66
+ }
67
+ }
68
+
69
+ // Validate COOKIE_EXPIRE_TIME if provided
70
+ if (mbkautheVar.COOKIE_EXPIRE_TIME !== undefined) {
71
+ const expireTime = parseFloat(mbkautheVar.COOKIE_EXPIRE_TIME);
72
+ if (isNaN(expireTime) || expireTime <= 0) {
73
+ errors.push("mbkautheVar.COOKIE_EXPIRE_TIME must be a valid positive number");
74
+ }
75
+ } else {
76
+ // Set default value
77
+ mbkautheVar.COOKIE_EXPIRE_TIME = 2;
78
+ }
79
+
80
+ // Validate DEVICE_TRUST_DURATION_DAYS if provided
81
+ if (mbkautheVar.DEVICE_TRUST_DURATION_DAYS !== undefined) {
82
+ const trustDuration = parseFloat(mbkautheVar.DEVICE_TRUST_DURATION_DAYS);
83
+ if (isNaN(trustDuration) || trustDuration <= 0) {
84
+ errors.push("mbkautheVar.DEVICE_TRUST_DURATION_DAYS must be a valid positive number");
85
+ }
86
+ } else {
87
+ // Set default value
88
+ mbkautheVar.DEVICE_TRUST_DURATION_DAYS = 7;
89
+ }
90
+
91
+ // Validate LOGIN_DB connection string format
92
+ if (mbkautheVar.LOGIN_DB && !mbkautheVar.LOGIN_DB.startsWith('postgresql://') && !mbkautheVar.LOGIN_DB.startsWith('postgres://')) {
93
+ errors.push("mbkautheVar.LOGIN_DB must be a valid PostgreSQL connection string");
94
+ }
95
+
96
+ // If there are validation errors, throw them all at once
97
+ if (errors.length > 0) {
98
+ throw new Error(`[mbkauthe] Configuration Validation Failed:\n - ${errors.join('\n - ')}`);
99
+ }
100
+
101
+ console.log('[mbkauthe] Configuration validation passed successfully');
102
+ return mbkautheVar;
103
+ }
104
+
105
+ // Parse and validate mbkautheVar once
106
+ const mbkautheVar = validateConfiguration();
107
+
108
+ // Shared cookie options functions
109
+ const getCookieOptions = () => ({
110
+ maxAge: mbkautheVar.COOKIE_EXPIRE_TIME * 24 * 60 * 60 * 1000,
111
+ domain: mbkautheVar.IS_DEPLOYED === 'true' ? `.${mbkautheVar.DOMAIN}` : undefined,
112
+ secure: mbkautheVar.IS_DEPLOYED === 'true',
113
+ sameSite: 'lax',
114
+ path: '/',
115
+ httpOnly: true
116
+ });
117
+
118
+ const getClearCookieOptions = () => ({
119
+ domain: mbkautheVar.IS_DEPLOYED === 'true' ? `.${mbkautheVar.DOMAIN}` : undefined,
120
+ secure: mbkautheVar.IS_DEPLOYED === 'true',
121
+ sameSite: 'lax',
122
+ path: '/',
123
+ httpOnly: true
124
+ });
125
+
126
+ // Cache cookie options for performance
127
+ const cachedCookieOptions = getCookieOptions();
128
+ const cachedClearCookieOptions = getClearCookieOptions();
129
+
130
+ // Constants for device trust feature
131
+ const DEVICE_TRUST_DURATION_DAYS = mbkautheVar.DEVICE_TRUST_DURATION_DAYS;
132
+ const DEVICE_TRUST_DURATION_MS = DEVICE_TRUST_DURATION_DAYS * 24 * 60 * 60 * 1000;
133
+
134
+ // Device token utilities
135
+ const generateDeviceToken = () => {
136
+ return crypto.randomBytes(32).toString('hex');
137
+ };
138
+
139
+ const getDeviceTokenCookieOptions = () => ({
140
+ maxAge: DEVICE_TRUST_DURATION_MS,
141
+ domain: mbkautheVar.IS_DEPLOYED === 'true' ? `.${mbkautheVar.DOMAIN}` : undefined,
142
+ secure: mbkautheVar.IS_DEPLOYED === 'true',
143
+ sameSite: 'lax',
144
+ path: '/',
145
+ httpOnly: true
146
+ });
147
+
148
+ // Load package.json from mbkauthe package (not parent project)
149
+ const require = createRequire(import.meta.url);
150
+ let packageJson;
151
+ try {
152
+ // Try to load from mbkauthe package directory
153
+ packageJson = require("mbkauthe/package.json");
154
+ } catch {
155
+ // Fallback to relative path (for development/testing)
156
+ packageJson = require("../package.json");
157
+ }
158
+
159
+ // Helper function to render error pages consistently
160
+ const renderError = (res, { code, error, message, page, pagename, details }) => {
161
+ const renderData = {
162
+ layout: false,
163
+ code,
164
+ error,
165
+ message,
166
+ page,
167
+ pagename,
168
+ app: mbkautheVar.APP_NAME,
169
+ version: packageJson.version
170
+ };
171
+
172
+ // Add optional parameters if provided
173
+ if (details !== undefined) renderData.details = details;
174
+
175
+ return res.render("Error/dError.handlebars", renderData);
176
+ };
177
+
178
+ // Helper to clear all session cookies
179
+ const clearSessionCookies = (res) => {
180
+ res.clearCookie("mbkauthe.sid", cachedClearCookieOptions);
181
+ res.clearCookie("sessionId", cachedClearCookieOptions);
182
+ res.clearCookie("username", cachedClearCookieOptions);
183
+ res.clearCookie("device_token", cachedClearCookieOptions);
184
+ };
185
+
186
+ export {
187
+ mbkautheVar,
188
+ getCookieOptions,
189
+ getClearCookieOptions,
190
+ cachedCookieOptions,
191
+ cachedClearCookieOptions,
192
+ renderError,
193
+ clearSessionCookies,
194
+ packageJson,
195
+ DEVICE_TRUST_DURATION_DAYS,
196
+ DEVICE_TRUST_DURATION_MS,
197
+ generateDeviceToken,
198
+ getDeviceTokenCookieOptions
199
+ };