diff --git a/dev/package.json b/dev/package.json index e0bb2bd..a389279 100644 --- a/dev/package.json +++ b/dev/package.json @@ -28,6 +28,7 @@ }, "devDependencies": { "@types/express": "^4.17.9", + "@types/qrcode": "^1.5.5", "copyfiles": "^2.4.1", "nodemon": "^2.0.6", "ts-node": "^9.1.1", diff --git a/package.json b/package.json index b85b559..ebd9151 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "@types/node": "18.11.3", "@types/notp": "^2.0.5", "@types/passport-strategy": "^0.2.38", + "@types/qrcode.react": "^1.0.5", "@types/react": "18.0.21", "assert": "^2.1.0", "body-parser": "^1.20.2", @@ -73,6 +74,7 @@ "nanoid": "^3.0.0", "neotp": "^3.0.0", "passport-strategy": "^1.0.0", + "qrcode.react": "^3.1.0", "querystring-es3": "^0.2.1", "react-cookie": "^7.1.4", "react-router-dom": "^6.23.1", diff --git a/src/components/fields/afterInput/MFAKey.tsx b/src/components/fields/afterInput/MFAKey.tsx new file mode 100644 index 0000000..f3f7183 --- /dev/null +++ b/src/components/fields/afterInput/MFAKey.tsx @@ -0,0 +1,34 @@ +import React, { useState } from 'react' +import { QRCodeSVG } from 'qrcode.react' + +const MFAKey: React.FC = () => { + const [showQRCode, setShowQRCode] = useState(false) + + const email = (document.getElementById('field-email') as HTMLInputElement)?.value + const secret = (document.getElementById('field-mfa_key') as HTMLInputElement)?.value + + // Return null if email or secret is not available + if (!email || !secret) { + return null + } + + const toggleQRCode = (e) => { + e.preventDefault() + setShowQRCode(prevShowQRCode => !prevShowQRCode) + } + + return ( +
+ + {showQRCode ? 'Hide QR Code' : 'Show QR Code'} + + {showQRCode && ( +
+ +
+ )} +
+ ) +} + +export default MFAKey diff --git a/src/plugin.ts b/src/plugin.ts index ae1e896..b9a7c66 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -17,6 +17,7 @@ import { loginResponseEndpoint, registerChallengeEndpoint, registerResponseEndpoint, } from './endpoints/Endpoints' +import MFAKey from "./components/fields/afterInput/MFAKey"; export const payloadWebAuthn: (pluginOptions: PluginTypes) => Plugin = (pluginOptions) => async (incomingConfig) => { let config: Config = {...incomingConfig} @@ -120,6 +121,9 @@ export const payloadWebAuthn: (pluginOptions: PluginTypes) => Plugin = (pluginOp required: true, admin: { readOnly: true, + components: { + afterInput: [MFAKey] + } }, defaultValue: () => generateSecret(20), }, diff --git a/yarn.lock b/yarn.lock index c585e18..e4335d9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1405,6 +1405,13 @@ resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz" integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q== +"@types/qrcode.react@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/qrcode.react/-/qrcode.react-1.0.5.tgz#d4ddcacee8f34d22a663029a230c5f0ab908cfb7" + integrity sha512-BghPtnlwvrvq8QkGa1H25YnN+5OIgCKFuQruncGWLGJYOzeSKiix/4+B9BtfKF2wf5ja8yfyWYA3OXju995G8w== + dependencies: + "@types/react" "*" + "@types/qs@*": version "6.9.15" resolved "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz" @@ -6343,6 +6350,11 @@ pvutils@^1.1.3: resolved "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz" integrity sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ== +qrcode.react@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/qrcode.react/-/qrcode.react-3.1.0.tgz#5c91ddc0340f768316fbdb8fff2765134c2aecd8" + integrity sha512-oyF+Urr3oAMUG/OiOuONL3HXM+53wvuH3mtIWQrYmsXoAq0DkvZp2RYUWFSMFtbdOpuS++9v+WAkzNVkMlNW6Q== + qs-middleware@1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/qs-middleware/-/qs-middleware-1.0.3.tgz"