diff --git a/containers/api/package-lock.json b/containers/api/package-lock.json index 4281bf54..5821b426 100644 --- a/containers/api/package-lock.json +++ b/containers/api/package-lock.json @@ -19,6 +19,8 @@ "base32-decode": "^1.0.0", "base32-encode": "^2.0.0", "express-session": "^1.17.3", + "hi-base32": "^0.5.1", + "nanoid": "^3.3.4", "passport": "^0.6.0", "passport-jwt": "^4.0.1", "passport-local": "^1.0.0", @@ -26,6 +28,7 @@ "qrcode": "^1.5.3", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1", + "thirty-two": "^1.0.2", "typeorm": "^0.3.15", "webpack": "^5.82.0" }, @@ -4955,6 +4958,11 @@ "node": ">=8" } }, + "node_modules/hi-base32": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/hi-base32/-/hi-base32-0.5.1.tgz", + "integrity": "sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA==" + }, "node_modules/highlight.js": { "version": "10.7.3", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", @@ -6457,6 +6465,17 @@ "thenify-all": "^1.0.0" } }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -8296,6 +8315,14 @@ "node": ">=0.8" } }, + "node_modules/thirty-two": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/thirty-two/-/thirty-two-1.0.2.tgz", + "integrity": "sha512-OEI0IWCe+Dw46019YLl6V10Us5bi574EvlJEOcAkB29IzQ/mYD1A6RyNHLjZPiHCmuodxvgF6U+vZO1L15lxVA==", + "engines": { + "node": ">=0.2.6" + } + }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", diff --git a/containers/api/package.json b/containers/api/package.json index d161cf6b..28893ce0 100644 --- a/containers/api/package.json +++ b/containers/api/package.json @@ -30,6 +30,8 @@ "base32-decode": "^1.0.0", "base32-encode": "^2.0.0", "express-session": "^1.17.3", + "hi-base32": "^0.5.1", + "nanoid": "^3.3.4", "passport": "^0.6.0", "passport-jwt": "^4.0.1", "passport-local": "^1.0.0", @@ -37,6 +39,7 @@ "qrcode": "^1.5.3", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1", + "thirty-two": "^1.0.2", "typeorm": "^0.3.15", "webpack": "^5.82.0" }, diff --git a/containers/api/qrcode.png b/containers/api/qrcode.png new file mode 100644 index 00000000..9a058f51 Binary files /dev/null and b/containers/api/qrcode.png differ diff --git a/containers/api/src/users/2fa.ts b/containers/api/src/users/2fa.ts index 845806a3..2f1a3147 100644 --- a/containers/api/src/users/2fa.ts +++ b/containers/api/src/users/2fa.ts @@ -1,6 +1,9 @@ import crypto from 'crypto'; import base32Decode from 'base32-decode'; +// import { randomBytes} from 'crypto'; +// import { promisify } from 'util'; + // export function generateHOTP(secret, counter) { // const decodedSecret = base32Decode(secret, 'RFC4648'); @@ -28,7 +31,7 @@ import base32Decode from 'base32-decode'; // return `${code % 10 ** 6}`.padStart(6, '0'); // } -type QRcode = any +// type QRcode = any; export function generateHOTP(secret, counter) { const decodedSecret = base32Decode(secret, 'RFC4648'); @@ -89,24 +92,40 @@ export function verifyTOTP(token, secret, window = 1) // import { Response } from 'express'; // import { Readable } from 'stream'; // import * as base32Encode from 'base32-encode'; +// import { base32Encode } from 'base32-encode'; +// import base32Encode from 'base32-encode'; +import { encode } from 'thirty-two'; + +// ... + +import * as qrcode from 'qrcode'; +import * as fs from 'fs'; + + +import { nanoid } from "nanoid"; +// import * as nanoid from 'nanoid' export async function generateQRcode(req) { - // const base32Encode = await import('base32-encode'); - const base32Encode = (await import('base32-encode')); - const util = (await import('util')); - const qrcode = (await import('qrcode')); + // const base32Encode = (await import('base32-encode')); + // const nanoid = (await import('nanoid')); + + // const util = (await import('util')); + // const qrcode = (await import('qrcode')); + const user = req.user; - let res: QRcode; + let res; // For security, we no longer show the QR code after is verified // if (user.mfaEnabled) return res.status(404).end(); - + // if (!user.mfaSecret) { //to do - - // generate unique secret for user - // this secret will be used to check the verification code sent by user - const buffer = await util.promisify(crypto.randomBytes)(14); - user.mfaSecret = base32Encode(buffer, 'RFC4648', { padding: false }); + const buffer = nanoid(14); + // generate unique secret for user + // this secret will be used to check the verification code sent by user + // const buffer = await util.promisify(crypto.randomBytes)(14); + // const buffer = crypto.lib.WordArray.random(32) + user.mfaSecret = encode(buffer).toString('utf8'); + // user.mfaSecret = base32Encoded(buffer, 'RFC4648', { padding: false }); // setUser(user); // to do !! @@ -121,8 +140,40 @@ export async function generateQRcode(req) const configUri = `otpauth://${otpType}/${issuer}:${user.username}?algorithm=${algorithm}&digits=${digits}&period=${period}&issuer=${issuer}&secret=${user.mfaSecret}`; // res.setHeader('Content-Type', 'image/png'); + const QRCode = require('qrcode'); + console.log(`before done`); + // QRCode.toFileStream(res, configUri); + // const filePath = 'qrcode.png'; // Specify the file path where the QR code should be saved + + + const qrCodeData = buffer; // Replace with your actual QR code data + const filePath = 'qrcode.png'; // Specify the file path where the QR code should be saved - qrcode.toFileStream(res, configUri); + qrcode.toFile(filePath, qrCodeData, (error) => { + if (error) { + console.error(error); + // Handle the error appropriately + return; + } + // QR code image has been generated and saved to the file + // Or, you can create a buffer of the image data directly + }) + +// qrcode.toFile(filePath, configUri, (error) => { +// if (error) { +// console.error(error); +// // Handle the error appropriately +// return; +// } +// const readableStream = fs.createReadStream(filePath); +// res.data = readableStream; + // Use the readable stream as needed +// }); + + + + // qrcode.toFileStream(res, configUri); console.log(`QRcode done`); return res; + // return } \ No newline at end of file diff --git a/containers/react/src/pages/2fa.js b/containers/react/src/pages/2fa.js index 79847689..9cc51df6 100644 --- a/containers/react/src/pages/2fa.js +++ b/containers/react/src/pages/2fa.js @@ -1,81 +1,146 @@ import React, { useCallback, useState, useEffect } from 'react'; import api from '../script/axiosApi'; -function DoubleAuth() { +// function DoubleAuth() { -// const enabled = await api.get("/2fa"); +// // const enabled = await api.get("/2fa"); -// const response = await api.get("/2fa"); -// const enabled = response.data; -// console.log(`enable= ${enabled.data}`) - // const enabled = 0; - let enabled; +// // const response = await api.get("/2fa"); +// // const enabled = response.data; +// // console.log(`enable= ${enabled.data}`) +// // const enabled = 0; +// let enabled; +// useEffect(() => { +// async function get2fa() +// { +// const response = await api.get("/2fa"); +// const enabled = response.data; +// console.log(`enable= ${enabled.data}`) +// } +// // const enabled = 0; +// }, []) + + + + // useEffect(() => { + // async function get2fa() + // { + // api.get('/api/QRcode', { responseType: 'blob' }) + // .then(response => { + // const reader = new FileReader(); + // reader.onloadend = () => { + // setImageSrc(reader.result); + // }; + // reader.readAsDataURL(response.data); + // }) + // .catch(error => { + // console.error(error); + // }); + + // } }, []); + +// // const [verificationCode, setVerificationCode] = useState(''); +// // const [invalidCode, setInvalidCode] = useState(false); + +// const handleSubmit = () => { +// // async (e) => { +// // e.preventDefault(); + +// // const result = await verifyOtp(verificationCode); + +// // if (result) return (window.location = '/'); + +// // setInvalidCode(true); +// // }, +// // [verificationCode] +// }; + +// let sourceCode + +// if (!enabled) +// { +// api.get('/QRcode') +// .then(response => { +// sourceCode = response.data; +// console.log(sourceCode); +// }) +// .catch(error => { +// console.error(error); +// }); +// } + +// return ( +//
+// {!enabled && ( +//
+//

Scan the QR code on your authenticator app

+// +//
+// )} + +//
+// {/* setVerificationCode(e.target.value)} +// /> */} + +// + +// {/* {invalidCode &&

Invalid verification code

} */} +//
+//
+// ); +// } + + +// import { toFileStream } from 'qrcode'; + +const DoubleAuth = () => { + const [imageSrc, setImageSrc] = useState(''); + useEffect(() => { - async function get2fa() - { - const response = await api.get("/2fa"); - const enabled = response.data; - console.log(`enable= ${enabled.data}`) - } - // const enabled = 0; - }, []) - - -// const [verificationCode, setVerificationCode] = useState(''); -// const [invalidCode, setInvalidCode] = useState(false); - - const handleSubmit = () => { - // async (e) => { - // e.preventDefault(); - - // const result = await verifyOtp(verificationCode); - - // if (result) return (window.location = '/'); - - // setInvalidCode(true); - // }, - // [verificationCode] - }; - - let sourceCode - - if (!enabled) - { - api.get('/QRcode') - .then(response => { - sourceCode = response.data; - console.log(sourceCode); - }) - .catch(error => { - console.error(error); - }); + async function getCode(){ + await api.get('/QRcode', { responseType: 'blob' }) + .then(response => { + const reader = new FileReader(); + reader.onloadend = () => { + setImageSrc(reader.result); + }; + reader.readAsDataURL(response.data); + }) + .catch(error => { + console.error(error); + }); } + getCode(); +}, []); + + // return ( + //
+ // {imageSrc && QR Code} + //
+ // ); - return ( -
- {!enabled && ( -
-

Scan the QR code on your authenticator app

- -
- )} + // -
- {/* setVerificationCode(e.target.value)} - /> */} + return ( +
+
+

Scan the QR code on your authenticator app

+ {imageSrc && QR Code} +
+ {/* + + */} +
+ ); - - {/* {invalidCode &&

Invalid verification code

} */} - -
- ); -} + }; -export default DoubleAuth; \ No newline at end of file + + export default DoubleAuth; \ No newline at end of file diff --git a/containers/react/src/pages/canvas.js b/containers/react/src/pages/canvas.js index 82226953..2ee7fd65 100644 --- a/containers/react/src/pages/canvas.js +++ b/containers/react/src/pages/canvas.js @@ -386,11 +386,11 @@ requestAnimationFrame(draw); vY = -vY; // send_info(); } - else if (ballX + ballRadius + 2 >= canvas.width) //touch right wall - { - vX = -vX; - // send_info(); - } + // else if (ballX + ballRadius + 2 >= canvas.width) //touch right wall + // { + // vX = -vX; + // // send_info(); + // } } function is_out()