From f7cd017f9bd34181567cd85bb5726076bc599fc8 Mon Sep 17 00:00:00 2001 From: TayKaiJun Date: Thu, 16 May 2024 17:58:21 -0700 Subject: [PATCH 1/8] initial development for floating button and login logic and page --- components/FloatingButton.tsx | 11 + css/style.css | 13 +- hash.js | 8 + package-lock.json | 577 +++++++++++++++++++++++++++++++++- package.json | 3 + pages/_app.tsx | 2 + pages/api/auth/login.ts | 29 ++ pages/login.tsx | 47 +++ 8 files changed, 683 insertions(+), 7 deletions(-) create mode 100644 components/FloatingButton.tsx create mode 100644 hash.js create mode 100644 pages/api/auth/login.ts create mode 100644 pages/login.tsx diff --git a/components/FloatingButton.tsx b/components/FloatingButton.tsx new file mode 100644 index 0000000..0ea1b2c --- /dev/null +++ b/components/FloatingButton.tsx @@ -0,0 +1,11 @@ +// components/FloatingButton.tsx +import React from 'react'; +import Link from 'next/link'; + +const FloatingButton = () => ( +
+ Need to edit or create an article? Click here +
+); + +export default FloatingButton; diff --git a/css/style.css b/css/style.css index 3110c52..d7d8932 100644 --- a/css/style.css +++ b/css/style.css @@ -285,4 +285,15 @@ li { font-weight: bold; font-size: 100%; font-family: 'Rockwell', sans-serif; -} \ No newline at end of file +} + +.floating-button { + position: fixed; + bottom: 20px; + right: 20px; + background: #fff; + padding: 10px; + border: 1px solid #ccc; + border-radius: 5px; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); +} diff --git a/hash.js b/hash.js new file mode 100644 index 0000000..8c847b5 --- /dev/null +++ b/hash.js @@ -0,0 +1,8 @@ +// hashPassword.js +const bcrypt = require('bcrypt'); +const password = 'password123'; // sample password + +bcrypt.hash(password, 10, (err, hash) => { + if (err) throw err; + console.log(hash); +}); diff --git a/package-lock.json b/package-lock.json index a296462..dbda4eb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,8 @@ "@types/node": "^20.4.7", "@types/react": "^18.2.18", "@types/react-dom": "^18.2.7", + "bcrypt": "^5.1.1", + "dotenv": "^16.4.5", "mongodb": "^6.5.0", "mongoose": "^7.4.2", "next": "latest", @@ -20,6 +22,7 @@ "typescript": "^5.1.6" }, "devDependencies": { + "@types/bcrypt": "^5.0.2", "autoprefixer": "^10.4.19", "postcss": "^8.4.38", "prettier": "3.2.5", @@ -114,6 +117,25 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, "node_modules/@mongodb-js/saslprep": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.5.tgz", @@ -328,6 +350,15 @@ "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==" }, + "node_modules/@types/bcrypt": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.2.tgz", + "integrity": "sha512-6atioO8Y75fNcbmj0G7UjI9lXN2pQ/IGJ2FWT4a/btd0Lk9lQalHLKhkgKVZ3r+spnmWUKfbMi1GEe9wyHQfNQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/node": { "version": "20.11.17", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.17.tgz", @@ -377,6 +408,22 @@ "@types/webidl-conversions": "*" } }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", @@ -419,6 +466,23 @@ "node": ">= 8" } }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", @@ -465,8 +529,20 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/bcrypt": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz", + "integrity": "sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==", + "hasInstallScript": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.11", + "node-addon-api": "^5.0.0" + }, + "engines": { + "node": ">= 10.0.0" + } }, "node_modules/binary-extensions": { "version": "2.3.0", @@ -612,6 +688,14 @@ "node": ">= 6" } }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", @@ -635,6 +719,14 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "bin": { + "color-support": "bin.js" + } + }, "node_modules/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", @@ -644,6 +736,16 @@ "node": ">= 6" } }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + }, "node_modules/cookie": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", @@ -704,6 +806,19 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "engines": { + "node": ">=8" + } + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -716,6 +831,17 @@ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", "dev": true }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -820,6 +946,33 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -842,6 +995,67 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gauge/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/gauge/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/gauge/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/gauge/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/gauge/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/glob": { "version": "10.3.12", "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", @@ -881,6 +1095,11 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -893,11 +1112,37 @@ "node": ">= 0.4" } }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/immutable": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==" }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, "node_modules/ip": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", @@ -938,7 +1183,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "engines": { "node": ">=8" } @@ -1053,6 +1297,28 @@ "node": ">=10" } }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/memory-pager": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", @@ -1104,6 +1370,40 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/mongodb": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.5.0.tgz", @@ -1431,12 +1731,69 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/node-addon-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-releases": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", "dev": true }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -1454,6 +1811,17 @@ "node": ">=0.10.0" } }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, "node_modules/oauth": { "version": "0.9.15", "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz", @@ -1463,7 +1831,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -1484,6 +1851,14 @@ "node": "^10.13.0 || >=12.0.0" } }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, "node_modules/openid-client": { "version": "5.6.5", "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.6.5.tgz", @@ -1498,6 +1873,14 @@ "url": "https://github.com/sponsors/panva" } }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -1821,6 +2204,19 @@ "pify": "^2.3.0" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -1872,6 +2268,59 @@ "node": ">=0.10.0" } }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -1895,6 +2344,25 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/sass": { "version": "1.75.0", "resolved": "https://registry.npmjs.org/sass/-/sass-1.75.0.tgz", @@ -1919,6 +2387,22 @@ "loose-envify": "^1.1.0" } }, + "node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -2003,6 +2487,14 @@ "node": ">=10.0.0" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -2213,6 +2705,30 @@ "node": ">= 6" } }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "engines": { + "node": ">=8" + } + }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -2325,8 +2841,7 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/uuid": { "version": "8.3.2", @@ -2371,6 +2886,51 @@ "node": ">= 8" } }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wide-align/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/wide-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/wide-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wide-align/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", @@ -2462,6 +3022,11 @@ "node": ">=8" } }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", diff --git a/package.json b/package.json index 7a5d3c0..f9ecab1 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,8 @@ "@types/node": "^20.4.7", "@types/react": "^18.2.18", "@types/react-dom": "^18.2.7", + "bcrypt": "^5.1.1", + "dotenv": "^16.4.5", "mongodb": "^6.5.0", "mongoose": "^7.4.2", "next": "latest", @@ -21,6 +23,7 @@ "typescript": "^5.1.6" }, "devDependencies": { + "@types/bcrypt": "^5.0.2", "autoprefixer": "^10.4.19", "postcss": "^8.4.38", "prettier": "3.2.5", diff --git a/pages/_app.tsx b/pages/_app.tsx index 203c5ef..19eb2ed 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -9,6 +9,7 @@ import { SessionProvider } from 'next-auth/react'; import SearchBar from './SearchBar'; import NavBar from '../components/NavBar'; import ChangeArticle from '../components/ChangeArticle'; +import FloatingButton from '../components/FloatingButton'; // import './_app.scss'; function MyApp({ Component, pageProps: { session, ...pageProps } }: AppProps) { @@ -36,6 +37,7 @@ function MyApp({ Component, pageProps: { session, ...pageProps } }: AppProps) {
+
diff --git a/pages/api/auth/login.ts b/pages/api/auth/login.ts new file mode 100644 index 0000000..c4f0bc4 --- /dev/null +++ b/pages/api/auth/login.ts @@ -0,0 +1,29 @@ +// pages/api/login.ts +import { NextApiRequest, NextApiResponse } from 'next'; +import bcrypt from 'bcrypt'; + +const ADMIN_PASSWORD = process.env.HASHED_PASSWORD; + +console.log('Loaded ADMIN_PASSWORD:', ADMIN_PASSWORD); + +export default (req: NextApiRequest, res: NextApiResponse) => { + if (req.method !== 'POST') { + return res.status(405).end(); // Method Not Allowed + } + + const { password } = req.body; + if (!password) { + return res.status(400).json({ error: 'Password is required' }); + } + + bcrypt.compare(password, ADMIN_PASSWORD!, (err, result) => { + if (err) { + return res.status(500).json({ error: 'Error occurred' }); + } + if (result) { + return res.status(200).json({ message: 'Login successful' }); + } else { + return res.status(401).json({ error: 'Wrong password. Please try again.' }); + } + }); +}; diff --git a/pages/login.tsx b/pages/login.tsx new file mode 100644 index 0000000..bf99f23 --- /dev/null +++ b/pages/login.tsx @@ -0,0 +1,47 @@ +import React, { useState } from 'react'; +import { useRouter } from 'next/router'; + +const LoginPage = () => { + const [password, setPassword] = useState(''); + const [error, setError] = useState(''); + const router = useRouter(); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + try { + const response = await fetch('/api/auth/login', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ password }), + }); + + const data = await response.json(); + if (response.status === 200) { + router.push('/edit'); + } else { + setError(data.error || 'Wrong password. Please try again.'); + } + } catch (err) { + setError('An error occurred. Please try again.'); + } + }; + + return ( +
+
+ setPassword(e.target.value)} + placeholder="Enter password" + /> + +
+ {error &&

{error}

} +
+ ); +}; + +export default LoginPage; From 42740c2db2b37af375ded157c7f8fcc05be68708 Mon Sep 17 00:00:00 2001 From: TayKaiJun Date: Thu, 16 May 2024 18:18:03 -0700 Subject: [PATCH 2/8] fixed parsing bug --- hash.js | 6 ++++-- package-lock.json | 31 +++++++++++++++++++++++++++++++ package.json | 3 +++ pages/api/auth/login.ts | 15 +++++++++++---- pages/login.tsx | 2 +- 5 files changed, 50 insertions(+), 7 deletions(-) diff --git a/hash.js b/hash.js index 8c847b5..7964004 100644 --- a/hash.js +++ b/hash.js @@ -1,8 +1,10 @@ -// hashPassword.js const bcrypt = require('bcrypt'); +const btoa = require('btoa'); // npm install btoa if you don't have it const password = 'password123'; // sample password bcrypt.hash(password, 10, (err, hash) => { if (err) throw err; - console.log(hash); + console.log('Hashed Password:', hash); + const base64Encoded = btoa(hash); + console.log('Base64 Encoded Hashed Password:', base64Encoded); }); diff --git a/package-lock.json b/package-lock.json index dbda4eb..d6a1bf3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,9 @@ "@types/node": "^20.4.7", "@types/react": "^18.2.18", "@types/react-dom": "^18.2.7", + "atob": "^2.1.2", "bcrypt": "^5.1.1", + "btoa": "^1.2.1", "dotenv": "^16.4.5", "mongodb": "^6.5.0", "mongoose": "^7.4.2", @@ -22,6 +24,7 @@ "typescript": "^5.1.6" }, "devDependencies": { + "@types/atob": "^2.1.4", "@types/bcrypt": "^5.0.2", "autoprefixer": "^10.4.19", "postcss": "^8.4.38", @@ -350,6 +353,12 @@ "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==" }, + "node_modules/@types/atob": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@types/atob/-/atob-2.1.4.tgz", + "integrity": "sha512-FisOhG87cCFqzCgq6FUtSYsTMOHCB/p28zJbSN1QBo4ZGJfg9PEhMjdIV++NDeOnloUUe0Gz6jwBV+L1Ac00Mw==", + "dev": true + }, "node_modules/@types/bcrypt": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.2.tgz", @@ -489,6 +498,17 @@ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", "dev": true }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, "node_modules/autoprefixer": { "version": "10.4.19", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", @@ -615,6 +635,17 @@ "node": ">=14.20.1" } }, + "node_modules/btoa": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", + "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==", + "bin": { + "btoa": "bin/btoa.js" + }, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", diff --git a/package.json b/package.json index f9ecab1..b169576 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,9 @@ "@types/node": "^20.4.7", "@types/react": "^18.2.18", "@types/react-dom": "^18.2.7", + "atob": "^2.1.2", "bcrypt": "^5.1.1", + "btoa": "^1.2.1", "dotenv": "^16.4.5", "mongodb": "^6.5.0", "mongoose": "^7.4.2", @@ -23,6 +25,7 @@ "typescript": "^5.1.6" }, "devDependencies": { + "@types/atob": "^2.1.4", "@types/bcrypt": "^5.0.2", "autoprefixer": "^10.4.19", "postcss": "^8.4.38", diff --git a/pages/api/auth/login.ts b/pages/api/auth/login.ts index c4f0bc4..0931fee 100644 --- a/pages/api/auth/login.ts +++ b/pages/api/auth/login.ts @@ -1,10 +1,16 @@ -// pages/api/login.ts import { NextApiRequest, NextApiResponse } from 'next'; import bcrypt from 'bcrypt'; +import atob from 'atob'; -const ADMIN_PASSWORD = process.env.HASHED_PASSWORD; +const HASHED_PASSWORD_BASE64 = process.env.HASHED_PASSWORD; -console.log('Loaded ADMIN_PASSWORD:', ADMIN_PASSWORD); +if (!HASHED_PASSWORD_BASE64) { + throw new Error('Environment variable HASHED_PASSWORD is not defined'); +} + +const HASHED_PASSWORD = atob(HASHED_PASSWORD_BASE64); + +console.log('Loaded ADMIN_PASSWORD:', HASHED_PASSWORD); // Debug log export default (req: NextApiRequest, res: NextApiResponse) => { if (req.method !== 'POST') { @@ -16,8 +22,9 @@ export default (req: NextApiRequest, res: NextApiResponse) => { return res.status(400).json({ error: 'Password is required' }); } - bcrypt.compare(password, ADMIN_PASSWORD!, (err, result) => { + bcrypt.compare(password, HASHED_PASSWORD!, (err, result) => { if (err) { + console.error('Error during password comparison:', err); return res.status(500).json({ error: 'Error occurred' }); } if (result) { diff --git a/pages/login.tsx b/pages/login.tsx index bf99f23..74b04b8 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -19,7 +19,7 @@ const LoginPage = () => { const data = await response.json(); if (response.status === 200) { - router.push('/edit'); + router.push('/new'); } else { setError(data.error || 'Wrong password. Please try again.'); } From 2a8c80251f757a5d97acf4301941aee14af0ac33 Mon Sep 17 00:00:00 2001 From: TayKaiJun Date: Thu, 16 May 2024 18:38:35 -0700 Subject: [PATCH 3/8] added authentication cookie --- lib/checkAuth.ts | 8 ++++++++ package-lock.json | 22 +++++++++++++++++++--- package.json | 2 ++ pages/api/auth/login.ts | 9 +++++++++ pages/new.tsx | 19 +++++++++++++++++++ 5 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 lib/checkAuth.ts diff --git a/lib/checkAuth.ts b/lib/checkAuth.ts new file mode 100644 index 0000000..c644f59 --- /dev/null +++ b/lib/checkAuth.ts @@ -0,0 +1,8 @@ +// lib/checkAuth.ts +import { NextApiRequest, NextApiResponse } from 'next'; +import { parse } from 'cookie'; + +export function checkAuth(req: NextApiRequest): boolean { + const cookies = parse(req.headers.cookie || ''); + return cookies.auth === 'logged-in'; +} diff --git a/package-lock.json b/package-lock.json index d6a1bf3..93cdb60 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "atob": "^2.1.2", "bcrypt": "^5.1.1", "btoa": "^1.2.1", + "cookie": "^0.6.0", "dotenv": "^16.4.5", "mongodb": "^6.5.0", "mongoose": "^7.4.2", @@ -26,6 +27,7 @@ "devDependencies": { "@types/atob": "^2.1.4", "@types/bcrypt": "^5.0.2", + "@types/cookie": "^0.6.0", "autoprefixer": "^10.4.19", "postcss": "^8.4.38", "prettier": "3.2.5", @@ -368,6 +370,12 @@ "@types/node": "*" } }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "dev": true + }, "node_modules/@types/node": { "version": "20.11.17", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.17.tgz", @@ -778,9 +786,9 @@ "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "engines": { "node": ">= 0.6" } @@ -1723,6 +1731,14 @@ } } }, + "node_modules/next-auth/node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/next-connect": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/next-connect/-/next-connect-1.0.0.tgz", diff --git a/package.json b/package.json index b169576..3e65611 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "atob": "^2.1.2", "bcrypt": "^5.1.1", "btoa": "^1.2.1", + "cookie": "^0.6.0", "dotenv": "^16.4.5", "mongodb": "^6.5.0", "mongoose": "^7.4.2", @@ -27,6 +28,7 @@ "devDependencies": { "@types/atob": "^2.1.4", "@types/bcrypt": "^5.0.2", + "@types/cookie": "^0.6.0", "autoprefixer": "^10.4.19", "postcss": "^8.4.38", "prettier": "3.2.5", diff --git a/pages/api/auth/login.ts b/pages/api/auth/login.ts index 0931fee..43575c3 100644 --- a/pages/api/auth/login.ts +++ b/pages/api/auth/login.ts @@ -1,6 +1,7 @@ import { NextApiRequest, NextApiResponse } from 'next'; import bcrypt from 'bcrypt'; import atob from 'atob'; +import { serialize } from 'cookie'; const HASHED_PASSWORD_BASE64 = process.env.HASHED_PASSWORD; @@ -28,6 +29,14 @@ export default (req: NextApiRequest, res: NextApiResponse) => { return res.status(500).json({ error: 'Error occurred' }); } if (result) { + const cookie = serialize('auth', 'logged-in', { + httpOnly: true, + secure: process.env.NODE_ENV === 'production', + sameSite: 'strict', + maxAge: 60 * 60 * 24, // 1 day + path: '/', + }); + res.setHeader('Set-Cookie', cookie); return res.status(200).json({ message: 'Login successful' }); } else { return res.status(401).json({ error: 'Wrong password. Please try again.' }); diff --git a/pages/new.tsx b/pages/new.tsx index 7bae744..bc528f3 100644 --- a/pages/new.tsx +++ b/pages/new.tsx @@ -1,4 +1,6 @@ +import { GetServerSideProps, NextApiRequest } from 'next'; import Form from '../components/Form'; +import { checkAuth } from '../lib/checkAuth'; const NewArticle = () => { const articleForm = { @@ -14,4 +16,21 @@ const NewArticle = () => { return
; }; +export const getServerSideProps: GetServerSideProps = async (context) => { + const req = context.req as NextApiRequest; + + if (!checkAuth(req)) { + return { + redirect: { + destination: '/login', + permanent: false, + }, + }; + } + + return { + props: {}, + }; +}; + export default NewArticle; From 46bdb5e6c7b7c6fd69c777bd83f7573f2e936bd7 Mon Sep 17 00:00:00 2001 From: TayKaiJun Date: Thu, 16 May 2024 18:50:20 -0700 Subject: [PATCH 4/8] added encryption for cookie --- hash.js | 4 ++++ lib/checkAuth.ts | 16 ++++++++++++++-- package-lock.json | 19 +++++++++++++++++++ package.json | 2 ++ pages/api/auth/login.ts | 11 +++++++---- 5 files changed, 46 insertions(+), 6 deletions(-) diff --git a/hash.js b/hash.js index 7964004..17c4e90 100644 --- a/hash.js +++ b/hash.js @@ -8,3 +8,7 @@ bcrypt.hash(password, 10, (err, hash) => { const base64Encoded = btoa(hash); console.log('Base64 Encoded Hashed Password:', base64Encoded); }); + +const crypto = require('crypto'); +const secret = crypto.randomBytes(64).toString('hex'); +console.log('COOKIE:', secret); \ No newline at end of file diff --git a/lib/checkAuth.ts b/lib/checkAuth.ts index c644f59..85bc80a 100644 --- a/lib/checkAuth.ts +++ b/lib/checkAuth.ts @@ -1,8 +1,20 @@ // lib/checkAuth.ts -import { NextApiRequest, NextApiResponse } from 'next'; +import { NextApiRequest } from 'next'; import { parse } from 'cookie'; +import cookieSignature from 'cookie-signature'; +import { CipherKey } from 'crypto'; // Import the CipherKey type +const COOKIE_SECRET = process.env.COOKIE_SECRET; + +if (!COOKIE_SECRET) { + throw new Error('Environment variable COOKIE_SECRET is not defined'); +} export function checkAuth(req: NextApiRequest): boolean { const cookies = parse(req.headers.cookie || ''); - return cookies.auth === 'logged-in'; + const signedValue = cookies.auth; + if (!signedValue) { + return false; + } + const value = cookieSignature.unsign(signedValue, COOKIE_SECRET as CipherKey); // Cast COOKIE_SECRET as CipherKey + return value === 'logged-in'; } diff --git a/package-lock.json b/package-lock.json index 93cdb60..3ffb5ad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "bcrypt": "^5.1.1", "btoa": "^1.2.1", "cookie": "^0.6.0", + "cookie-signature": "^1.2.1", "dotenv": "^16.4.5", "mongodb": "^6.5.0", "mongoose": "^7.4.2", @@ -28,6 +29,7 @@ "@types/atob": "^2.1.4", "@types/bcrypt": "^5.0.2", "@types/cookie": "^0.6.0", + "@types/cookie-signature": "^1.1.2", "autoprefixer": "^10.4.19", "postcss": "^8.4.38", "prettier": "3.2.5", @@ -376,6 +378,15 @@ "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", "dev": true }, + "node_modules/@types/cookie-signature": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@types/cookie-signature/-/cookie-signature-1.1.2.tgz", + "integrity": "sha512-2OhrZV2LVnUAXklUFwuYUTokalh/dUb8rqt70OW6ByMSxYpauPZ+kfNLknX3aJyjY5iu8i3cUyoLZP9Fn37tTg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/node": { "version": "20.11.17", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.17.tgz", @@ -793,6 +804,14 @@ "node": ">= 0.6" } }, + "node_modules/cookie-signature": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.1.tgz", + "integrity": "sha512-78KWk9T26NhzXtuL26cIJ8/qNHANyJ/ZYrmEXFzUmhZdjpBv+DlWlOANRTGBt48YcyslsLrj0bMLFTmXvLRCOw==", + "engines": { + "node": ">=6.6.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", diff --git a/package.json b/package.json index 3e65611..c5a2d6e 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "bcrypt": "^5.1.1", "btoa": "^1.2.1", "cookie": "^0.6.0", + "cookie-signature": "^1.2.1", "dotenv": "^16.4.5", "mongodb": "^6.5.0", "mongoose": "^7.4.2", @@ -29,6 +30,7 @@ "@types/atob": "^2.1.4", "@types/bcrypt": "^5.0.2", "@types/cookie": "^0.6.0", + "@types/cookie-signature": "^1.1.2", "autoprefixer": "^10.4.19", "postcss": "^8.4.38", "prettier": "3.2.5", diff --git a/pages/api/auth/login.ts b/pages/api/auth/login.ts index 43575c3..781fa60 100644 --- a/pages/api/auth/login.ts +++ b/pages/api/auth/login.ts @@ -2,16 +2,18 @@ import { NextApiRequest, NextApiResponse } from 'next'; import bcrypt from 'bcrypt'; import atob from 'atob'; import { serialize } from 'cookie'; +import cookieSignature from 'cookie-signature'; const HASHED_PASSWORD_BASE64 = process.env.HASHED_PASSWORD; +const COOKIE_SECRET = process.env.COOKIE_SECRET; -if (!HASHED_PASSWORD_BASE64) { - throw new Error('Environment variable HASHED_PASSWORD is not defined'); +if (!HASHED_PASSWORD_BASE64 || !COOKIE_SECRET) { + throw new Error('Environment variable HASHED_PASSWORD or COOKIE_SECRET is not defined'); } const HASHED_PASSWORD = atob(HASHED_PASSWORD_BASE64); -console.log('Loaded ADMIN_PASSWORD:', HASHED_PASSWORD); // Debug log +// console.log('Loaded ADMIN_PASSWORD:', HASHED_PASSWORD); // Debug log export default (req: NextApiRequest, res: NextApiResponse) => { if (req.method !== 'POST') { @@ -29,7 +31,8 @@ export default (req: NextApiRequest, res: NextApiResponse) => { return res.status(500).json({ error: 'Error occurred' }); } if (result) { - const cookie = serialize('auth', 'logged-in', { + const signedValue = cookieSignature.sign('logged-in', COOKIE_SECRET); + const cookie = serialize('auth', signedValue, { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'strict', From 541724636ba29955886c178fe6a04868b410f2ca Mon Sep 17 00:00:00 2001 From: TayKaiJun Date: Thu, 16 May 2024 19:10:06 -0700 Subject: [PATCH 5/8] merged floating button into existing ChargeArticle element --- components/FloatingButton.tsx | 11 ----------- css/style.css | 14 +++----------- pages/_app.tsx | 2 -- 3 files changed, 3 insertions(+), 24 deletions(-) delete mode 100644 components/FloatingButton.tsx diff --git a/components/FloatingButton.tsx b/components/FloatingButton.tsx deleted file mode 100644 index 0ea1b2c..0000000 --- a/components/FloatingButton.tsx +++ /dev/null @@ -1,11 +0,0 @@ -// components/FloatingButton.tsx -import React from 'react'; -import Link from 'next/link'; - -const FloatingButton = () => ( -
- Need to edit or create an article? Click here -
-); - -export default FloatingButton; diff --git a/css/style.css b/css/style.css index d7d8932..d79f7e7 100644 --- a/css/style.css +++ b/css/style.css @@ -267,6 +267,9 @@ li { /* Change Article Styling */ .edit-article { + position: fixed; + bottom: 20px; + right: 20px; display: flex; justify-content: center; align-items: center; @@ -286,14 +289,3 @@ li { font-size: 100%; font-family: 'Rockwell', sans-serif; } - -.floating-button { - position: fixed; - bottom: 20px; - right: 20px; - background: #fff; - padding: 10px; - border: 1px solid #ccc; - border-radius: 5px; - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); -} diff --git a/pages/_app.tsx b/pages/_app.tsx index 19eb2ed..203c5ef 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -9,7 +9,6 @@ import { SessionProvider } from 'next-auth/react'; import SearchBar from './SearchBar'; import NavBar from '../components/NavBar'; import ChangeArticle from '../components/ChangeArticle'; -import FloatingButton from '../components/FloatingButton'; // import './_app.scss'; function MyApp({ Component, pageProps: { session, ...pageProps } }: AppProps) { @@ -37,7 +36,6 @@ function MyApp({ Component, pageProps: { session, ...pageProps } }: AppProps) {
-
From 31bb6ac4cce54f30ae4a4d63fa2169f33ad64793 Mon Sep 17 00:00:00 2001 From: TayKaiJun Date: Thu, 16 May 2024 19:24:34 -0700 Subject: [PATCH 6/8] styling the login page (incomplete) --- css/form.css | 44 ++++++++++++++++++++++++++++++++++++++++---- pages/login.tsx | 21 +++++++++++++-------- 2 files changed, 53 insertions(+), 12 deletions(-) diff --git a/css/form.css b/css/form.css index 4681e68..a28499e 100644 --- a/css/form.css +++ b/css/form.css @@ -1,20 +1,23 @@ +/* Center the form on the page */ form { width: 90%; margin: auto; max-width: 550px; + text-align: center; } + +/* Style the input, button, and label */ input, form button, label { display: block; + margin: auto; + text-align: center; } -form button, + input, textarea { outline: none; -} -input, -textarea { border: 1px solid rgb(199, 199, 199); border-radius: 10px; padding: 10px; @@ -23,12 +26,17 @@ textarea { height: 30px; color: rgb(53, 53, 53); } + textarea { height: 50px; } + label { margin-top: 10px; + font-weight: bold; + color: #000; } + form button { --accent: rgb(0, 162, 255); margin-top: 20px; @@ -36,4 +44,32 @@ form button { .form-container { width: 90%; + margin: auto; +} + +/* Style for error messages */ +.error-message { + color: red; + margin-top: 10px; + font-size: 90%; +} + +/* Styles for password form */ +.password-container { + margin-top: 20px; +} + +.password-label { + margin-bottom: 5px; + display: block; + font-weight: bold; +} + +.password-input { + padding: 10px; + border: 1px solid #ccc; + border-radius: 5px; + width: 100%; + max-width: 300px; + font-size: 16px; } diff --git a/pages/login.tsx b/pages/login.tsx index 74b04b8..0909361 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -29,17 +29,22 @@ const LoginPage = () => { }; return ( -
+
- setPassword(e.target.value)} - placeholder="Enter password" - /> +
+ + setPassword(e.target.value)} + placeholder="Password" + /> +
+ {error &&

{error}

} - {error &&

{error}

}
); }; From 06450ae7fbd60cb53895d245e40713dcb01a886c Mon Sep 17 00:00:00 2001 From: TayKaiJun Date: Thu, 16 May 2024 19:44:33 -0700 Subject: [PATCH 7/8] styling changes for font and centering --- css/form.css | 3 +++ pages/login.tsx | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/css/form.css b/css/form.css index a28499e..b15ec11 100644 --- a/css/form.css +++ b/css/form.css @@ -52,6 +52,7 @@ form button { color: red; margin-top: 10px; font-size: 90%; + font-family: 'Rockwell', sans-serif; } /* Styles for password form */ @@ -63,6 +64,7 @@ form button { margin-bottom: 5px; display: block; font-weight: bold; + font-family: 'Rockwell', sans-serif; } .password-input { @@ -72,4 +74,5 @@ form button { width: 100%; max-width: 300px; font-size: 16px; + margin: auto; } diff --git a/pages/login.tsx b/pages/login.tsx index 0909361..70c1011 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -43,7 +43,6 @@ const LoginPage = () => { />
{error &&

{error}

} - ); From 7a06315c2cb454127fa25987abcec1bde61b213b Mon Sep 17 00:00:00 2001 From: TayKaiJun Date: Thu, 16 May 2024 19:54:22 -0700 Subject: [PATCH 8/8] css tweaking for password input box --- css/form.css | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/css/form.css b/css/form.css index b15ec11..6af51b3 100644 --- a/css/form.css +++ b/css/form.css @@ -64,15 +64,21 @@ form button { margin-bottom: 5px; display: block; font-weight: bold; + font-size: 90%; font-family: 'Rockwell', sans-serif; } .password-input { - padding: 10px; - border: 1px solid #ccc; - border-radius: 5px; + padding: 15px; + background-color: #FCFCFC; + border: 2px solid #000000; + border-bottom: 3.5px solid #000000; + border-right: 3.5px solid #000000; + border-radius: 10px; width: 100%; max-width: 300px; - font-size: 16px; + font-size: 80%; + font-family: 'Rockwell', sans-serif; + text-align: left; margin: auto; }