diff --git a/package-lock.json b/package-lock.json index b24a243..d8751c1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,8 +8,10 @@ "name": "ezcheck", "version": "0.1.0", "dependencies": { + "bcryptjs": "^3.0.3", "better-sqlite3": "^9.4.3", "express": "^4.18.3", + "express-session": "^1.19.0", "multer": "^2.1.1", "pdfkit": "^0.15.0" }, @@ -129,6 +131,15 @@ ], "license": "MIT" }, + "node_modules/bcryptjs": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.3.tgz", + "integrity": "sha512-GlF5wPWnSa/X5LKM1o0wz0suXIINz1iHRLvTS+sLyi7XPbe5ycmYI3DlZqVGZZtDgl4DmasFg7gOB3JYbphV5g==", + "license": "BSD-3-Clause", + "bin": { + "bcrypt": "bin/bcrypt" + } + }, "node_modules/better-sqlite3": { "version": "9.6.0", "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-9.6.0.tgz", @@ -717,6 +728,29 @@ "url": "https://opencollective.com/express" } }, + "node_modules/express-session": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.19.0.tgz", + "integrity": "sha512-0csaMkGq+vaiZTmSMMGkfdCOabYv192VbytFypcvI0MANrp+4i/7yEkJ0sbAEhycQjntaKGzYfjfXQyVb7BHMA==", + "license": "MIT", + "dependencies": { + "cookie": "~0.7.2", + "cookie-signature": "~1.0.7", + "debug": "~2.6.9", + "depd": "~2.0.0", + "on-headers": "~1.1.0", + "parseurl": "~1.3.3", + "safe-buffer": "~5.2.1", + "uid-safe": "~2.1.5" + }, + "engines": { + "node": ">= 0.8.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -1679,6 +1713,15 @@ "node": ">= 0.8" } }, + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -1821,6 +1864,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -2345,6 +2397,18 @@ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", "license": "MIT" }, + "node_modules/uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "license": "MIT", + "dependencies": { + "random-bytes": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", diff --git a/package.json b/package.json index ae7b43b..8da1b68 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,10 @@ "migrate": "node migrations/import-mdb.js" }, "dependencies": { + "bcryptjs": "^3.0.3", "better-sqlite3": "^9.4.3", "express": "^4.18.3", + "express-session": "^1.19.0", "multer": "^2.1.1", "pdfkit": "^0.15.0" }, diff --git a/public/css/style.css b/public/css/style.css index ce048ad..be7df09 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -42,6 +42,8 @@ header { .header-info { font-size: 12px; color: rgba(255,255,255,0.7); } .header-info strong { color: #fff; } .header-left { display: flex; align-items: center; gap: 10px; } +.header-right { display: flex; align-items: center; gap: 10px; } +.header-username { font-size: 12px; color: rgba(255,255,255,0.7); } .account-switcher { background: rgba(255,255,255,0.15); @@ -760,3 +762,46 @@ input[type="file"] { flex-wrap: wrap; } .dep-pdf-btns { display: flex; gap: 6px; } + +/* ── Login overlay ── */ +.login-overlay { + position: fixed; + inset: 0; + background: var(--header-bg); + display: flex; + align-items: center; + justify-content: center; + z-index: 2000; +} +.login-overlay.hidden { display: none; } +.login-card { + background: #fff; + border-radius: 8px; + padding: 32px; + width: 360px; + box-shadow: 0 8px 32px rgba(0,0,0,0.35); +} +.login-logo { + font-size: 22px; + font-weight: 700; + color: var(--header-bg); + margin-bottom: 20px; + letter-spacing: -0.5px; +} +.login-card h2 { font-size: 16px; font-weight: 600; margin-bottom: 4px; } +.login-sub { font-size: 12px; color: var(--text-muted); margin-bottom: 16px; } + +/* ── User management ── */ +.account-checkboxes { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; } +.account-checkbox-label { + display: flex; + align-items: center; + gap: 5px; + font-size: 12px; + background: var(--bg); + border: 1px solid var(--border); + border-radius: 4px; + padding: 3px 8px; + cursor: pointer; +} +.account-checkbox-label:hover { border-color: var(--primary); } diff --git a/public/index.html b/public/index.html index 7d6bd99..830b3c4 100644 --- a/public/index.html +++ b/public/index.html @@ -7,13 +7,58 @@
+ + +