build: setup docker containers for development
This commit is contained in:
219
app/server/routes/users.js
Normal file
219
app/server/routes/users.js
Normal file
@@ -0,0 +1,219 @@
|
||||
import express from 'express';
|
||||
import {
|
||||
generateRegistrationOptions,
|
||||
verifyRegistrationResponse,
|
||||
generateAuthenticationOptions,
|
||||
verifyAuthenticationResponse,
|
||||
} from '@simplewebauthn/server';
|
||||
import dbClient from './../db/index.js';
|
||||
import crypto from 'node:crypto';
|
||||
import limitedUsers from '../middlewares/limitedUsers.js';
|
||||
|
||||
var router = express.Router();
|
||||
|
||||
const userPasskeys = [];
|
||||
const origin = `https://${process.env.RP_ID}`;
|
||||
|
||||
const challenges = {};
|
||||
const users = {};
|
||||
const currentLogin = {};
|
||||
|
||||
router.get("/register", limitedUsers, function(_, res) {
|
||||
res.render("users/register");
|
||||
});
|
||||
|
||||
router.get("/login", function(_, res) {
|
||||
res.render("users/login");
|
||||
});
|
||||
|
||||
router.get("/generate-auth-options/:username", async function(req, res, next) {
|
||||
dbClient.query({
|
||||
text: 'SELECT * FROM users WHERE username=$1',
|
||||
values: [req.params.username]
|
||||
})
|
||||
.then((result) => {
|
||||
const user = result.rows[0];
|
||||
if (!user) {
|
||||
throw new Error("ya pas de user wesh");
|
||||
}
|
||||
return dbClient.query({
|
||||
text: `
|
||||
SELECT *
|
||||
FROM user_passkeys up
|
||||
JOIN passkeys ON up.passkey_id = passkeys.id
|
||||
WHERE up.user_id = $1
|
||||
`,
|
||||
values: [user.id]
|
||||
});
|
||||
})
|
||||
.then(async (passkeyData) => {
|
||||
const options = await generateAuthenticationOptions({
|
||||
rpID: process.env.RP_ID,
|
||||
allowCredentials: passkeyData.rows.map(passkey => ({
|
||||
id: passkey.id,
|
||||
transports: passkey.transports,
|
||||
})),
|
||||
});
|
||||
|
||||
currentLogin[req.params.username] = options;
|
||||
return options;
|
||||
})
|
||||
.then((options) => {
|
||||
res.json(options);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("Error in login");
|
||||
console.error(err);
|
||||
next(err);
|
||||
});
|
||||
});
|
||||
|
||||
router.post("/verify-auth/", function(req, res) {
|
||||
console.log("Verify auth");
|
||||
const { authResp, username } = req.body;
|
||||
|
||||
dbClient.query({
|
||||
text: 'SELECT * FROM users WHERE username=$1',
|
||||
values: [username]
|
||||
})
|
||||
.then((result) => {
|
||||
const user = result.rows[0];
|
||||
if (!user) {
|
||||
throw new Error("ya pas de user wesh");
|
||||
}
|
||||
return dbClient.query({
|
||||
text: `
|
||||
SELECT *
|
||||
FROM passkeys
|
||||
WHERE id = $1
|
||||
`,
|
||||
values: [authResp.id]
|
||||
});
|
||||
})
|
||||
.then(async (passkeyData) => {
|
||||
const passkey = passkeyData.rows[0];
|
||||
|
||||
return verifyAuthenticationResponse({
|
||||
response: authResp,
|
||||
expectedChallenge: currentLogin[username].challenge,
|
||||
expectedOrigin: origin,
|
||||
expectedRPID: process.env.RP_ID,
|
||||
credential: {
|
||||
id: passkey.id,
|
||||
publicKey: new Uint8Array(passkey['public_key']),
|
||||
counter: passkey.counter,
|
||||
transports: passkey.transports,
|
||||
},
|
||||
equireUserVerification: false,
|
||||
});
|
||||
})
|
||||
.then(verification => {
|
||||
const header = Buffer.from(JSON.stringify({
|
||||
'alg': 'HS256',
|
||||
'type': "JWT"
|
||||
})).toString('base64url');
|
||||
const payload = Buffer.from(JSON.stringify({
|
||||
verified: true,
|
||||
username: username
|
||||
})).toString('base64url');
|
||||
|
||||
const hash = crypto.createHmac('sha256', process.env.AUTH_JWT_SECRET);
|
||||
hash.update(header + "." + payload);
|
||||
const token = header + "." + payload + "." + hash.digest('base64url');
|
||||
|
||||
res.cookie('auth_token', token, {
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: 'Strict'
|
||||
});
|
||||
|
||||
res.send(verification);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log("ya erreur")
|
||||
console.error(err);
|
||||
res.status(400).send({ error: err.message });
|
||||
});
|
||||
});
|
||||
|
||||
router.post("/register/setup", limitedUsers, async function(req, res, next) {
|
||||
const { username } = req.body;
|
||||
|
||||
generateRegistrationOptions({
|
||||
rpName: process.env.RP_NAME,
|
||||
rpID: process.env.RP_ID,
|
||||
userName: username,
|
||||
attestationType: 'none',
|
||||
excludeCredentials: userPasskeys.map(passkey => ({
|
||||
id: passkey.id,
|
||||
transports: passkey.transports,
|
||||
})),
|
||||
authenticatorSelection: {
|
||||
residentKey: 'preferred',
|
||||
userVerification: 'preferred',
|
||||
authenticatorAttachment: 'platform',
|
||||
},
|
||||
})
|
||||
.then((options) => {
|
||||
challenges[username] = options.challenge;
|
||||
users[username] = options.user;
|
||||
res.send(options);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("Something went wrong");
|
||||
console.error(err);
|
||||
next(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
router.post("/register/verify", limitedUsers, function(req, res, next) {
|
||||
const { registration, username } = req.body;
|
||||
verifyRegistrationResponse({
|
||||
response: registration,
|
||||
expectedChallenge: challenges[username],
|
||||
expectedOrigin: origin,
|
||||
expectedRPID: process.env.RP_ID,
|
||||
})
|
||||
.then(async (verification) => {
|
||||
const user = users[username];
|
||||
|
||||
await dbClient.query("BEGIN");
|
||||
|
||||
await dbClient.query({
|
||||
text: 'INSERT INTO users(id, username) VALUES($1, $2)',
|
||||
values: [user.id, user.name],
|
||||
});
|
||||
|
||||
await dbClient.query({
|
||||
text: 'INSERT INTO passkeys(id, public_key, counter, transports) VALUES($1, $2, $3, $4)',
|
||||
values: [
|
||||
verification.registrationInfo.credential.id,
|
||||
Buffer.from(verification.registrationInfo.credential.publicKey),
|
||||
verification.registrationInfo.credential.counter,
|
||||
verification.registrationInfo.credential.transports.join(',')
|
||||
]
|
||||
});
|
||||
|
||||
await dbClient.query({
|
||||
text: 'INSERT INTO user_passkeys(user_id, passkey_id) VALUES($1, $2)',
|
||||
values: [user.id, verification.registrationInfo.credential.id]
|
||||
});
|
||||
|
||||
dbClient.query("COMMIT");
|
||||
res.send(verification);
|
||||
})
|
||||
.catch((err) => {
|
||||
dbClient.query("ROLLBACK");
|
||||
console.error("Something went wrong")
|
||||
console.error(err);
|
||||
next(err);
|
||||
})
|
||||
.finally(() => {
|
||||
delete challenges[username];
|
||||
delete users[username];
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user