admindb 2.1.0 → 2.1.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.
Files changed (178) hide show
  1. package/README.md +1 -1
  2. package/dist/app.d.ts +1 -69
  3. package/dist/app.js +1 -257
  4. package/dist/auth/config.d.ts +1 -19
  5. package/dist/auth/config.js +1 -147
  6. package/dist/auth/crypto.d.ts +1 -27
  7. package/dist/auth/crypto.js +1 -133
  8. package/dist/auth/index.d.ts +1 -5
  9. package/dist/auth/index.js +1 -22
  10. package/dist/auth/middleware.d.ts +1 -14
  11. package/dist/auth/middleware.js +1 -100
  12. package/dist/auth/routes.d.ts +1 -7
  13. package/dist/auth/routes.js +1 -78
  14. package/dist/auth/types.d.ts +1 -35
  15. package/dist/auth/types.js +1 -11
  16. package/dist/cli/args.d.ts +1 -45
  17. package/dist/cli/args.js +1 -328
  18. package/dist/cli/config.d.ts +1 -56
  19. package/dist/cli/config.js +1 -133
  20. package/dist/cli/index.d.ts +1 -4
  21. package/dist/cli/index.js +1 -21
  22. package/dist/cli/runner.d.ts +1 -1
  23. package/dist/cli/runner.js +1 -222
  24. package/dist/cli.d.ts +1 -2
  25. package/dist/cli.js +1 -5
  26. package/dist/data/datasets.d.ts +1 -17
  27. package/dist/data/datasets.js +1 -133
  28. package/dist/data/detector.d.ts +1 -30
  29. package/dist/data/detector.js +1 -472
  30. package/dist/data/engine.d.ts +1 -10
  31. package/dist/data/engine.js +1 -211
  32. package/dist/data/index.d.ts +1 -5
  33. package/dist/data/index.js +1 -22
  34. package/dist/data/strategies.d.ts +1 -30
  35. package/dist/data/strategies.js +1 -343
  36. package/dist/data/types.d.ts +1 -73
  37. package/dist/data/types.js +1 -8
  38. package/dist/db/database.d.ts +1 -119
  39. package/dist/db/database.js +1 -471
  40. package/dist/db/export.d.ts +1 -12
  41. package/dist/db/export.js +1 -42
  42. package/dist/db/filters.d.ts +1 -22
  43. package/dist/db/filters.js +1 -158
  44. package/dist/db/index.d.ts +1 -8
  45. package/dist/db/index.js +1 -25
  46. package/dist/db/introspection.d.ts +1 -6
  47. package/dist/db/introspection.js +1 -172
  48. package/dist/db/manager.d.ts +1 -81
  49. package/dist/db/manager.js +1 -397
  50. package/dist/db/migrations.d.ts +1 -5
  51. package/dist/db/migrations.js +1 -110
  52. package/dist/db/postgres.d.ts +1 -85
  53. package/dist/db/postgres.js +1 -745
  54. package/dist/db/types.d.ts +1 -206
  55. package/dist/db/types.js +1 -7
  56. package/dist/index.d.ts +1 -23
  57. package/dist/index.js +1 -66
  58. package/dist/public/js/api.js +1 -47
  59. package/dist/public/js/app.js +1 -262
  60. package/dist/public/js/browse.js +1 -1371
  61. package/dist/public/js/databases.js +1 -235
  62. package/dist/public/js/designer.js +1 -258
  63. package/dist/public/js/forms.js +1 -826
  64. package/dist/public/js/icons.js +1 -51
  65. package/dist/public/js/inspector.js +1 -638
  66. package/dist/public/js/query.js +1 -322
  67. package/dist/public/js/schema.js +1 -447
  68. package/dist/public/js/seed.js +1 -1090
  69. package/dist/routes/api/helpers.d.ts +1 -42
  70. package/dist/routes/api/helpers.js +1 -133
  71. package/dist/routes/api/import-export.d.ts +1 -3
  72. package/dist/routes/api/import-export.js +1 -85
  73. package/dist/routes/api/index.d.ts +1 -4
  74. package/dist/routes/api/index.js +1 -37
  75. package/dist/routes/api/query.d.ts +1 -3
  76. package/dist/routes/api/query.js +1 -76
  77. package/dist/routes/api/rows.d.ts +1 -3
  78. package/dist/routes/api/rows.js +1 -373
  79. package/dist/routes/api/seed.d.ts +1 -3
  80. package/dist/routes/api/seed.js +1 -82
  81. package/dist/routes/api/tables.d.ts +1 -3
  82. package/dist/routes/api/tables.js +1 -160
  83. package/dist/routes/databases.d.ts +1 -26
  84. package/dist/routes/databases.js +1 -230
  85. package/dist/routes/index.d.ts +1 -3
  86. package/dist/routes/index.js +1 -20
  87. package/dist/routes/pages.d.ts +1 -9
  88. package/dist/routes/pages.js +1 -390
  89. package/dist/serverless.d.ts +1 -40
  90. package/dist/serverless.js +1 -210
  91. package/dist/sql/classifier.d.ts +1 -19
  92. package/dist/sql/classifier.js +1 -37
  93. package/dist/sql/generator.d.ts +1 -81
  94. package/dist/sql/generator.js +1 -348
  95. package/dist/sql/index.d.ts +1 -2
  96. package/dist/sql/index.js +1 -19
  97. package/dist/types/api.d.ts +1 -412
  98. package/dist/types/api.js +1 -9
  99. package/dist/utils/colors.d.ts +1 -40
  100. package/dist/utils/colors.js +1 -64
  101. package/dist/utils/common.d.ts +1 -50
  102. package/dist/utils/common.js +1 -229
  103. package/dist/utils/csv.d.ts +1 -15
  104. package/dist/utils/csv.js +1 -80
  105. package/dist/utils/datatype.d.ts +1 -49
  106. package/dist/utils/datatype.js +1 -222
  107. package/dist/utils/icons.d.ts +1 -11
  108. package/dist/utils/icons.js +1 -72
  109. package/dist/utils/index.d.ts +1 -4
  110. package/dist/utils/index.js +1 -21
  111. package/dist/utils/logger.d.ts +1 -10
  112. package/dist/utils/logger.js +1 -40
  113. package/dist/views/layouts/main.hbs +0 -4
  114. package/dist/views/pages/databases.hbs +0 -18
  115. package/dist/views/pages/designer.hbs +0 -10
  116. package/dist/views/pages/error.hbs +0 -2
  117. package/dist/views/pages/form.hbs +0 -5
  118. package/dist/views/pages/home.hbs +0 -8
  119. package/dist/views/pages/login.hbs +0 -13
  120. package/dist/views/pages/query.hbs +0 -9
  121. package/dist/views/pages/schema.hbs +0 -20
  122. package/dist/views/pages/seed.hbs +0 -31
  123. package/dist/views/pages/table.hbs +0 -14
  124. package/dist/views/partials/icon.hbs +0 -1
  125. package/dist/views/partials/navbar.hbs +0 -6
  126. package/dist/views/partials/sidebar.hbs +0 -8
  127. package/package.json +3 -2
  128. package/dist/app.js.map +0 -1
  129. package/dist/auth/config.js.map +0 -1
  130. package/dist/auth/crypto.js.map +0 -1
  131. package/dist/auth/index.js.map +0 -1
  132. package/dist/auth/middleware.js.map +0 -1
  133. package/dist/auth/routes.js.map +0 -1
  134. package/dist/auth/types.js.map +0 -1
  135. package/dist/cli/args.js.map +0 -1
  136. package/dist/cli/config.js.map +0 -1
  137. package/dist/cli/index.js.map +0 -1
  138. package/dist/cli/runner.js.map +0 -1
  139. package/dist/cli.js.map +0 -1
  140. package/dist/data/datasets.js.map +0 -1
  141. package/dist/data/detector.js.map +0 -1
  142. package/dist/data/engine.js.map +0 -1
  143. package/dist/data/index.js.map +0 -1
  144. package/dist/data/strategies.js.map +0 -1
  145. package/dist/data/types.js.map +0 -1
  146. package/dist/db/database.js.map +0 -1
  147. package/dist/db/export.js.map +0 -1
  148. package/dist/db/filters.js.map +0 -1
  149. package/dist/db/index.js.map +0 -1
  150. package/dist/db/introspection.js.map +0 -1
  151. package/dist/db/manager.js.map +0 -1
  152. package/dist/db/migrations.js.map +0 -1
  153. package/dist/db/postgres.js.map +0 -1
  154. package/dist/db/types.js.map +0 -1
  155. package/dist/index.js.map +0 -1
  156. package/dist/public/css/input.css +0 -302
  157. package/dist/routes/api/helpers.js.map +0 -1
  158. package/dist/routes/api/import-export.js.map +0 -1
  159. package/dist/routes/api/index.js.map +0 -1
  160. package/dist/routes/api/query.js.map +0 -1
  161. package/dist/routes/api/rows.js.map +0 -1
  162. package/dist/routes/api/seed.js.map +0 -1
  163. package/dist/routes/api/tables.js.map +0 -1
  164. package/dist/routes/databases.js.map +0 -1
  165. package/dist/routes/index.js.map +0 -1
  166. package/dist/routes/pages.js.map +0 -1
  167. package/dist/serverless.js.map +0 -1
  168. package/dist/sql/classifier.js.map +0 -1
  169. package/dist/sql/generator.js.map +0 -1
  170. package/dist/sql/index.js.map +0 -1
  171. package/dist/types/api.js.map +0 -1
  172. package/dist/utils/colors.js.map +0 -1
  173. package/dist/utils/common.js.map +0 -1
  174. package/dist/utils/csv.js.map +0 -1
  175. package/dist/utils/datatype.js.map +0 -1
  176. package/dist/utils/icons.js.map +0 -1
  177. package/dist/utils/index.js.map +0 -1
  178. package/dist/utils/logger.js.map +0 -1
@@ -1,133 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.hashPassword = hashPassword;
4
- exports.constantTimeCompare = constantTimeCompare;
5
- exports.verifyPassword = verifyPassword;
6
- exports.parseCookies = parseCookies;
7
- exports.createSessionToken = createSessionToken;
8
- exports.verifySessionToken = verifySessionToken;
9
- const node_crypto_1 = require("node:crypto");
10
- const types_1 = require("./types");
11
- /**
12
- * Generates a secure scrypt password hash with a random or provided salt.
13
- * Format: `scrypt:<saltHex>:<derivedKeyHex>`
14
- */
15
- function hashPassword(password, salt) {
16
- const saltHex = salt || (0, node_crypto_1.randomBytes)(16).toString('hex');
17
- const derivedKey = (0, node_crypto_1.scryptSync)(password, saltHex, 64).toString('hex');
18
- return `scrypt:${saltHex}:${derivedKey}`;
19
- }
20
- /**
21
- * Constant-time comparison between two strings to prevent timing attacks.
22
- */
23
- function constantTimeCompare(a, b) {
24
- try {
25
- const bufA = Buffer.from(String(a), 'utf8');
26
- const bufB = Buffer.from(String(b), 'utf8');
27
- if (bufA.length !== bufB.length) {
28
- // Dummy comparison to prevent timing leak on length mismatch
29
- (0, node_crypto_1.timingSafeEqual)(bufA, bufA);
30
- return false;
31
- }
32
- return (0, node_crypto_1.timingSafeEqual)(bufA, bufB);
33
- }
34
- catch {
35
- return false;
36
- }
37
- }
38
- /**
39
- * Verifies a candidate plaintext password against a stored password or scrypt hash.
40
- */
41
- function verifyPassword(candidatePassword, storedPasswordOrHash) {
42
- if (typeof candidatePassword !== 'string' || typeof storedPasswordOrHash !== 'string') {
43
- return false;
44
- }
45
- // Handle scrypt formatted hash: `scrypt:<salt>:<hash>`
46
- if (storedPasswordOrHash.startsWith('scrypt:')) {
47
- const parts = storedPasswordOrHash.split(':');
48
- if (parts.length === 3 && parts[1] && parts[2]) {
49
- const salt = parts[1];
50
- const expectedKeyHex = parts[2];
51
- try {
52
- const derivedKey = (0, node_crypto_1.scryptSync)(candidatePassword, salt, 64).toString('hex');
53
- return constantTimeCompare(derivedKey, expectedKeyHex);
54
- }
55
- catch {
56
- return false;
57
- }
58
- }
59
- }
60
- // Fallback for plaintext passwords (legacy or plain string configs)
61
- return constantTimeCompare(candidatePassword, storedPasswordOrHash);
62
- }
63
- /**
64
- * Parses raw Cookie header string into key-value map.
65
- */
66
- function parseCookies(cookieHeader) {
67
- const cookies = {};
68
- if (!cookieHeader)
69
- return cookies;
70
- for (const pair of cookieHeader.split(';')) {
71
- const idx = pair.indexOf('=');
72
- if (idx === -1)
73
- continue;
74
- const key = pair.slice(0, idx).trim();
75
- let val = pair.slice(idx + 1).trim();
76
- if (val.startsWith('"') && val.endsWith('"') && val.length >= 2) {
77
- val = val.slice(1, -1);
78
- }
79
- if (key) {
80
- try {
81
- cookies[key] = decodeURIComponent(val);
82
- }
83
- catch {
84
- cookies[key] = val;
85
- }
86
- }
87
- }
88
- return cookies;
89
- }
90
- /**
91
- * Creates a tamper-proof signed session token using HMAC-SHA256.
92
- * Format: `<base64url(username)>.<expiresAtTimestamp>.<hmacSignature>`
93
- */
94
- function createSessionToken(username, secret, durationMs = types_1.DEFAULT_SESSION_DURATION_MS) {
95
- const expiresAt = Date.now() + durationMs;
96
- const userPayload = Buffer.from(username, 'utf8').toString('base64url');
97
- const data = `${userPayload}.${expiresAt}`;
98
- const signature = (0, node_crypto_1.createHmac)('sha256', secret).update(data).digest('base64url');
99
- return `${data}.${signature}`;
100
- }
101
- /**
102
- * Verifies a signed session token in constant time.
103
- * Returns the authenticated username if valid and non-expired, or null otherwise.
104
- */
105
- function verifySessionToken(token, secret, expectedUser) {
106
- if (!token || typeof token !== 'string')
107
- return null;
108
- const parts = token.split('.');
109
- if (parts.length !== 3)
110
- return null;
111
- const [userPayload, expiresStr, providedSignature] = parts;
112
- const data = `${userPayload}.${expiresStr}`;
113
- const expectedSignature = (0, node_crypto_1.createHmac)('sha256', secret).update(data).digest('base64url');
114
- if (!constantTimeCompare(providedSignature, expectedSignature)) {
115
- return null;
116
- }
117
- const expiresAt = Number.parseInt(expiresStr, 10);
118
- if (!Number.isFinite(expiresAt) || Date.now() > expiresAt) {
119
- return null; // Expired
120
- }
121
- let username;
122
- try {
123
- username = Buffer.from(userPayload, 'base64url').toString('utf8');
124
- }
125
- catch {
126
- return null;
127
- }
128
- if (expectedUser && !constantTimeCompare(username, expectedUser)) {
129
- return null;
130
- }
131
- return username;
132
- }
133
- //# sourceMappingURL=crypto.js.map
1
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.hashPassword=function(password,salt){const saltHex=salt||(0,node_crypto_1.randomBytes)(16).toString("hex"),derivedKey=(0,node_crypto_1.scryptSync)(password,saltHex,64).toString("hex");return`scrypt:${saltHex}:${derivedKey}`},exports.constantTimeCompare=constantTimeCompare,exports.verifyPassword=function(candidatePassword,storedPasswordOrHash){if("string"!=typeof candidatePassword||"string"!=typeof storedPasswordOrHash)return!1;if(storedPasswordOrHash.startsWith("scrypt:")){const parts=storedPasswordOrHash.split(":");if(3===parts.length&&parts[1]&&parts[2]){const salt=parts[1],expectedKeyHex=parts[2];try{return constantTimeCompare((0,node_crypto_1.scryptSync)(candidatePassword,salt,64).toString("hex"),expectedKeyHex)}catch{return!1}}}return constantTimeCompare(candidatePassword,storedPasswordOrHash)},exports.parseCookies=function(cookieHeader){const cookies={};if(!cookieHeader)return cookies;for(const pair of cookieHeader.split(";")){const idx=pair.indexOf("=");if(-1===idx)continue;const key=pair.slice(0,idx).trim();let val=pair.slice(idx+1).trim();if(val.startsWith('"')&&val.endsWith('"')&&val.length>=2&&(val=val.slice(1,-1)),key)try{cookies[key]=decodeURIComponent(val)}catch{cookies[key]=val}}return cookies},exports.createSessionToken=function(username,secret,durationMs=types_1.DEFAULT_SESSION_DURATION_MS){const expiresAt=Date.now()+durationMs,data=`${Buffer.from(username,"utf8").toString("base64url")}.${expiresAt}`,signature=(0,node_crypto_1.createHmac)("sha256",secret).update(data).digest("base64url");return`${data}.${signature}`},exports.verifySessionToken=function(token,secret,expectedUser){if(!token||"string"!=typeof token)return null;const parts=token.split(".");if(3!==parts.length)return null;const[userPayload,expiresStr,providedSignature]=parts,data=`${userPayload}.${expiresStr}`,expectedSignature=(0,node_crypto_1.createHmac)("sha256",secret).update(data).digest("base64url");if(!constantTimeCompare(providedSignature,expectedSignature))return null;const expiresAt=Number.parseInt(expiresStr,10);if(!Number.isFinite(expiresAt)||Date.now()>expiresAt)return null;let username;try{username=Buffer.from(userPayload,"base64url").toString("utf8")}catch{return null}if(expectedUser&&!constantTimeCompare(username,expectedUser))return null;return username};const node_crypto_1=require("node:crypto"),types_1=require("./types");function constantTimeCompare(a,b){try{const bufA=Buffer.from(String(a),"utf8"),bufB=Buffer.from(String(b),"utf8");return bufA.length!==bufB.length?((0,node_crypto_1.timingSafeEqual)(bufA,bufA),!1):(0,node_crypto_1.timingSafeEqual)(bufA,bufB)}catch{return!1}}
@@ -1,5 +1 @@
1
- export * from './types';
2
- export * from './crypto';
3
- export * from './config';
4
- export * from './middleware';
5
- export * from './routes';
1
+ export * from './types';export * from './crypto';export * from './config';export * from './middleware';export * from './routes';
@@ -1,22 +1 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./types"), exports);
18
- __exportStar(require("./crypto"), exports);
19
- __exportStar(require("./config"), exports);
20
- __exportStar(require("./middleware"), exports);
21
- __exportStar(require("./routes"), exports);
22
- //# sourceMappingURL=index.js.map
1
+ var __createBinding=this&&this.__createBinding||(Object.create?function(o,m,k,k2){void 0===k2&&(k2=k);var desc=Object.getOwnPropertyDescriptor(m,k);desc&&!("get"in desc?!m.__esModule:desc.writable||desc.configurable)||(desc={enumerable:!0,get:function(){return m[k]}}),Object.defineProperty(o,k2,desc)}:function(o,m,k,k2){void 0===k2&&(k2=k),o[k2]=m[k]}),__exportStar=this&&this.__exportStar||function(m,exports){for(var p in m)"default"===p||Object.prototype.hasOwnProperty.call(exports,p)||__createBinding(exports,m,p)};Object.defineProperty(exports,"__esModule",{value:!0}),__exportStar(require("./types"),exports),__exportStar(require("./crypto"),exports),__exportStar(require("./config"),exports),__exportStar(require("./middleware"),exports),__exportStar(require("./routes"),exports);
@@ -1,14 +1 @@
1
- import type { Request, Response, NextFunction } from 'express';
2
- import type { Logger } from '../utils/logger';
3
- import { type ResolvedAuthConfig } from './types';
4
- /**
5
- * Checks incoming request headers and cookies for valid authentication.
6
- */
7
- export declare function authenticateRequest(req: Request, config: ResolvedAuthConfig): {
8
- authenticated: boolean;
9
- user?: string;
10
- };
11
- /**
12
- * Express middleware to protect routes.
13
- */
14
- export declare function createAuthMiddleware(config: ResolvedAuthConfig, basePath: string, _logger: Logger): (req: Request, res: Response, next: NextFunction) => void;
1
+ import type {Request,Response,NextFunction} from 'express';import type {Logger} from '../utils/logger';import{type ResolvedAuthConfig} from './types';export declare function authenticateRequest(req:Request,config:ResolvedAuthConfig):{authenticated:boolean;user?:string;};export declare function createAuthMiddleware(config:ResolvedAuthConfig,basePath:string,_logger:Logger):(req:Request,res:Response,next:NextFunction)=>void;
@@ -1,100 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.authenticateRequest = authenticateRequest;
4
- exports.createAuthMiddleware = createAuthMiddleware;
5
- const types_1 = require("./types");
6
- const crypto_1 = require("./crypto");
7
- /**
8
- * Checks incoming request headers and cookies for valid authentication.
9
- */
10
- function authenticateRequest(req, config) {
11
- if (!config.enabled) {
12
- return { authenticated: true, user: 'anonymous' };
13
- }
14
- // 1. Check HTTP Authorization header (Basic or Bearer)
15
- const authHeader = req.headers.authorization;
16
- if (authHeader) {
17
- const [scheme, credentials] = authHeader.split(/\s+/, 2);
18
- if (scheme && credentials) {
19
- if (scheme.toLowerCase() === 'basic') {
20
- try {
21
- const decoded = Buffer.from(credentials, 'base64').toString('utf8');
22
- const colonIdx = decoded.indexOf(':');
23
- if (colonIdx !== -1) {
24
- const user = decoded.slice(0, colonIdx);
25
- const pass = decoded.slice(colonIdx + 1);
26
- if ((0, crypto_1.constantTimeCompare)(user, config.username) && (0, crypto_1.verifyPassword)(pass, config.password)) {
27
- return { authenticated: true, user };
28
- }
29
- }
30
- }
31
- catch {
32
- // Ignore parse errors
33
- }
34
- }
35
- else if (scheme.toLowerCase() === 'bearer') {
36
- const user = (0, crypto_1.verifySessionToken)(credentials, config.secret, config.username);
37
- if (user) {
38
- return { authenticated: true, user };
39
- }
40
- // Direct password comparison as bearer token
41
- if ((0, crypto_1.verifyPassword)(credentials, config.password)) {
42
- return { authenticated: true, user: config.username };
43
- }
44
- }
45
- }
46
- }
47
- // 2. Check Cookie session
48
- const cookies = (0, crypto_1.parseCookies)(req.headers.cookie);
49
- const sessionCookie = cookies[types_1.SESSION_COOKIE_NAME];
50
- if (sessionCookie) {
51
- const user = (0, crypto_1.verifySessionToken)(sessionCookie, config.secret, config.username);
52
- if (user) {
53
- return { authenticated: true, user };
54
- }
55
- }
56
- return { authenticated: false };
57
- }
58
- /**
59
- * Express middleware to protect routes.
60
- */
61
- function createAuthMiddleware(config, basePath, _logger) {
62
- return (req, res, next) => {
63
- // Expose auth state to templates
64
- res.locals.authEnabled = config.enabled;
65
- res.locals.isDefaultPassword = config.isDefaultPassword;
66
- if (!config.enabled) {
67
- res.locals.authUser = null;
68
- return next();
69
- }
70
- const p = req.path;
71
- // Public static assets and auth endpoints bypass authentication
72
- if (p.startsWith('/css/') ||
73
- p.startsWith('/js/') ||
74
- p === '/favicon.ico' ||
75
- p === '/login' ||
76
- p === '/logout') {
77
- return next();
78
- }
79
- const auth = authenticateRequest(req, config);
80
- if (auth.authenticated && auth.user) {
81
- res.locals.authUser = auth.user;
82
- req.user = auth.user;
83
- return next();
84
- }
85
- // Unauthenticated: API requests get 401 JSON
86
- if (p.startsWith('/api/') || req.xhr || (req.headers.accept && req.headers.accept.includes('application/json'))) {
87
- res.setHeader('WWW-Authenticate', 'Basic realm="AdminDB", Bearer');
88
- res.status(401).json({
89
- success: false,
90
- error: 'Authentication required. Please log in or provide valid credentials.',
91
- });
92
- return;
93
- }
94
- // Web UI: Redirect to login with return path
95
- const returnUrl = req.originalUrl || `${basePath}${req.url}`;
96
- const loginUrl = `${basePath}/login${returnUrl && returnUrl !== `${basePath}/` ? `?next=${encodeURIComponent(returnUrl)}` : ''}`;
97
- res.redirect(loginUrl);
98
- };
99
- }
100
- //# sourceMappingURL=middleware.js.map
1
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.authenticateRequest=authenticateRequest,exports.createAuthMiddleware=function(config,basePath,_logger){return(req,res,next)=>{if(res.locals.authEnabled=config.enabled,res.locals.isDefaultPassword=config.isDefaultPassword,!config.enabled)return res.locals.authUser=null,next();const p=req.path;if(p.startsWith("/css/")||p.startsWith("/js/")||"/favicon.ico"===p||"/login"===p||"/logout"===p)return next();const auth=authenticateRequest(req,config);if(auth.authenticated&&auth.user)return res.locals.authUser=auth.user,req.user=auth.user,next();if(p.startsWith("/api/")||req.xhr||req.headers.accept&&req.headers.accept.includes("application/json"))return res.setHeader("WWW-Authenticate",'Basic realm="AdminDB", Bearer'),void res.status(401).json({success:!1,error:"Authentication required. Please log in or provide valid credentials."});const returnUrl=req.originalUrl||`${basePath}${req.url}`,loginUrl=`${basePath}/login${returnUrl&&returnUrl!==`${basePath}/`?`?next=${encodeURIComponent(returnUrl)}`:""}`;res.redirect(loginUrl)}};const types_1=require("./types"),crypto_1=require("./crypto");function authenticateRequest(req,config){if(!config.enabled)return{authenticated:!0,user:"anonymous"};const authHeader=req.headers.authorization;if(authHeader){const[scheme,credentials]=authHeader.split(/\s+/,2);if(scheme&&credentials)if("basic"===scheme.toLowerCase())try{const decoded=Buffer.from(credentials,"base64").toString("utf8"),colonIdx=decoded.indexOf(":");if(-1!==colonIdx){const user=decoded.slice(0,colonIdx),pass=decoded.slice(colonIdx+1);if((0,crypto_1.constantTimeCompare)(user,config.username)&&(0,crypto_1.verifyPassword)(pass,config.password))return{authenticated:!0,user:user}}}catch{}else if("bearer"===scheme.toLowerCase()){const user=(0,crypto_1.verifySessionToken)(credentials,config.secret,config.username);if(user)return{authenticated:!0,user:user};if((0,crypto_1.verifyPassword)(credentials,config.password))return{authenticated:!0,user:config.username}}}const sessionCookie=(0,crypto_1.parseCookies)(req.headers.cookie)[types_1.SESSION_COOKIE_NAME];if(sessionCookie){const user=(0,crypto_1.verifySessionToken)(sessionCookie,config.secret,config.username);if(user)return{authenticated:!0,user:user}}return{authenticated:!1}}
@@ -1,7 +1 @@
1
- import type { Router } from 'express';
2
- import type { Logger } from '../utils/logger';
3
- import { type ResolvedAuthConfig } from './types';
4
- /**
5
- * Registers /login and /logout routes.
6
- */
7
- export declare function registerAuthRoutes(router: Router, config: ResolvedAuthConfig, basePath: string, logger: Logger): void;
1
+ import type {Router} from 'express';import type {Logger} from '../utils/logger';import{type ResolvedAuthConfig} from './types';export declare function registerAuthRoutes(router:Router,config:ResolvedAuthConfig,basePath:string,logger:Logger):void;
@@ -1,78 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.registerAuthRoutes = registerAuthRoutes;
4
- const types_1 = require("./types");
5
- const middleware_1 = require("./middleware");
6
- const crypto_1 = require("./crypto");
7
- /**
8
- * Registers /login and /logout routes.
9
- */
10
- function registerAuthRoutes(router, config, basePath, logger) {
11
- // GET /login - render login screen
12
- router.get('/login', (req, res) => {
13
- if (!config.enabled) {
14
- return res.redirect(`${basePath}/`);
15
- }
16
- const auth = (0, middleware_1.authenticateRequest)(req, config);
17
- if (auth.authenticated) {
18
- const nextUrl = String(req.query.next ?? '').trim();
19
- return res.redirect(nextUrl.startsWith('/') ? nextUrl : `${basePath}/`);
20
- }
21
- const nextUrl = String(req.query.next ?? '').trim();
22
- res.render('pages/login', {
23
- title: 'Sign in',
24
- noSidebar: true,
25
- next: nextUrl.startsWith('/') ? nextUrl : '',
26
- isDefaultPassword: config.isDefaultPassword,
27
- error: req.query.error ? String(req.query.error) : null,
28
- });
29
- });
30
- // POST /login - process login submission
31
- router.post('/login', (req, res) => {
32
- if (!config.enabled) {
33
- return res.redirect(`${basePath}/`);
34
- }
35
- const username = String(req.body?.username ?? '').trim();
36
- const password = String(req.body?.password ?? '').trim();
37
- const nextUrl = String(req.body?.next ?? req.query.next ?? '').trim();
38
- const isValid = (0, crypto_1.constantTimeCompare)(username, config.username) &&
39
- (0, crypto_1.verifyPassword)(password, config.password);
40
- if (!isValid) {
41
- logger.warn(`Failed login attempt for user "${username || '<empty>'}"`);
42
- if (req.xhr || (req.headers.accept && req.headers.accept.includes('application/json'))) {
43
- return res.status(401).json({ success: false, error: 'Invalid username or password.' });
44
- }
45
- return res.status(401).render('pages/login', {
46
- title: 'Sign in',
47
- noSidebar: true,
48
- username,
49
- next: nextUrl.startsWith('/') ? nextUrl : '',
50
- isDefaultPassword: config.isDefaultPassword,
51
- error: 'Invalid username or password. Please check your credentials.',
52
- });
53
- }
54
- // Successful authentication: issue signed session cookie
55
- const token = (0, crypto_1.createSessionToken)(config.username, config.secret, config.sessionDurationMs);
56
- const maxAgeSec = Math.floor(config.sessionDurationMs / 1000);
57
- const expiresUtc = new Date(Date.now() + config.sessionDurationMs).toUTCString();
58
- const cookiePath = basePath || '/';
59
- res.setHeader('Set-Cookie', `${types_1.SESSION_COOKIE_NAME}=${encodeURIComponent(token)}; Path=${cookiePath}; Max-Age=${maxAgeSec}; Expires=${expiresUtc}; HttpOnly; SameSite=Lax`);
60
- if (req.xhr || (req.headers.accept && req.headers.accept.includes('application/json'))) {
61
- return res.json({ success: true, message: 'Logged in successfully.', user: config.username, token });
62
- }
63
- const target = nextUrl.startsWith('/') ? nextUrl : `${basePath}/`;
64
- res.redirect(target);
65
- });
66
- // POST & GET /logout - clear session and redirect to login
67
- const handleLogout = (req, res) => {
68
- const cookiePath = basePath || '/';
69
- res.setHeader('Set-Cookie', `${types_1.SESSION_COOKIE_NAME}=; Path=${cookiePath}; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly; SameSite=Lax`);
70
- if (req.xhr || (req.headers.accept && req.headers.accept.includes('application/json'))) {
71
- return res.json({ success: true, message: 'Logged out successfully.' });
72
- }
73
- res.redirect(`${basePath}/login`);
74
- };
75
- router.post('/logout', handleLogout);
76
- router.get('/logout', handleLogout);
77
- }
78
- //# sourceMappingURL=routes.js.map
1
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.registerAuthRoutes=function(router,config,basePath,logger){router.get("/login",(req,res)=>{if(!config.enabled)return res.redirect(`${basePath}/`);if((0,middleware_1.authenticateRequest)(req,config).authenticated){const nextUrl=String(req.query.next??"").trim();return res.redirect(nextUrl.startsWith("/")?nextUrl:`${basePath}/`)}const nextUrl=String(req.query.next??"").trim();res.render("pages/login",{title:"Sign in",noSidebar:!0,next:nextUrl.startsWith("/")?nextUrl:"",isDefaultPassword:config.isDefaultPassword,error:req.query.error?String(req.query.error):null})}),router.post("/login",(req,res)=>{if(!config.enabled)return res.redirect(`${basePath}/`);const username=String(req.body?.username??"").trim(),password=String(req.body?.password??"").trim(),nextUrl=String(req.body?.next??req.query.next??"").trim();if(!((0,crypto_1.constantTimeCompare)(username,config.username)&&(0,crypto_1.verifyPassword)(password,config.password)))return logger.warn(`Failed login attempt for user "${username||"<empty>"}"`),req.xhr||req.headers.accept&&req.headers.accept.includes("application/json")?res.status(401).json({success:!1,error:"Invalid username or password."}):res.status(401).render("pages/login",{title:"Sign in",noSidebar:!0,username:username,next:nextUrl.startsWith("/")?nextUrl:"",isDefaultPassword:config.isDefaultPassword,error:"Invalid username or password. Please check your credentials."});const token=(0,crypto_1.createSessionToken)(config.username,config.secret,config.sessionDurationMs),maxAgeSec=Math.floor(config.sessionDurationMs/1e3),expiresUtc=new Date(Date.now()+config.sessionDurationMs).toUTCString(),cookiePath=basePath||"/";if(res.setHeader("Set-Cookie",`${types_1.SESSION_COOKIE_NAME}=${encodeURIComponent(token)}; Path=${cookiePath}; Max-Age=${maxAgeSec}; Expires=${expiresUtc}; HttpOnly; SameSite=Lax`),req.xhr||req.headers.accept&&req.headers.accept.includes("application/json"))return res.json({success:!0,message:"Logged in successfully.",user:config.username,token:token});const target=nextUrl.startsWith("/")?nextUrl:`${basePath}/`;res.redirect(target)});const handleLogout=(req,res)=>{const cookiePath=basePath||"/";if(res.setHeader("Set-Cookie",`${types_1.SESSION_COOKIE_NAME}=; Path=${cookiePath}; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly; SameSite=Lax`),req.xhr||req.headers.accept&&req.headers.accept.includes("application/json"))return res.json({success:!0,message:"Logged out successfully."});res.redirect(`${basePath}/login`)};router.post("/logout",handleLogout),router.get("/logout",handleLogout)};const types_1=require("./types"),middleware_1=require("./middleware"),crypto_1=require("./crypto");
@@ -1,35 +1 @@
1
- export interface AuthConfig {
2
- /**
3
- * Whether authentication is enabled.
4
- * Set to `false` to disable protection entirely (e.g. for development or custom upstream auth).
5
- * Defaults to `true`.
6
- */
7
- enabled?: boolean;
8
- /** Admin username. Defaults to `process.env.ADMINDB_USERNAME` or `'admin'`. */
9
- username?: string;
10
- /**
11
- * Admin password or password hash (e.g. `scrypt:<salt>:<hash>`).
12
- * Generate a hash using `npm run generatehash`.
13
- * Defaults to `process.env.ADMINDB_PASSWORD` or the hardcoded default hash for `'admin'`.
14
- */
15
- password?: string;
16
- /** Secret key used to sign session cookies. Defaults to `process.env.ADMINDB_SECRET` or auto-generated. */
17
- secret?: string;
18
- /** Session expiration time in milliseconds. Defaults to 7 days (604800000 ms). */
19
- sessionDurationMs?: number;
20
- }
21
- export interface ResolvedAuthConfig {
22
- enabled: boolean;
23
- username: string;
24
- password: string;
25
- secret: string;
26
- sessionDurationMs: number;
27
- isDefaultPassword: boolean;
28
- }
29
- export declare const DEFAULT_USERNAME = "admin";
30
- /**
31
- * Hardcoded default scrypt hash for password 'admin' (salt: d9f2e64b8a1c3d5e7f0a2b4c6e801357, keyLen: 64).
32
- */
33
- export declare const DEFAULT_PASSWORD_HASH = "scrypt:d9f2e64b8a1c3d5e7f0a2b4c6e801357:cb3032b16f29c8d44f75c779f070c61c846b17eb333d07596ceb8470fc1b4c06cc720c08796ebc86937dab28a3ef580ced38a71c940fd4a169fd2e9cb9fa40e2";
34
- export declare const DEFAULT_SESSION_DURATION_MS: number;
35
- export declare const SESSION_COOKIE_NAME = "admindb_session";
1
+ export interface AuthConfig{enabled?:boolean;username?:string;password?:string;secret?:string;sessionDurationMs?:number;}export interface ResolvedAuthConfig{enabled:boolean;username:string;password:string;secret:string;sessionDurationMs:number;isDefaultPassword:boolean;}export declare const DEFAULT_USERNAME="admin";export declare const DEFAULT_PASSWORD_HASH="scrypt:d9f2e64b8a1c3d5e7f0a2b4c6e801357:cb3032b16f29c8d44f75c779f070c61c846b17eb333d07596ceb8470fc1b4c06cc720c08796ebc86937dab28a3ef580ced38a71c940fd4a169fd2e9cb9fa40e2";export declare const DEFAULT_SESSION_DURATION_MS:number;export declare const SESSION_COOKIE_NAME="admindb_session";
@@ -1,11 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SESSION_COOKIE_NAME = exports.DEFAULT_SESSION_DURATION_MS = exports.DEFAULT_PASSWORD_HASH = exports.DEFAULT_USERNAME = void 0;
4
- exports.DEFAULT_USERNAME = 'admin';
5
- /**
6
- * Hardcoded default scrypt hash for password 'admin' (salt: d9f2e64b8a1c3d5e7f0a2b4c6e801357, keyLen: 64).
7
- */
8
- exports.DEFAULT_PASSWORD_HASH = 'scrypt:d9f2e64b8a1c3d5e7f0a2b4c6e801357:cb3032b16f29c8d44f75c779f070c61c846b17eb333d07596ceb8470fc1b4c06cc720c08796ebc86937dab28a3ef580ced38a71c940fd4a169fd2e9cb9fa40e2';
9
- exports.DEFAULT_SESSION_DURATION_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
10
- exports.SESSION_COOKIE_NAME = 'admindb_session';
11
- //# sourceMappingURL=types.js.map
1
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.SESSION_COOKIE_NAME=exports.DEFAULT_SESSION_DURATION_MS=exports.DEFAULT_PASSWORD_HASH=exports.DEFAULT_USERNAME=void 0,exports.DEFAULT_USERNAME="admin",exports.DEFAULT_PASSWORD_HASH="scrypt:d9f2e64b8a1c3d5e7f0a2b4c6e801357:cb3032b16f29c8d44f75c779f070c61c846b17eb333d07596ceb8470fc1b4c06cc720c08796ebc86937dab28a3ef580ced38a71c940fd4a169fd2e9cb9fa40e2",exports.DEFAULT_SESSION_DURATION_MS=6048e5,exports.SESSION_COOKIE_NAME="admindb_session";
@@ -1,45 +1 @@
1
- import type { LogLevel } from '../utils/logger';
2
- export interface CliArgs {
3
- help: boolean;
4
- version: boolean;
5
- /** Bind host/interface (`--host`, `-H`). */
6
- host?: string;
7
- /** Port to listen on (`--port`, `-p`). */
8
- port?: number;
9
- /** A single database file to open directly (`--open`/`--db`/`--file`/`--db-path`). */
10
- dbPath?: string;
11
- /** PostgreSQL or database connection string (`--connection`/`--conn`/`--pg`). */
12
- connection?: string;
13
- /** Database connections map (from JSON config file). */
14
- connections?: Record<string, string>;
15
- /** Path to a JSON configuration file (`--config`, `-C`). */
16
- configPath?: string;
17
- /** Directory of database files to manage (`--dir`/`--folder`/`--db-dir`, `-d`). */
18
- dbDir?: string;
19
- /** Explicit database file paths (`--files`/`--db-files`). */
20
- dbFiles?: string[];
21
- /** URL prefix to serve under (`--base-path`/`--base`, `-b`). */
22
- basePath?: string;
23
- /** Log level filter (`--log-level`, `-l`). */
24
- logLevel?: LogLevel;
25
- /** Open databases read-only (`--readonly`, `-r`). */
26
- readonly: boolean;
27
- /** Serverless mode (enforces read-only database operations) (`--serverless`). */
28
- serverless?: boolean;
29
- /** Whether authentication is enabled (defaults to true). Set to false via `--no-auth`. */
30
- auth?: boolean;
31
- /** Custom admin username (`--username`/`--user`/`--auth-username`, `-u`). */
32
- authUsername?: string;
33
- /** Custom admin password (`--password`/`--pass`/`--auth-password`, `-P`). */
34
- authPassword?: string;
35
- /** Secret key for session cookie signing (`--auth-secret`/`--secret`). */
36
- authSecret?: string;
37
- }
38
- export declare function helpText(): string;
39
- /** The installed `admindb` package version (from package.json), or '' when unknown. */
40
- export declare function getPackageVersion(): string;
41
- export declare function versionText(): string;
42
- export declare function parseArgs(argv: string[]): {
43
- args: CliArgs;
44
- error?: string;
45
- };
1
+ import type {LogLevel} from '../utils/logger';export interface CliArgs{help:boolean;version:boolean;host?:string;port?:number;dbPath?:string;connection?:string;connections?:Record<string,string>;configPath?:string;dbDir?:string;dbFiles?:string[];basePath?:string;logLevel?:LogLevel;readonly :boolean;serverless?:boolean;auth?:boolean;authUsername?:string;authPassword?:string;authSecret?:string;}export declare function helpText():string;export declare function getPackageVersion():string;export declare function versionText():string;export declare function parseArgs(argv:string[]):{args:CliArgs;error?:string;};