From 270e59d9ea01c1a1cc4d456266eeaecb5b938fb0 Mon Sep 17 00:00:00 2001 From: henrygd Date: Sun, 7 Sep 2025 20:46:34 -0400 Subject: [PATCH] add support for otp and mfa --- src/site/bun.lockb | Bin 224846 -> 225313 bytes src/site/package-lock.json | 167 +++++++++++--------- src/site/package.json | 1 + src/site/src/components/login/auth-form.tsx | 51 ++++-- src/site/src/components/login/login.tsx | 7 +- src/site/src/components/login/otp-forms.tsx | 106 +++++++++++++ src/site/src/components/router.tsx | 1 + src/site/src/components/ui/otp.tsx | 66 ++++++++ 8 files changed, 305 insertions(+), 94 deletions(-) create mode 100644 src/site/src/components/login/otp-forms.tsx create mode 100644 src/site/src/components/ui/otp.tsx diff --git a/src/site/bun.lockb b/src/site/bun.lockb index 98e3b25897c8161d9e7226697bf8b0735e2052c1..19985005c1fa2a9b1c51c94364be876871ffa1ca 100755 GIT binary patch delta 39071 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 W19|FQb>F^2s=dO#{vWDGH~ue>0zQ5K diff --git a/src/site/package-lock.json b/src/site/package-lock.json index 51f3277..86a064c 100644 --- a/src/site/package-lock.json +++ b/src/site/package-lock.json @@ -35,6 +35,7 @@ "clsx": "^2.1.1", "cmdk": "^1.1.1", "d3-time": "^3.1.0", + "input-otp": "^1.4.2", "lucide-react": "^0.452.0", "nanostores": "^0.11.4", "pocketbase": "^0.26.2", @@ -67,7 +68,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -81,7 +82,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", @@ -96,7 +97,7 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -106,7 +107,7 @@ "version": "7.28.3", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.3.tgz", "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", @@ -137,7 +138,7 @@ "version": "7.28.3", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.28.3", @@ -154,7 +155,7 @@ "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.27.2", @@ -171,7 +172,7 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -181,7 +182,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.27.1", @@ -195,7 +196,7 @@ "version": "7.28.3", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.27.1", @@ -213,7 +214,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -223,7 +224,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -233,7 +234,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -243,7 +244,7 @@ "version": "7.28.3", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.3.tgz", "integrity": "sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.27.2", @@ -257,7 +258,7 @@ "version": "7.28.3", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.3.tgz", "integrity": "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.28.2" @@ -285,7 +286,7 @@ "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -300,7 +301,7 @@ "version": "7.28.3", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.3.tgz", "integrity": "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -319,7 +320,7 @@ "version": "7.28.2", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -855,7 +856,7 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@sinclair/typebox": "^0.27.8" @@ -868,7 +869,7 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "^29.6.3", @@ -886,7 +887,7 @@ "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", @@ -908,7 +909,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -918,14 +919,14 @@ "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.30", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -946,7 +947,7 @@ "version": "5.4.1", "resolved": "https://registry.npmjs.org/@lingui/babel-plugin-lingui-macro/-/babel-plugin-lingui-macro-5.4.1.tgz", "integrity": "sha512-9IO+PDvdneY8OCI8zvI1oDXpzryTMtyRv7uq9O0U1mFCvIPVd5dWQKQDu/CpgpYAc2+JG/izn5PNl9xzPc6ckw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.20.12", @@ -1166,7 +1167,7 @@ "version": "5.4.1", "resolved": "https://registry.npmjs.org/@lingui/conf/-/conf-5.4.1.tgz", "integrity": "sha512-aDkj/bMSr/mCL8Nr1TS52v0GLCuVa4YqtRz+WvUCFZw/ovVInX0hKq1TClx/bSlhu60FzB/CbclxFMBw8aLVUg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@babel/runtime": "^7.20.13", @@ -2585,7 +2586,7 @@ "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@swc/core": { @@ -3255,14 +3256,14 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@types/istanbul-lib-coverage": "*" @@ -3272,7 +3273,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@types/istanbul-lib-report": "*" @@ -3282,7 +3283,7 @@ "version": "24.3.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz", "integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "undici-types": "~7.10.0" @@ -3292,7 +3293,7 @@ "version": "19.1.11", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.11.tgz", "integrity": "sha512-lr3jdBw/BGj49Eps7EvqlUaoeA0xpj3pc0RoJkHpYaCHkVK7i28dKyImLQb3JVlqs3aYSXf7qYuWOW/fgZnTXQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "csstype": "^3.0.2" @@ -3302,7 +3303,7 @@ "version": "19.1.7", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.7.tgz", "integrity": "sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw==", - "devOptional": true, + "dev": true, "license": "MIT", "peerDependencies": { "@types/react": "^19.0.0" @@ -3312,7 +3313,7 @@ "version": "17.0.33", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@types/yargs-parser": "*" @@ -3322,7 +3323,7 @@ "version": "21.0.3", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@vitejs/plugin-react-swc": { @@ -3359,7 +3360,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -3402,7 +3403,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "devOptional": true, + "dev": true, "license": "Python-2.0" }, "node_modules/aria-hidden": { @@ -3497,7 +3498,7 @@ "version": "4.25.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", - "devOptional": true, + "dev": true, "funding": [ { "type": "opencollective", @@ -3568,7 +3569,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -3578,7 +3579,7 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -3591,7 +3592,7 @@ "version": "1.0.30001727", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz", "integrity": "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==", - "devOptional": true, + "dev": true, "funding": [ { "type": "opencollective", @@ -3612,7 +3613,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -3724,7 +3725,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -3737,7 +3738,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/colors": { @@ -3754,14 +3755,14 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/cosmiconfig": { "version": "8.3.6", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "import-fresh": "^3.3.0", @@ -3941,7 +3942,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -4011,7 +4012,7 @@ "version": "1.5.182", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.182.tgz", "integrity": "sha512-Lv65Btwv9W4J9pyODI6EWpdnhfvrve/us5h1WspW8B2Fb0366REPtY3hX7ounk1CkV/TBjWCEvCBBbYbmV0qCA==", - "devOptional": true, + "dev": true, "license": "ISC" }, "node_modules/emoji-regex": { @@ -4039,7 +4040,7 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" @@ -4108,7 +4109,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -4196,7 +4197,7 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -4222,7 +4223,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -4253,7 +4254,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -4273,6 +4274,16 @@ "dev": true, "license": "ISC" }, + "node_modules/input-otp": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/input-otp/-/input-otp-1.4.2.tgz", + "integrity": "sha512-l3jWwYNvrEa6NTCt7BECfCm48GvwuZzkoeG3gBL2w4CHeOXW3eKFmf9UNYkNfYc3mxMrthMnxjIE07MT0zLBQA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" + } + }, "node_modules/internmap": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", @@ -4286,7 +4297,7 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/is-binary-path": { @@ -4379,7 +4390,7 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -4389,7 +4400,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", @@ -4407,7 +4418,7 @@ "version": "1.21.7", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", - "devOptional": true, + "dev": true, "license": "MIT", "bin": { "jiti": "bin/jiti.js" @@ -4429,7 +4440,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -4442,7 +4453,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "devOptional": true, + "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -4455,14 +4466,14 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "devOptional": true, + "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -4475,7 +4486,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -4724,7 +4735,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/lodash": { @@ -4773,7 +4784,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "devOptional": true, + "dev": true, "license": "ISC", "dependencies": { "yallist": "^3.0.2" @@ -4884,7 +4895,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/nanoid": { @@ -4925,7 +4936,7 @@ "version": "2.0.19", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/normalize-path": { @@ -5021,7 +5032,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -5034,7 +5045,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", @@ -5063,7 +5074,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -5073,7 +5084,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "devOptional": true, + "dev": true, "license": "ISC" }, "node_modules/picomatch": { @@ -5135,7 +5146,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "^29.6.3", @@ -5150,7 +5161,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -5396,7 +5407,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -5494,7 +5505,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "devOptional": true, + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -5677,7 +5688,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -5811,7 +5822,7 @@ "version": "5.9.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -5825,14 +5836,14 @@ "version": "7.10.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/update-browserslist-db": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", - "devOptional": true, + "dev": true, "funding": [ { "type": "opencollective", @@ -6164,7 +6175,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "devOptional": true, + "dev": true, "license": "ISC" } } diff --git a/src/site/package.json b/src/site/package.json index 648023f..64c7d49 100644 --- a/src/site/package.json +++ b/src/site/package.json @@ -38,6 +38,7 @@ "clsx": "^2.1.1", "cmdk": "^1.1.1", "d3-time": "^3.1.0", + "input-otp": "^1.4.2", "lucide-react": "^0.452.0", "nanostores": "^0.11.4", "pocketbase": "^0.26.2", diff --git a/src/site/src/components/login/auth-form.tsx b/src/site/src/components/login/auth-form.tsx index c17b79f..49709b9 100644 --- a/src/site/src/components/login/auth-form.tsx +++ b/src/site/src/components/login/auth-form.tsx @@ -4,7 +4,7 @@ import { cn } from "@/lib/utils" import { buttonVariants } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" -import { LoaderCircle, LockIcon, LogInIcon, MailIcon } from "lucide-react" +import { KeyIcon, LoaderCircle, LockIcon, LogInIcon, MailIcon } from "lucide-react" import { $authenticated } from "@/lib/stores" import * as v from "valibot" import { toast } from "../ui/use-toast" @@ -14,6 +14,7 @@ import { AuthMethodsList, AuthProviderInfo, OAuth2AuthConfig } from "pocketbase" import { $router, Link, prependBasePath } from "../router" import { getPagePath } from "@nanostores/router" import { pb } from "@/lib/api" +import { OtpInputForm } from "./otp-forms" const honeypot = v.literal("") const emailSchema = v.pipe(v.string(), v.email(t`Invalid email address.`)) @@ -36,10 +37,11 @@ const RegisterSchema = v.looseObject({ passwordConfirm: passwordSchema, }) -const showLoginFaliedToast = () => { +export const showLoginFaliedToast = (description?: string) => { + description ||= t`Please check your credentials and try again` toast({ title: t`Login attempt failed`, - description: t`Please check your credentials and try again`, + description, variant: "destructive", }) } @@ -65,6 +67,8 @@ export function UserAuthForm({ const [isLoading, setIsLoading] = useState(false) const [isOauthLoading, setIsOauthLoading] = useState(false) const [errors, setErrors] = useState>({}) + const [mfaId, setMfaId] = useState() + const [otpId, setOtpId] = useState() const handleSubmit = useCallback( async (e: React.FormEvent) => { @@ -106,17 +110,19 @@ export function UserAuthForm({ } $authenticated.set(true) } catch (err: any) { - showLoginFaliedToast() - // todo: implement MFA - // const mfaId = err.response?.mfaId - // if (!mfaId) { - // showLoginFaliedToast() - // throw err - // } - // the user needs to authenticate again with another auth method, for example OTP - // const result = await pb.collection("users").requestOTP(email) - // ... show a modal for users to check their email and to enter the received code ... - // await pb.collection("users").authWithOTP(result.otpId, "EMAIL_CODE", { mfaId: mfaId }) + const mfaId = err?.response?.mfaId + if (!mfaId) { + showLoginFaliedToast() + throw err + } + setMfaId(mfaId) + try { + const { otpId } = await pb.collection("users").requestOTP(email) + setOtpId(otpId) + } catch (err) { + console.log({ err }) + showLoginFaliedToast() + } } finally { setIsLoading(false) } @@ -131,6 +137,8 @@ export function UserAuthForm({ const authProviders = authMethods.oauth2.providers ?? [] const oauthEnabled = authMethods.oauth2.enabled && authProviders.length > 0 const passwordEnabled = authMethods.password.enabled + const otpEnabled = authMethods.otp.enabled + const mfaEnabled = authMethods.mfa.enabled function loginWithOauth(provider: AuthProviderInfo, forcePopup = false) { setIsOauthLoading(true) @@ -173,6 +181,10 @@ export function UserAuthForm({ } }, []) + if (otpId && mfaId) { + return + } + return (
{passwordEnabled && ( @@ -249,7 +261,7 @@ export function UserAuthForm({
- {(isFirstRun || oauthEnabled) && ( + {(isFirstRun || oauthEnabled || (otpEnabled && !mfaEnabled)) && ( // only show 'continue with' during onboarding or if we have auth providers
@@ -264,6 +276,15 @@ export function UserAuthForm({ )} )} + {/* hide OTP button if MFA is enabled (it will be used as MFA) */} + {otpEnabled && !mfaEnabled && ( +
+ + + One-time password + +
+ )} {oauthEnabled && (
{authMethods.oauth2.providers.map((provider) => ( diff --git a/src/site/src/components/login/login.tsx b/src/site/src/components/login/login.tsx index 38e4754..30ae6cf 100644 --- a/src/site/src/components/login/login.tsx +++ b/src/site/src/components/login/login.tsx @@ -9,6 +9,7 @@ import { AuthMethodsList } from "pocketbase" import { useTheme } from "../theme-provider" import { pb } from "@/lib/api" import { ModeToggle } from "../mode-toggle" +import { OtpRequestForm } from "./otp-forms" export default function () { const page = useStore($router) @@ -37,6 +38,8 @@ export default function () { return t`Please create an admin account` } else if (page?.route === "forgot_password") { return t`Enter email address to reset password` + } else if (page?.route === "request_otp") { + return t`Request a one-time password` } else { return t`Please sign in to your account` } @@ -51,7 +54,7 @@ export default function () {
@@ -65,6 +68,8 @@ export default function () {
{page?.route === "forgot_password" ? ( + ) : page?.route === "request_otp" ? ( + ) : ( )} diff --git a/src/site/src/components/login/otp-forms.tsx b/src/site/src/components/login/otp-forms.tsx new file mode 100644 index 0000000..e6f01b2 --- /dev/null +++ b/src/site/src/components/login/otp-forms.tsx @@ -0,0 +1,106 @@ +import { useCallback, useState } from "react" +import { pb } from "@/lib/api" +import { $authenticated } from "@/lib/stores" +import { InputOTP, InputOTPGroup, InputOTPSlot } from "@/components/ui/otp" +import { Trans } from "@lingui/react/macro" +import { showLoginFaliedToast } from "./auth-form" +import { cn } from "@/lib/utils" +import { MailIcon, LoaderCircle, SendHorizonalIcon } from "lucide-react" +import { Label } from "../ui/label" +import { buttonVariants } from "../ui/button" +import { Input } from "../ui/input" +import { $router } from "../router" + +export function OtpInputForm({ otpId, mfaId }: { otpId: string; mfaId: string }) { + const [value, setValue] = useState("") + + if (value.length === 6) { + pb.collection("users") + .authWithOTP(otpId, value, { mfaId }) + .then(() => { + $router.open("/") + $authenticated.set(true) + }) + .catch((err) => { + showLoginFaliedToast(err.message) + }) + } + + return ( +
+ + + {Array.from({ length: 6 }).map((_, i) => ( + + ))} + + +
+ Enter your one-time password. +
+
+ ) +} + +export function OtpRequestForm() { + const [isLoading, setIsLoading] = useState(false) + const [email, setEmail] = useState("") + const [otpId, setOtpId] = useState() + + const handleSubmit = useCallback( + async (e: React.FormEvent) => { + e.preventDefault() + setIsLoading(true) + try { + // console.log(email) + const { otpId } = await pb.collection("users").requestOTP(email) + setOtpId(otpId) + } catch (e: any) { + showLoginFaliedToast(e?.message) + } finally { + setIsLoading(false) + setEmail("") + } + }, + [email] + ) + + if (otpId) { + return + } + + return ( +
+
+
+ + + setEmail(e.target.value)} + id="email" + name="email" + required + placeholder="name@example.com" + type="email" + autoCapitalize="none" + autoComplete="email" + autoCorrect="off" + disabled={isLoading} + className="ps-9" + /> +
+ +
+
+ ) +} diff --git a/src/site/src/components/router.tsx b/src/site/src/components/router.tsx index fcb5b55..8c82229 100644 --- a/src/site/src/components/router.tsx +++ b/src/site/src/components/router.tsx @@ -5,6 +5,7 @@ const routes = { system: `/system/:name`, settings: `/settings/:name?`, forgot_password: `/forgot-password`, + request_otp: `/request-otp`, } as const /** diff --git a/src/site/src/components/ui/otp.tsx b/src/site/src/components/ui/otp.tsx new file mode 100644 index 0000000..4511886 --- /dev/null +++ b/src/site/src/components/ui/otp.tsx @@ -0,0 +1,66 @@ +import * as React from "react" +import { OTPInput, OTPInputContext } from "input-otp" +import { MinusIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function InputOTP({ + className, + containerClassName, + ...props +}: React.ComponentProps & { + containerClassName?: string +}) { + return ( + + ) +} + +function InputOTPGroup({ className, ...props }: React.ComponentProps<"div">) { + return
+} + +function InputOTPSlot({ + index, + className, + ...props +}: React.ComponentProps<"div"> & { + index: number +}) { + const inputOTPContext = React.useContext(OTPInputContext) + const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {} + + return ( +
+ {char} + {hasFakeCaret && ( +
+
+
+ )} +
+ ) +} + +function InputOTPSeparator({ ...props }: React.ComponentProps<"div">) { + return ( +
+ +
+ ) +} + +export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator }