add 2fa start and change secret api key
This commit is contained in:
parent
fafecdacc3
commit
e5e77f264b
197
containers/api/package-lock.json
generated
197
containers/api/package-lock.json
generated
@ -16,11 +16,14 @@
|
||||
"@nestjs/platform-express": "^9.0.0",
|
||||
"@nestjs/typeorm": "^9.0.1",
|
||||
"axios": "^1.4.0",
|
||||
"base32-decode": "^1.0.0",
|
||||
"base32-encode": "^2.0.0",
|
||||
"express-session": "^1.17.3",
|
||||
"passport": "^0.6.0",
|
||||
"passport-jwt": "^4.0.1",
|
||||
"passport-local": "^1.0.0",
|
||||
"pg": "^8.10.0",
|
||||
"qrcode": "^1.5.3",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rxjs": "^7.8.1",
|
||||
"typeorm": "^0.3.15",
|
||||
@ -3065,6 +3068,22 @@
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||
},
|
||||
"node_modules/base32-decode": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/base32-decode/-/base32-decode-1.0.0.tgz",
|
||||
"integrity": "sha512-KNWUX/R7wKenwE/G/qFMzGScOgVntOmbE27vvc6GrniDGYb6a5+qWcuoXl8WIOQL7q0TpK7nZDm1Y04Yi3Yn5g=="
|
||||
},
|
||||
"node_modules/base32-encode": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/base32-encode/-/base32-encode-2.0.0.tgz",
|
||||
"integrity": "sha512-mlmkfc2WqdDtMl/id4qm3A7RjW6jxcbAoMjdRmsPiwQP0ufD4oXItYMnPgVHe80lnAIy+1xwzhHE1s4FoIceSw==",
|
||||
"dependencies": {
|
||||
"to-data-view": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
@ -3310,7 +3329,6 @@
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
|
||||
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
@ -3741,6 +3759,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/decamelize": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
|
||||
"integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dedent": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
|
||||
@ -3836,6 +3862,11 @@
|
||||
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dijkstrajs": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz",
|
||||
"integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA=="
|
||||
},
|
||||
"node_modules/dir-glob": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
||||
@ -3903,6 +3934,11 @@
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||
},
|
||||
"node_modules/encode-utf8": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz",
|
||||
"integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw=="
|
||||
},
|
||||
"node_modules/encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
@ -6669,7 +6705,6 @@
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
|
||||
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
@ -6784,7 +6819,6 @@
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@ -7039,6 +7073,14 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/pngjs": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz",
|
||||
"integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==",
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/postgres-array": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
|
||||
@ -7205,6 +7247,132 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/qrcode": {
|
||||
"version": "1.5.3",
|
||||
"resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.3.tgz",
|
||||
"integrity": "sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==",
|
||||
"dependencies": {
|
||||
"dijkstrajs": "^1.0.1",
|
||||
"encode-utf8": "^1.0.3",
|
||||
"pngjs": "^5.0.0",
|
||||
"yargs": "^15.3.1"
|
||||
},
|
||||
"bin": {
|
||||
"qrcode": "bin/qrcode"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/qrcode/node_modules/cliui": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
|
||||
"integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
|
||||
"dependencies": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"wrap-ansi": "^6.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/qrcode/node_modules/find-up": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
|
||||
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
|
||||
"dependencies": {
|
||||
"locate-path": "^5.0.0",
|
||||
"path-exists": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/qrcode/node_modules/locate-path": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
|
||||
"dependencies": {
|
||||
"p-locate": "^4.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/qrcode/node_modules/p-limit": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
||||
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
|
||||
"dependencies": {
|
||||
"p-try": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/qrcode/node_modules/p-locate": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
|
||||
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
|
||||
"dependencies": {
|
||||
"p-limit": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/qrcode/node_modules/wrap-ansi": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
|
||||
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/qrcode/node_modules/y18n": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
|
||||
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="
|
||||
},
|
||||
"node_modules/qrcode/node_modules/yargs": {
|
||||
"version": "15.4.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
|
||||
"integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
|
||||
"dependencies": {
|
||||
"cliui": "^6.0.0",
|
||||
"decamelize": "^1.2.0",
|
||||
"find-up": "^4.1.0",
|
||||
"get-caller-file": "^2.0.1",
|
||||
"require-directory": "^2.1.1",
|
||||
"require-main-filename": "^2.0.0",
|
||||
"set-blocking": "^2.0.0",
|
||||
"string-width": "^4.2.0",
|
||||
"which-module": "^2.0.0",
|
||||
"y18n": "^4.0.0",
|
||||
"yargs-parser": "^18.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/qrcode/node_modules/yargs-parser": {
|
||||
"version": "18.1.3",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
|
||||
"integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
|
||||
"dependencies": {
|
||||
"camelcase": "^5.0.0",
|
||||
"decamelize": "^1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
|
||||
@ -7356,6 +7524,11 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/require-main-filename": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
|
||||
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.22.2",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
|
||||
@ -7669,6 +7842,11 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/set-blocking": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
||||
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
|
||||
},
|
||||
"node_modules/setprototypeof": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
||||
@ -8142,6 +8320,14 @@
|
||||
"integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/to-data-view": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/to-data-view/-/to-data-view-2.0.0.tgz",
|
||||
"integrity": "sha512-RGEM5KqlPHr+WVTPmGNAXNeFEmsBnlkxXaIfEpUYV0AST2Z5W1EGq9L/MENFrMMmL2WQr1wjkmZy/M92eKhjYA==",
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/to-fast-properties": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
||||
@ -8855,6 +9041,11 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/which-module": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
|
||||
"integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ=="
|
||||
},
|
||||
"node_modules/windows-release": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/windows-release/-/windows-release-4.0.0.tgz",
|
||||
|
||||
@ -27,11 +27,14 @@
|
||||
"@nestjs/platform-express": "^9.0.0",
|
||||
"@nestjs/typeorm": "^9.0.1",
|
||||
"axios": "^1.4.0",
|
||||
"base32-decode": "^1.0.0",
|
||||
"base32-encode": "^2.0.0",
|
||||
"express-session": "^1.17.3",
|
||||
"passport": "^0.6.0",
|
||||
"passport-jwt": "^4.0.1",
|
||||
"passport-local": "^1.0.0",
|
||||
"pg": "^8.10.0",
|
||||
"qrcode": "^1.5.3",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rxjs": "^7.8.1",
|
||||
"typeorm": "^0.3.15",
|
||||
|
||||
@ -7,6 +7,10 @@ import { ChatService } from './chat/chat.service';
|
||||
import { UsersService } from './users/users.service';
|
||||
|
||||
import { MatchLog } from './model/user.entity'
|
||||
import { generate } from 'rxjs';
|
||||
import { generateQRcode } from './users/2fa';
|
||||
|
||||
// import { initStorage, getUser, setUser } from './storage';
|
||||
|
||||
// import { AuthGuard } from '@nestjs/passport';
|
||||
// import { Login42 } from './auth/login42'
|
||||
@ -100,6 +104,22 @@ export class AppController {
|
||||
return user.rank;
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('/2fa')
|
||||
async get2fa(@Request() req)
|
||||
{
|
||||
const user = await this.userService.findOne(req.user.username);
|
||||
return user.doubleAuth;
|
||||
}
|
||||
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('/QRcode')
|
||||
async createQrCode(@Request() req)
|
||||
{
|
||||
return (await generateQRcode(req));
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/quit')
|
||||
async setOffline(@Request() req) {
|
||||
|
||||
@ -19,7 +19,7 @@ export class AuthService {
|
||||
return null;
|
||||
}
|
||||
|
||||
async login(user: any) {
|
||||
async login(user) {
|
||||
const myJSON = JSON.stringify(user);
|
||||
// console.log(`in login all user= ${myJSON}`)
|
||||
// console.log(`in login user= ${user.username}`)
|
||||
|
||||
@ -25,7 +25,7 @@ export class loginClass {
|
||||
const data = {
|
||||
grant_type: 'authorization_code',
|
||||
client_id: 'u-s4t2ud-6d29dfa49ba7146577ffd8bf595ae8d9e5aaa3e0a9615df18777171ebf836a41',
|
||||
client_secret: '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',
|
||||
client_secret: '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',
|
||||
code: code,
|
||||
redirect_uri: 'http://localhost:80/api/auth/login',
|
||||
};
|
||||
@ -66,6 +66,7 @@ export class loginClass {
|
||||
userId: userId,
|
||||
children: null,
|
||||
status: 1,
|
||||
doubleAuth: 0
|
||||
};
|
||||
await this.usersService.create(user);
|
||||
}
|
||||
|
||||
@ -43,6 +43,9 @@ export class User {
|
||||
|
||||
@Column({ default: 0 })
|
||||
userId: number;
|
||||
|
||||
@Column({ default: 0 })
|
||||
doubleAuth: number;
|
||||
|
||||
@OneToMany(() => MatchLog, child => child.parent)
|
||||
children: MatchLog[];
|
||||
|
||||
128
containers/api/src/users/2fa.ts
Normal file
128
containers/api/src/users/2fa.ts
Normal file
@ -0,0 +1,128 @@
|
||||
import crypto from 'crypto';
|
||||
import base32Decode from 'base32-decode';
|
||||
|
||||
// export function generateHOTP(secret, counter) {
|
||||
// const decodedSecret = base32Decode(secret, 'RFC4648');
|
||||
|
||||
// const buffer = Buffer.alloc(8);
|
||||
// for (let i = 0; i < 8; i++)
|
||||
// {
|
||||
// buffer[7 - i] = counter & 0xff;
|
||||
// counter = counter >> 8;
|
||||
// }
|
||||
|
||||
// // Step 1: Generate an HMAC-SHA-1 value
|
||||
// const hmac = crypto.createHmac('sha1', Buffer.from(decodedSecret));
|
||||
// hmac.update(buffer);
|
||||
// const hmacResult = hmac.digest();
|
||||
|
||||
// // Step 2: Generate a 4-byte string (Dynamic Truncation)
|
||||
// const offset = hmacResult[hmacResult.length - 1] & 0xf;
|
||||
// const code =
|
||||
// ((hmacResult[offset] & 0x7f) << 24) |
|
||||
// ((hmacResult[offset + 1] & 0xff) << 16) |
|
||||
// ((hmacResult[offset + 2] & 0xff) << 8) |
|
||||
// (hmacResult[offset + 3] & 0xff);
|
||||
|
||||
// // Step 3: Compute an HOTP value
|
||||
// return `${code % 10 ** 6}`.padStart(6, '0');
|
||||
// }
|
||||
|
||||
type QRcode = any
|
||||
|
||||
export function generateHOTP(secret, counter) {
|
||||
const decodedSecret = base32Decode(secret, 'RFC4648');
|
||||
|
||||
const buffer = Buffer.alloc(8);
|
||||
for (let i = 0; i < 8; i++) {
|
||||
buffer[7 - i] = counter & 0xff;
|
||||
counter = counter >> 8;
|
||||
}
|
||||
|
||||
// Step 1: Generate an HMAC-SHA-1 value
|
||||
const hmac = crypto.createHmac('sha1', Buffer.from(decodedSecret));
|
||||
hmac.update(buffer);
|
||||
const hmacResult = hmac.digest();
|
||||
|
||||
// Step 2: Generate a 4-byte string (Dynamic Truncation)
|
||||
const offset = hmacResult[hmacResult.length - 1] & 0xf;
|
||||
const code =
|
||||
((hmacResult[offset] & 0x7f) << 24) |
|
||||
((hmacResult[offset + 1] & 0xff) << 16) |
|
||||
((hmacResult[offset + 2] & 0xff) << 8) |
|
||||
(hmacResult[offset + 3] & 0xff);
|
||||
|
||||
// Step 3: Compute an HOTP value
|
||||
return code % 10 ** 6;
|
||||
}
|
||||
|
||||
export function generateTOTP(secret, window = 0)
|
||||
{
|
||||
const counter = Math.floor(Date.now() / 30000);
|
||||
return generateHOTP(secret, counter + window);
|
||||
}
|
||||
|
||||
export function verifyTOTP(token, secret, window = 1)
|
||||
{
|
||||
for (let errorWindow = -window; errorWindow <= +window; errorWindow++)
|
||||
{
|
||||
const totp = generateTOTP(secret, errorWindow);
|
||||
if (token === totp)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// import { initStorage, getUser, setUser } from './storage';
|
||||
// import util from 'util';
|
||||
// import qrcode from 'qrcode';
|
||||
// // import base32Encode from 'base32-encode';
|
||||
// import * as util from 'util';
|
||||
// import * as qrcode from 'qrcode';
|
||||
// import * as base32Encode from 'base32-encode';
|
||||
|
||||
// import * as util from 'util';
|
||||
// import * as qrcode from 'qrcode';
|
||||
// import * as crypto from 'crypto';
|
||||
// import { Response } from 'express';
|
||||
// import { Readable } from 'stream';
|
||||
// import * as base32Encode from 'base32-encode';
|
||||
|
||||
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 user = req.user;
|
||||
let res: QRcode;
|
||||
// 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 });
|
||||
|
||||
// setUser(user); // to do !!
|
||||
|
||||
|
||||
// }
|
||||
|
||||
const issuer = 'Google';
|
||||
const algorithm = 'SHA1';
|
||||
const digits = '6';
|
||||
const period = '30';
|
||||
const otpType = 'totp';
|
||||
const configUri = `otpauth://${otpType}/${issuer}:${user.username}?algorithm=${algorithm}&digits=${digits}&period=${period}&issuer=${issuer}&secret=${user.mfaSecret}`;
|
||||
|
||||
// res.setHeader('Content-Type', 'image/png');
|
||||
|
||||
qrcode.toFileStream(res, configUri);
|
||||
console.log(`QRcode done`);
|
||||
return res;
|
||||
}
|
||||
@ -14,6 +14,8 @@ import {AnimatePresence} from "framer-motion";
|
||||
import SuccessToken from '../script/tokenSuccess'
|
||||
|
||||
|
||||
import DoubleAuth from "../pages/2fa.js";
|
||||
|
||||
function AnimatedRoute () {
|
||||
const location = useLocation();
|
||||
return (
|
||||
@ -22,6 +24,9 @@ function AnimatedRoute () {
|
||||
|
||||
<Route exact path="/" element={<HomeLogin/>}/>
|
||||
<Route exact path="/profile" element={<Home/>}/>
|
||||
|
||||
<Route exact path="/2fa" element={<DoubleAuth/>}/>
|
||||
|
||||
<Route exact path="/token" element={<SuccessToken />}/>
|
||||
<Route path="/game" element={<PlayButton />}/>
|
||||
<Route exact path="/pong" element={<PlayButton />}/>
|
||||
|
||||
81
containers/react/src/pages/2fa.js
Normal file
81
containers/react/src/pages/2fa.js
Normal file
@ -0,0 +1,81 @@
|
||||
import React, { useCallback, useState, useEffect } from 'react';
|
||||
import api from '../script/axiosApi';
|
||||
|
||||
function DoubleAuth() {
|
||||
|
||||
// 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;
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{!enabled && (
|
||||
<div>
|
||||
<p>Scan the QR code on your authenticator app</p>
|
||||
<img src={sourceCode} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<form onSubmit={handleSubmit}>
|
||||
{/* <Input
|
||||
id="verificationCode"
|
||||
label="Verification code"
|
||||
type="text"
|
||||
value={verificationCode}
|
||||
onChange={(e) => setVerificationCode(e.target.value)}
|
||||
/> */}
|
||||
|
||||
<button type="submit">Confirm</button>
|
||||
|
||||
{/* {invalidCode && <p>Invalid verification code</p>} */}
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default DoubleAuth;
|
||||
Loading…
Reference in New Issue
Block a user