diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index ff7fb64..355b95c 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -1,6 +1,10 @@ name: Greetings -on: [pull_request_target, issues] +on: + pull_request_target: + types: [opened, synchronized, reopened, closed] + issues: + types: [opened] jobs: greeting: @@ -9,8 +13,26 @@ jobs: issues: write pull-requests: write steps: - - uses: actions/first-interaction@v1 + - name: Greet on new issue + if: github.event_name == 'issues' + uses: actions/first-interaction@v1 with: - repo-token: ${{ secrets.GITHUB_TOKEN }} issue-message: "👋 Thank you for raising an issue! We appreciate your effort in helping us improve. Our team will review it shortly. Stay tuned!" - pr-message: " 🎉 Thank you for your contribution! Your pull request has been submitted successfully. A maintainer will review it as soon as possible. We appreciate your support in making this project better" + + - name: Greet on new pull request + if: github.event_name == 'pull_request' + uses: actions/first-interaction@v1 + with: + pr-message: "🎉 Thank you for your contribution! Your pull request has been submitted successfully. A maintainer will review it as soon as possible. We appreciate your support in making this project better." + + - name: Congratulate on merged pull request + if: github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged == true + run: | + echo "Congratulations to @${{ github.event.pull_request.user.login }} for merging your pull request! 🎉" + echo "If you enjoyed contributing, please consider giving us a star on GitHub and following us for updates!" + # Post a comment on the PR + curl -X POST \ + -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + -H "Accept: application/vnd.github.v3+json" \ + https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments \ + -d "{\"body\": \"Congratulations @${{ github.event.pull_request.user.login }} for merging your pull request! 🎉 If you enjoyed contributing, please consider giving us a star on GitHub and following us for updates!\"}" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5312800 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Adarsh + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/backend/.env b/backend/.env index 7efc9a0..eab5738 100755 --- a/backend/.env +++ b/backend/.env @@ -1,2 +1,5 @@ MONGO_URI = mongodb://localhost:27017 -DB_NAME = passop \ No newline at end of file +DB_NAME = passop +# Encryption and Decryption keys +# Must be 256 bits (32 bytes) +ENCRYPTION_KEY = thisisaverysecureencryptionkey!! diff --git a/backend/server.js b/backend/server.js index 296cabb..472d8a7 100755 --- a/backend/server.js +++ b/backend/server.js @@ -4,9 +4,10 @@ const { MongoClient, ObjectId } = require("mongodb"); const bodyParser = require("body-parser"); const cors = require("cors"); const crypto = require("crypto"); +dotenv.config(); // Encryption and Decryption keys -const ENCRYPTION_KEY = crypto.randomBytes(32); // Must be 256 bits (32 bytes) +const ENCRYPTION_KEY = Buffer.from(process.env.ENCRYPTION_KEY, 'utf-8'); const IV_LENGTH = 16; // For AES, this is always 16 // Encrypt a password @@ -22,7 +23,6 @@ const encrypt = (text) => { return iv.toString("hex") + ":" + encrypted; // Store IV with the encrypted password }; -// Decrypt function const decrypt = (text) => { const [iv, encryptedData] = text.split(":"); const ivBuffer = Buffer.from(iv, "hex"); @@ -33,13 +33,12 @@ const decrypt = (text) => { ivBuffer ); let decrypted = decipher.update(encryptedData, "hex", "utf-8"); + decrypted += decipher.final("utf-8"); return decrypted; }; -dotenv.config(); - // Connecting to the MongoDB Client const url = process.env.MONGO_URI; const client = new MongoClient(url); @@ -61,7 +60,7 @@ const port = process.env.PORT || 3000; // Use port from environment variables or // Middleware app.use(bodyParser.json()); -app.use(cors()); +app.use(cors({ origin: 'chrome-extension://your-extension-id' })); // Replace with your actual extension ID // Get all the passwords app.get("/", async (req, res) => { @@ -69,13 +68,38 @@ app.get("/", async (req, res) => { const db = client.db(dbName); const collection = db.collection("passwords"); const passwords = await collection.find({}).toArray(); - res.status(200).json(passwords); + const decryptedPassword = passwords.map((item) => { + const [iv, encryptedData] = item.password.split(':'); + return { ...item, password: decrypt({ iv, encryptedData }) }; + }); + res.status(200).json(decryptedPassword); } catch (error) { console.error("Error fetching passwords:", error); res.status(500).json({ success: false, message: "Internal Server Error" }); } }); +// Get a password by id +app.get("/:id", async (req, res) => { + try { + const { id } = req.params; + const db = client.db(dbName); + const collection = db.collection("passwords"); + const item = await collection.findOne({ _id: new ObjectId(id) }); + + if (!item) { + return res.status(404).json({ success: false, message: "Password not found" }); + } + + const [iv, encryptedData] = item.password.split(':'); + const decryptedPassword = decrypt({ iv, encryptedData }); + res.status(200).json({ ...item, password: decryptedPassword }); + } catch (error) { + console.error("Error fetching password:", error); + res.status(500).json({ success: false, message: "Internal Server Error" }); + } +}); + // Save a password app.post("/", async (req, res) => { try { diff --git a/package-lock.json b/package-lock.json index 574522c..ce59011 100755 --- a/package-lock.json +++ b/package-lock.json @@ -9,8 +9,10 @@ "version": "0.0.0", "dependencies": { "dotenv": "^16.4.5", + "firebase": "^10.14.1", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-router-dom": "^6.27.0", "react-toastify": "^9.1.3", "uuid": "^9.0.1" }, @@ -819,6 +821,600 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@firebase/analytics": { + "version": "0.10.8", + "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.8.tgz", + "integrity": "sha512-CVnHcS4iRJPqtIDc411+UmFldk0ShSK3OB+D0bKD8Ck5Vro6dbK5+APZpkuWpbfdL359DIQUnAaMLE+zs/PVyA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.9", + "@firebase/installations": "0.6.9", + "@firebase/logger": "0.4.2", + "@firebase/util": "1.10.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/analytics-compat": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.14.tgz", + "integrity": "sha512-unRVY6SvRqfNFIAA/kwl4vK+lvQAL2HVcgu9zTrUtTyYDmtIt/lOuHJynBMYEgLnKm39YKBDhtqdapP2e++ASw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/analytics": "0.10.8", + "@firebase/analytics-types": "0.8.2", + "@firebase/component": "0.6.9", + "@firebase/util": "1.10.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/analytics-types": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.2.tgz", + "integrity": "sha512-EnzNNLh+9/sJsimsA/FGqzakmrAUKLeJvjRHlg8df1f97NLUlFidk9600y0ZgWOp3CAxn6Hjtk+08tixlUOWyw==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/app": { + "version": "0.10.13", + "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.10.13.tgz", + "integrity": "sha512-OZiDAEK/lDB6xy/XzYAyJJkaDqmQ+BCtOEPLqFvxWKUz5JbBmej7IiiRHdtiIOD/twW7O5AxVsfaaGA/V1bNsA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.9", + "@firebase/logger": "0.4.2", + "@firebase/util": "1.10.0", + "idb": "7.1.1", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/app-check": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.8.8.tgz", + "integrity": "sha512-O49RGF1xj7k6BuhxGpHmqOW5hqBIAEbt2q6POW0lIywx7emYtzPDeQI+ryQpC4zbKX646SoVZ711TN1DBLNSOQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.9", + "@firebase/logger": "0.4.2", + "@firebase/util": "1.10.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/app-check-compat": { + "version": "0.3.15", + "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.15.tgz", + "integrity": "sha512-zFIvIFFNqDXpOT2huorz9cwf56VT3oJYRFjSFYdSbGYEJYEaXjLJbfC79lx/zjx4Fh+yuN8pry3TtvwaevrGbg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check": "0.8.8", + "@firebase/app-check-types": "0.5.2", + "@firebase/component": "0.6.9", + "@firebase/logger": "0.4.2", + "@firebase/util": "1.10.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/app-check-interop-types": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.2.tgz", + "integrity": "sha512-LMs47Vinv2HBMZi49C09dJxp0QT5LwDzFaVGf/+ITHe3BlIhUiLNttkATSXplc89A2lAaeTqjgqVkiRfUGyQiQ==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/app-check-types": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.2.tgz", + "integrity": "sha512-FSOEzTzL5bLUbD2co3Zut46iyPWML6xc4x+78TeaXMSuJap5QObfb+rVvZJtla3asN4RwU7elaQaduP+HFizDA==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/app-compat": { + "version": "0.2.43", + "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.43.tgz", + "integrity": "sha512-HM96ZyIblXjAC7TzE8wIk2QhHlSvksYkQ4Ukh1GmEenzkucSNUmUX4QvoKrqeWsLEQ8hdcojABeCV8ybVyZmeg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app": "0.10.13", + "@firebase/component": "0.6.9", + "@firebase/logger": "0.4.2", + "@firebase/util": "1.10.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/app-types": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.2.tgz", + "integrity": "sha512-oMEZ1TDlBz479lmABwWsWjzHwheQKiAgnuKxE0pz0IXCVx7/rtlkx1fQ6GfgK24WCrxDKMplZrT50Kh04iMbXQ==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/auth": { + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.7.9.tgz", + "integrity": "sha512-yLD5095kVgDw965jepMyUrIgDklD6qH/BZNHeKOgvu7pchOKNjVM+zQoOVYJIKWMWOWBq8IRNVU6NXzBbozaJg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.9", + "@firebase/logger": "0.4.2", + "@firebase/util": "1.10.0", + "tslib": "^2.1.0", + "undici": "6.19.7" + }, + "peerDependencies": { + "@firebase/app": "0.x", + "@react-native-async-storage/async-storage": "^1.18.1" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "node_modules/@firebase/auth-compat": { + "version": "0.5.14", + "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.14.tgz", + "integrity": "sha512-2eczCSqBl1KUPJacZlFpQayvpilg3dxXLy9cSMTKtQMTQSmondUtPI47P3ikH3bQAXhzKLOE+qVxJ3/IRtu9pw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/auth": "1.7.9", + "@firebase/auth-types": "0.12.2", + "@firebase/component": "0.6.9", + "@firebase/util": "1.10.0", + "tslib": "^2.1.0", + "undici": "6.19.7" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/auth-interop-types": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.3.tgz", + "integrity": "sha512-Fc9wuJGgxoxQeavybiuwgyi+0rssr76b+nHpj+eGhXFYAdudMWyfBHvFL/I5fEHniUM/UQdFzi9VXJK2iZF7FQ==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/auth-types": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.12.2.tgz", + "integrity": "sha512-qsEBaRMoGvHO10unlDJhaKSuPn4pyoTtlQuP1ghZfzB6rNQPuhp/N/DcFZxm9i4v0SogjCbf9reWupwIvfmH6w==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/component": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.9.tgz", + "integrity": "sha512-gm8EUEJE/fEac86AvHn8Z/QW8BvR56TBw3hMW0O838J/1mThYQXAIQBgUv75EqlCZfdawpWLrKt1uXvp9ciK3Q==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/util": "1.10.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/data-connect": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@firebase/data-connect/-/data-connect-0.1.0.tgz", + "integrity": "sha512-vSe5s8dY13ilhLnfY0eYRmQsdTbH7PUFZtBbqU6JVX/j8Qp9A6G5gG6//ulbX9/1JFOF1IWNOne9c8S/DOCJaQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/auth-interop-types": "0.2.3", + "@firebase/component": "0.6.9", + "@firebase/logger": "0.4.2", + "@firebase/util": "1.10.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/database": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.8.tgz", + "integrity": "sha512-dzXALZeBI1U5TXt6619cv0+tgEhJiwlUtQ55WNZY7vGAjv7Q1QioV969iYwt1AQQ0ovHnEW0YW9TiBfefLvErg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.2", + "@firebase/auth-interop-types": "0.2.3", + "@firebase/component": "0.6.9", + "@firebase/logger": "0.4.2", + "@firebase/util": "1.10.0", + "faye-websocket": "0.11.4", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/database-compat": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-1.0.8.tgz", + "integrity": "sha512-OpeWZoPE3sGIRPBKYnW9wLad25RaWbGyk7fFQe4xnJQKRzlynWeFBSRRAoLE2Old01WXwskUiucNqUUVlFsceg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.9", + "@firebase/database": "1.0.8", + "@firebase/database-types": "1.0.5", + "@firebase/logger": "0.4.2", + "@firebase/util": "1.10.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/database-types": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.5.tgz", + "integrity": "sha512-fTlqCNwFYyq/C6W7AJ5OCuq5CeZuBEsEwptnVxlNPkWCo5cTTyukzAHRSO/jaQcItz33FfYrrFk1SJofcu2AaQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-types": "0.9.2", + "@firebase/util": "1.10.0" + } + }, + "node_modules/@firebase/firestore": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.7.3.tgz", + "integrity": "sha512-NwVU+JPZ/3bhvNSJMCSzfcBZZg8SUGyzZ2T0EW3/bkUeefCyzMISSt/TTIfEHc8cdyXGlMqfGe3/62u9s74UEg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.9", + "@firebase/logger": "0.4.2", + "@firebase/util": "1.10.0", + "@firebase/webchannel-wrapper": "1.0.1", + "@grpc/grpc-js": "~1.9.0", + "@grpc/proto-loader": "^0.7.8", + "tslib": "^2.1.0", + "undici": "6.19.7" + }, + "engines": { + "node": ">=10.10.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/firestore-compat": { + "version": "0.3.38", + "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.38.tgz", + "integrity": "sha512-GoS0bIMMkjpLni6StSwRJarpu2+S5m346Na7gr9YZ/BZ/W3/8iHGNr9PxC+f0rNZXqS4fGRn88pICjrZEgbkqQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.9", + "@firebase/firestore": "4.7.3", + "@firebase/firestore-types": "3.0.2", + "@firebase/util": "1.10.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/firestore-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.2.tgz", + "integrity": "sha512-wp1A+t5rI2Qc/2q7r2ZpjUXkRVPtGMd6zCLsiWurjsQpqPgFin3AhNibKcIzoF2rnToNa/XYtyWXuifjOOwDgg==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/functions": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.11.8.tgz", + "integrity": "sha512-Lo2rTPDn96naFIlSZKVd1yvRRqqqwiJk7cf9TZhUerwnPKgBzXy+aHE22ry+6EjCaQusUoNai6mU6p+G8QZT1g==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.2", + "@firebase/auth-interop-types": "0.2.3", + "@firebase/component": "0.6.9", + "@firebase/messaging-interop-types": "0.2.2", + "@firebase/util": "1.10.0", + "tslib": "^2.1.0", + "undici": "6.19.7" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/functions-compat": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.14.tgz", + "integrity": "sha512-dZ0PKOKQFnOlMfcim39XzaXonSuPPAVuzpqA4ONTIdyaJK/OnBaIEVs/+BH4faa1a2tLeR+Jy15PKqDRQoNIJw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.9", + "@firebase/functions": "0.11.8", + "@firebase/functions-types": "0.6.2", + "@firebase/util": "1.10.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/functions-types": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.2.tgz", + "integrity": "sha512-0KiJ9lZ28nS2iJJvimpY4nNccV21rkQyor5Iheu/nq8aKXJqtJdeSlZDspjPSBBiHRzo7/GMUttegnsEITqR+w==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/installations": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.9.tgz", + "integrity": "sha512-hlT7AwCiKghOX3XizLxXOsTFiFCQnp/oj86zp1UxwDGmyzsyoxtX+UIZyVyH/oBF5+XtblFG9KZzZQ/h+dpy+Q==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.9", + "@firebase/util": "1.10.0", + "idb": "7.1.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/installations-compat": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.9.tgz", + "integrity": "sha512-2lfdc6kPXR7WaL4FCQSQUhXcPbI7ol3wF+vkgtU25r77OxPf8F/VmswQ7sgIkBBWtymn5ZF20TIKtnOj9rjb6w==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.9", + "@firebase/installations": "0.6.9", + "@firebase/installations-types": "0.5.2", + "@firebase/util": "1.10.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/installations-types": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.2.tgz", + "integrity": "sha512-que84TqGRZJpJKHBlF2pkvc1YcXrtEDOVGiDjovP/a3s6W4nlbohGXEsBJo0JCeeg/UG9A+DEZVDUV9GpklUzA==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x" + } + }, + "node_modules/@firebase/logger": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.2.tgz", + "integrity": "sha512-Q1VuA5M1Gjqrwom6I6NUU4lQXdo9IAQieXlujeHZWvRt1b7qQ0KwBaNAjgxG27jgF9/mUwsNmO8ptBCGVYhB0A==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/messaging": { + "version": "0.12.12", + "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.12.tgz", + "integrity": "sha512-6q0pbzYBJhZEtUoQx7hnPhZvAbuMNuBXKQXOx2YlWhSrlv9N1m0ZzlNpBbu/ItTzrwNKTibdYzUyaaxdWLg+4w==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.9", + "@firebase/installations": "0.6.9", + "@firebase/messaging-interop-types": "0.2.2", + "@firebase/util": "1.10.0", + "idb": "7.1.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/messaging-compat": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.12.tgz", + "integrity": "sha512-pKsiUVZrbmRgdImYqhBNZlkKJbqjlPkVdQRZGRbkTyX4OSGKR0F/oJeCt1a8jEg5UnBp4fdVwSWSp4DuCovvEQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.9", + "@firebase/messaging": "0.12.12", + "@firebase/util": "1.10.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/messaging-interop-types": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.2.tgz", + "integrity": "sha512-l68HXbuD2PPzDUOFb3aG+nZj5KA3INcPwlocwLZOzPp9rFM9yeuI9YLl6DQfguTX5eAGxO0doTR+rDLDvQb5tA==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/performance": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.6.9.tgz", + "integrity": "sha512-PnVaak5sqfz5ivhua+HserxTJHtCar/7zM0flCX6NkzBNzJzyzlH4Hs94h2Il0LQB99roBqoE5QT1JqWqcLJHQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.9", + "@firebase/installations": "0.6.9", + "@firebase/logger": "0.4.2", + "@firebase/util": "1.10.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/performance-compat": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.9.tgz", + "integrity": "sha512-dNl95IUnpsu3fAfYBZDCVhXNkASE0uo4HYaEPd2/PKscfTvsgqFAOxfAXzBEDOnynDWiaGUnb5M1O00JQ+3FXA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.9", + "@firebase/logger": "0.4.2", + "@firebase/performance": "0.6.9", + "@firebase/performance-types": "0.2.2", + "@firebase/util": "1.10.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/performance-types": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.2.tgz", + "integrity": "sha512-gVq0/lAClVH5STrIdKnHnCo2UcPLjJlDUoEB/tB4KM+hAeHUxWKnpT0nemUPvxZ5nbdY/pybeyMe8Cs29gEcHA==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/remote-config": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.4.9.tgz", + "integrity": "sha512-EO1NLCWSPMHdDSRGwZ73kxEEcTopAxX1naqLJFNApp4hO8WfKfmEpmjxmP5TrrnypjIf2tUkYaKsfbEA7+AMmA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.9", + "@firebase/installations": "0.6.9", + "@firebase/logger": "0.4.2", + "@firebase/util": "1.10.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/remote-config-compat": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.9.tgz", + "integrity": "sha512-AxzGpWfWFYejH2twxfdOJt5Cfh/ATHONegTd/a0p5flEzsD5JsxXgfkFToop+mypEL3gNwawxrxlZddmDoNxyA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.9", + "@firebase/logger": "0.4.2", + "@firebase/remote-config": "0.4.9", + "@firebase/remote-config-types": "0.3.2", + "@firebase/util": "1.10.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/remote-config-types": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.3.2.tgz", + "integrity": "sha512-0BC4+Ud7y2aPTyhXJTMTFfrGGLqdYXrUB9sJVAB8NiqJswDTc4/2qrE/yfUbnQJhbSi6ZaTTBKyG3n1nplssaA==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/storage": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.13.2.tgz", + "integrity": "sha512-fxuJnHshbhVwuJ4FuISLu+/76Aby2sh+44ztjF2ppoe0TELIDxPW6/r1KGlWYt//AD0IodDYYA8ZTN89q8YqUw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.9", + "@firebase/util": "1.10.0", + "tslib": "^2.1.0", + "undici": "6.19.7" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/storage-compat": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.12.tgz", + "integrity": "sha512-hA4VWKyGU5bWOll+uwzzhEMMYGu9PlKQc1w4DWxB3aIErWYzonrZjF0icqNQZbwKNIdh8SHjZlFeB2w6OSsjfg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.9", + "@firebase/storage": "0.13.2", + "@firebase/storage-types": "0.8.2", + "@firebase/util": "1.10.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/storage-types": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.2.tgz", + "integrity": "sha512-0vWu99rdey0g53lA7IShoA2Lol1jfnPovzLDUBuon65K7uKG9G+L5uO05brD9pMw+l4HRFw23ah3GwTGpEav6g==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/util": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.10.0.tgz", + "integrity": "sha512-xKtx4A668icQqoANRxyDLBLz51TAbDP9KRfpbKGxiCAW346d0BeJe5vN6/hKxxmWwnZ0mautyv39JxviwwQMOQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/vertexai-preview": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@firebase/vertexai-preview/-/vertexai-preview-0.0.4.tgz", + "integrity": "sha512-EBSqyu9eg8frQlVU9/HjKtHN7odqbh9MtAcVz3WwHj4gLCLOoN9F/o+oxlq3CxvFrd3CNTZwu6d2mZtVlEInng==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.2", + "@firebase/component": "0.6.9", + "@firebase/logger": "0.4.2", + "@firebase/util": "1.10.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x", + "@firebase/app-types": "0.x" + } + }, + "node_modules/@firebase/webchannel-wrapper": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.1.tgz", + "integrity": "sha512-jmEnr/pk0yVkA7mIlHNnxCi+wWzOFUg0WyIotgkKAb2u1J7fAeDBcVNSTjTihbAYNusCLQdW5s9IJ5qwnEufcQ==", + "license": "Apache-2.0" + }, + "node_modules/@grpc/grpc-js": { + "version": "1.9.15", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.15.tgz", + "integrity": "sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/proto-loader": "^0.7.8", + "@types/node": ">=12.12.47" + }, + "engines": { + "node": "^8.13.0 || >=10.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.7.13", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz", + "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==", + "license": "Apache-2.0", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.5", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -989,6 +1585,79 @@ "node": ">=14" } }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause" + }, + "node_modules/@remix-run/router": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.20.0.tgz", + "integrity": "sha512-mUnk8rPJBI9loFDZ+YzPGdeniYK+FTmRD1TMCz7ev2SNIozyKKpnGgsxO34u6Z4z/t0ITuu7voi/AshfsGsgFg==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.18.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz", @@ -1244,6 +1913,15 @@ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, + "node_modules/@types/node": { + "version": "22.7.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", + "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, "node_modules/@types/prop-types": { "version": "15.7.12", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", @@ -1335,7 +2013,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -1753,6 +2430,90 @@ "node": ">= 6" } }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/cliui/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/cliui/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==", + "license": "MIT" + }, + "node_modules/cliui/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==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/clsx": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", @@ -2190,7 +2951,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "dev": true, "engines": { "node": ">=6" } @@ -2563,6 +3323,18 @@ "reusify": "^1.0.4" } }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "license": "Apache-2.0", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -2603,6 +3375,42 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/firebase": { + "version": "10.14.1", + "resolved": "https://registry.npmjs.org/firebase/-/firebase-10.14.1.tgz", + "integrity": "sha512-0KZxU+Ela9rUCULqFsUUOYYkjh7OM1EWdIfG6///MtXd0t2/uUIf0iNV5i0KariMhRQ5jve/OY985nrAXFaZeQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/analytics": "0.10.8", + "@firebase/analytics-compat": "0.2.14", + "@firebase/app": "0.10.13", + "@firebase/app-check": "0.8.8", + "@firebase/app-check-compat": "0.3.15", + "@firebase/app-compat": "0.2.43", + "@firebase/app-types": "0.9.2", + "@firebase/auth": "1.7.9", + "@firebase/auth-compat": "0.5.14", + "@firebase/data-connect": "0.1.0", + "@firebase/database": "1.0.8", + "@firebase/database-compat": "1.0.8", + "@firebase/firestore": "4.7.3", + "@firebase/firestore-compat": "0.3.38", + "@firebase/functions": "0.11.8", + "@firebase/functions-compat": "0.3.14", + "@firebase/installations": "0.6.9", + "@firebase/installations-compat": "0.2.9", + "@firebase/messaging": "0.12.12", + "@firebase/messaging-compat": "0.2.12", + "@firebase/performance": "0.6.9", + "@firebase/performance-compat": "0.2.9", + "@firebase/remote-config": "0.4.9", + "@firebase/remote-config-compat": "0.2.9", + "@firebase/storage": "0.13.2", + "@firebase/storage-compat": "0.3.12", + "@firebase/util": "1.10.0", + "@firebase/vertexai-preview": "0.0.4" + } + }, "node_modules/flat-cache": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", @@ -2726,6 +3534,15 @@ "node": ">=6.9.0" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-intrinsic": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", @@ -2919,6 +3736,18 @@ "node": ">= 0.4" } }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "license": "MIT" + }, + "node_modules/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", + "license": "ISC" + }, "node_modules/ignore": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", @@ -3134,7 +3963,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" } @@ -3529,12 +4357,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==", + "license": "Apache-2.0" + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -4140,6 +4980,30 @@ "react-is": "^16.13.1" } }, + "node_modules/protobufjs": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz", + "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -4207,6 +5071,38 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "6.27.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.27.0.tgz", + "integrity": "sha512-YA+HGZXz4jaAkVoYBE98VQl+nVzI+cVI2Oj/06F5ZM+0u3TgedN9Y9kmMRo2mnkSK2nCpNQn0DVob4HCsY/WLw==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.20.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.27.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.27.0.tgz", + "integrity": "sha512-+bvtFWMC0DgAFrfKXKG9Fc+BcXWRUO1aJIihbB79xaeq0v5UzfvnM5houGUm1Y461WVRcgAQ+Clh5rdb1eCx4g==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.20.0", + "react-router": "6.27.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/react-toastify": { "version": "9.1.3", "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-9.1.3.tgz", @@ -4279,6 +5175,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve": { "version": "2.0.0-next.5", "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", @@ -4407,6 +5312,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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" + } + ], + "license": "MIT" + }, "node_modules/safe-regex-test": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", @@ -4677,7 +5602,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -4910,6 +5834,12 @@ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", "dev": true }, + "node_modules/tslib": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "license": "0BSD" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -5022,6 +5952,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.19.7.tgz", + "integrity": "sha512-HR3W/bMGPSr90i8AAp2C4DM3wChFdJPLrWYpIS++LxS8K+W535qftjt+4MyjNYHeWabMj1nvtmLIi7l++iq91A==", + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "license": "MIT" + }, "node_modules/update-browserslist-db": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", @@ -5134,6 +6079,29 @@ } } }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "license": "Apache-2.0", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -5370,6 +6338,15 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", @@ -5388,6 +6365,53 @@ "node": ">= 14" } }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/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==", + "license": "MIT" + }, + "node_modules/yargs/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==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 3dd7601..38dffac 100755 --- a/package.json +++ b/package.json @@ -11,8 +11,10 @@ }, "dependencies": { "dotenv": "^16.4.5", + "firebase": "^10.14.1", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-router-dom": "^6.27.0", "react-toastify": "^9.1.3", "uuid": "^9.0.1" }, @@ -29,4 +31,4 @@ "tailwindcss": "^3.4.1", "vite": "^5.1.4" } -} \ No newline at end of file +} diff --git a/src/App.jsx b/src/App.jsx index 3a26ccd..018dd1f 100755 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,20 +1,30 @@ -import { useState } from 'react' -import './App.css' -import Navbar from './components/Navbar' -import Manager from './components/Manager' -import Footer from './components/Footer' +import { BrowserRouter as Router, Route, Routes, Navigate } from 'react-router-dom'; +import { useState } from 'react'; +import './App.css'; +import Navbar from './components/Navbar'; +import Manager from './components/Manager'; +import Footer from './components/Footer'; +import SignIn from './components/SignIn'; +import SignUp from './components/SignUp'; function App() { - return ( - <> + - + + } /> + } /> + } /> + {/* Redirect to Manager if no match */} + } /> + - > - ) + + ); } -export default App \ No newline at end of file + + +export default App; diff --git a/src/browser-extension/background.js b/src/browser-extension/background.js new file mode 100644 index 0000000..1a0b85e --- /dev/null +++ b/src/browser-extension/background.js @@ -0,0 +1,3 @@ +chrome.runtime.onInstalled.addListener(() => { + console.log("PassOP Autofill Extension installed."); +}); diff --git a/src/browser-extension/content.js b/src/browser-extension/content.js new file mode 100644 index 0000000..618855a --- /dev/null +++ b/src/browser-extension/content.js @@ -0,0 +1,12 @@ +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + if (request.action === "autofill") { + const usernameField = document.querySelector("input[type='email'], input[type='text']"); + const passwordField = document.querySelector("input[type='password']"); + + if (usernameField && passwordField) { + usernameField.value = request.username; + passwordField.value = request.password; + sendResponse({ status: "filled" }); + } + } +}); diff --git a/src/browser-extension/manifest.json b/src/browser-extension/manifest.json new file mode 100644 index 0000000..1162095 --- /dev/null +++ b/src/browser-extension/manifest.json @@ -0,0 +1,18 @@ +{ + "manifest_version": 3, + "name": "PassOP AutoFill", + "version": "1.0", + "permissions": ["storage", "activeTab", "scripting"], + "action": { + "default_popup": "popup.html" + }, + "background": { + "service_worker": "background.js" + }, + "content_scripts": [ + { + "matches": [""], + "js": ["content.js"] + } + ] +} diff --git a/src/browser-extension/popup.html b/src/browser-extension/popup.html new file mode 100644 index 0000000..32398cb --- /dev/null +++ b/src/browser-extension/popup.html @@ -0,0 +1,10 @@ + + + PassOP Autofill + + + Fetch Credentials + + + + diff --git a/src/browser-extension/popup.js b/src/browser-extension/popup.js new file mode 100644 index 0000000..c153bc9 --- /dev/null +++ b/src/browser-extension/popup.js @@ -0,0 +1,16 @@ +document.getElementById("fetch").addEventListener("click", () => { + const site = document.getElementById("site").value; + + // Fetch credentials from backend (e.g., your API) + fetch(`https://your-backend-url/api/credentials?site=${site}`) + .then(response => response.json()) + .then(data => { + chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => { + chrome.tabs.sendMessage(tabs[0].id, { + action: "autofill", + username: data.username, + password: data.password + }); + }); + }); +}); diff --git a/src/components/Manager.jsx b/src/components/Manager.jsx index 9f8ad20..11bd5b7 100755 --- a/src/components/Manager.jsx +++ b/src/components/Manager.jsx @@ -8,7 +8,7 @@ const Manager = () => { const ref = useRef(); const passwordRef = useRef(); const [form, setForm] = useState({ - id: "", + _id: "", site: "", username: "", password: "", @@ -131,7 +131,6 @@ const Manager = () => { return; // Exit if there are validation errors } - // Proceed to save the password if all validations pass if (form.id) { const updatedPasswords = passwordArray.map((item) => item._id === form.id ? { ...form } : item @@ -191,7 +190,7 @@ const Manager = () => { }; const editPassword = (id) => { - const passwordToEdit = passwordArray.find((item) => item.id === id); + const passwordToEdit = passwordArray.find((item) => item._id === id); setForm({ ...passwordToEdit }); }; @@ -359,7 +358,7 @@ const Manager = () => { src="https://cdn.lordicon.com/jgnvfzqg.json" trigger="hover" > - {form.id ? "Update" : "Save"} + {form._id ? "Update" : "Save"} { { - editPassword(item.id); + editPassword(item._id); }} > { + const { currentUser } = useAuth(); + const { userLoggedIn } = useAuth(); + const navigate = useNavigate(); // function to download passwords const downloadPasswords = async () => { try { @@ -105,6 +112,36 @@ const Navbar = () => { Import + {userLoggedIn ? + { doSignOut().then(() => { navigate('/login') }) }} // Navigate to the login page + className="flex justify-center items-center gap-2 font-semibold bg-green-500 hover:bg-green-600 rounded-full px-4 py-1 border border-green-900" + > + + Sign out + + : + navigate('/sign-in')} // Navigate to the login page + className="flex justify-center items-center gap-2 font-semibold bg-green-500 hover:bg-green-600 rounded-full px-4 py-1 border border-green-900" + > + + Sign in + + + + } + + + + {userLoggedIn ? + : ''} { + const { userLoggedIn } = useAuth(); + + const [email, setEmail] = useState('') + const [password, setPassword] = useState('') + const [isSigningIn, setIsSigningIn] = useState(false) + const [errorMessage, setErrorMessage] = useState('') + + const onSubmit = async (e) => { + e.preventDefault() + if (!isSigningIn) { + setIsSigningIn(true) + await doSignInWithEmailAndPassword(email, password) + // doSendEmailVerification() + } + } + + const onGoogleSignIn = (e) => { + e.preventDefault() + if (!isSigningIn) { + setIsSigningIn(true) + doSignInWithGoogle().catch(err => { + setIsSigningIn(false) + }) + } + } + if (userLoggedIn) { + return ; + } + + return ( + + + + + + Welcome Back + + + + + + Email + + { setEmail(e.target.value) }} + className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-green-600 shadow-sm rounded-lg transition duration-300" + /> + + + + + + Password + + { setPassword(e.target.value) }} + className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-green-600 shadow-sm rounded-lg transition duration-300" + /> + + + {errorMessage && ( + {errorMessage} + )} + + + {isSigningIn ? 'Signing In...' : 'Sign In'} + + + Don't have an account? Sign up + + OR + + { onGoogleSignIn(e) }} + className={`w-full flex items-center justify-center gap-x-3 py-2.5 border rounded-lg text-sm font-medium ${isSigningIn ? 'cursor-not-allowed' : 'hover:bg-gray-100 transition duration-300 active:bg-gray-100'}`}> + + + + + + + + + + + + + + {isSigningIn ? 'Signing In...' : 'Continue with Google'} + + + + + ) +} + +export default SignIn \ No newline at end of file diff --git a/src/components/SignUp.jsx b/src/components/SignUp.jsx new file mode 100644 index 0000000..c9da772 --- /dev/null +++ b/src/components/SignUp.jsx @@ -0,0 +1,107 @@ +import { useState } from 'react' +import { Navigate, Link } from 'react-router-dom' +import { useAuth } from '../contexts/authContext/index' +import { doCreateUserWithEmailAndPassword } from '../firebase/auth' + +const Register = () => { + + + const [email, setEmail] = useState('') + const [password, setPassword] = useState('') + const [confirmPassword, setconfirmPassword] = useState('') + const [isRegistering, setIsRegistering] = useState(false) + const [errorMessage, setErrorMessage] = useState('') + + const { userLoggedIn } = useAuth() + + const onSubmit = async (e) => { + e.preventDefault() + if (!isRegistering) { + setIsRegistering(true) + await doCreateUserWithEmailAndPassword(email, password) + } + } + + if (userLoggedIn) { + return ; + } + + return ( + <> + + + + + + Create a New Account + + + + + + + Email + + { setEmail(e.target.value) }} + className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:green-600 shadow-sm rounded-lg transition duration-300" + /> + + + + + Password + + { setPassword(e.target.value) }} + className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-green-600 shadow-sm rounded-lg transition duration-300" + /> + + + + + Confirm Password + + { setconfirmPassword(e.target.value) }} + className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-green-600 shadow-sm rounded-lg transition duration-300" + /> + + + {errorMessage && ( + {errorMessage} + )} + + + {isRegistering ? 'Signing Up...' : 'Sign Up'} + + + Already have an account? {' '} + Continue + + + + + > + ) +} + +export default Register \ No newline at end of file diff --git a/src/components/UserAccount.jsx b/src/components/UserAccount.jsx new file mode 100644 index 0000000..79fc571 --- /dev/null +++ b/src/components/UserAccount.jsx @@ -0,0 +1,30 @@ +import { useState } from 'react'; + +const UserAccount = ({ email, username }) => { + const [isHovered, setIsHovered] = useState(false); + + // Extract the first letter of the email for the avatar + const avatarLetter = email.charAt(0).toUpperCase(); + + return ( + + setIsHovered(true)} + onMouseLeave={() => setIsHovered(false)} + > + {avatarLetter} + + + {isHovered && ( + + PassOp Account + {email} + {username && {username}} + + )} + + ); +}; + +export default UserAccount; diff --git a/src/contexts/authContext/index.jsx b/src/contexts/authContext/index.jsx new file mode 100644 index 0000000..ecc4d83 --- /dev/null +++ b/src/contexts/authContext/index.jsx @@ -0,0 +1,63 @@ +import React, { useContext, useState, useEffect } from "react"; +import { auth } from "../../firebase/firebase"; +// import { GoogleAuthProvider } from "firebase/auth"; +import { onAuthStateChanged } from "firebase/auth"; + +const AuthContext = React.createContext(); + +export function useAuth() { + return useContext(AuthContext); +} + +export function AuthProvider({ children }) { + const [currentUser, setCurrentUser] = useState(null); + const [userLoggedIn, setUserLoggedIn] = useState(false); + const [isEmailUser, setIsEmailUser] = useState(false); + const [isGoogleUser, setIsGoogleUser] = useState(false); + const [loading, setLoading] = useState(true); + + useEffect(() => { + const unsubscribe = onAuthStateChanged(auth, initializeUser); + return unsubscribe; + }, []); + + async function initializeUser(user) { + if (user) { + + setCurrentUser({ ...user }); + + // check if provider is email and password login + const isEmail = user.providerData.some( + (provider) => provider.providerId === "password" + ); + setIsEmailUser(isEmail); + + // check if the auth provider is google or not + // const isGoogle = user.providerData.some( + // (provider) => provider.providerId === GoogleAuthProvider.PROVIDER_ID + // ); + // setIsGoogleUser(isGoogle); + + setUserLoggedIn(true); + } else { + setCurrentUser(null); + setUserLoggedIn(false); + } + + setLoading(false); + } + + const value = { + userLoggedIn, + isEmailUser, + isGoogleUser, + currentUser, + setCurrentUser + }; + + return ( + + {!loading && children} + + ); +} \ No newline at end of file diff --git a/src/firebase/auth.js b/src/firebase/auth.js new file mode 100644 index 0000000..925fd34 --- /dev/null +++ b/src/firebase/auth.js @@ -0,0 +1,44 @@ +import { auth } from "./firebase"; +import { + createUserWithEmailAndPassword, + signInWithEmailAndPassword, + sendPasswordResetEmail, + sendEmailVerification, + updatePassword, + signInWithPopup, + GoogleAuthProvider, +} from "firebase/auth"; + +export const doCreateUserWithEmailAndPassword = async (email, password) => { + return createUserWithEmailAndPassword(auth, email, password); +}; + +export const doSignInWithEmailAndPassword = (email, password) => { + return signInWithEmailAndPassword(auth, email, password); +}; + +export const doSignInWithGoogle = async () => { + const provider = new GoogleAuthProvider(); + const result = await signInWithPopup(auth, provider); + const user = result.user; + + // add user to firestore +}; + +export const doSignOut = () => { + return auth.signOut(); +}; + +export const doPasswordReset = (email) => { + return sendPasswordResetEmail(auth, email); +}; + +export const doPasswordChange = (password) => { + return updatePassword(auth.currentUser, password); +}; + +export const doSendEmailVerification = () => { + return sendEmailVerification(auth.currentUser, { + url: `${window.location.origin}/home`, + }); +}; \ No newline at end of file diff --git a/src/firebase/firebase.js b/src/firebase/firebase.js new file mode 100644 index 0000000..0d4bf28 --- /dev/null +++ b/src/firebase/firebase.js @@ -0,0 +1,22 @@ +// Import the functions you need from the SDKs you need +import { initializeApp } from "firebase/app"; +import { getAuth } from "firebase/auth" + + +// Your web app's Firebase configuration +// Create an accont on firebase and you get all this configuration just replace that with this +// Then your sign-in / sign-up feature will work smothly +const firebaseConfig = { + apiKey: "YOUR_API_KEY", + authDomain: "YOUR_AUTH_DOMAIN", + projectId: "PROJECT_ID", + storageBucket: "SOCKET_BUTTON", + messagingSenderId: "SENDER_ID", + appId: "APP_ID", + measurementId: "MEASUREMENT_ID" +}; + +// Initialize Firebase +const app = initializeApp(firebaseConfig); +const auth = getAuth(app); +export { auth, app }; \ No newline at end of file diff --git a/src/main.jsx b/src/main.jsx index 0291fe5..491d31f 100755 --- a/src/main.jsx +++ b/src/main.jsx @@ -2,9 +2,12 @@ import React from 'react' import ReactDOM from 'react-dom/client' import App from './App.jsx' import './index.css' +import { AuthProvider } from './contexts/authContext/index.jsx' ReactDOM.createRoot(document.getElementById('root')).render( - + + + , ) \ No newline at end of file
Don't have an account? Sign up