i've been struggling a lot with fastify-passport library, mainly because it seems that nobody uses it and there aren't any good examples or issues related to it
anyhow, i have some routes defined like this:
const adminRoutes = [
{
handler: (req,res) => {console.log(req.user) },
url: "/logout",
method: "GET"
}
]
this route is then registered by fastify like this (do note that there are more routes, however, this is just a code snippet)
adminRoutes.forEach((route, index) => {
fastify.route(route)
})
i am using passport local strategy to autenticate, it's configured like this
fastifyPassport.use('login', new passportLocal(async function (username, password, done) {
try {
let data = await dbQuery(`SELECT * FROM \`users\` WHERE username="${username}"`)
if (data[0].length > 0) {
data = data[0][0]
if (username === data.username && bCrypt.compareSync(password, data.hashedPassword)) {
return done(null, username)
} else return done(null, false)
}
} catch (error) {
console.log(error)
done(error);
}
}))
this seems to work, in all my tests, the strategy did what it had to do, when the right user and password is passed all the checks seems to pass and gets all the way down to return done(null, username)
this is my serializer and deserializer
fastifyPassport.registerUserSerializer(async (user, request) => {
return user
});
fastifyPassport.registerUserDeserializer(async (username, request) => {
let data = await dbQuery(`SELECT * FROM users WHERE username="${username}"`);
return data[0][0]
});
i've checked with both a debugger and console logs, they don't seem to ever get called
in fact when i go to /logout my console throws a null
also no session cookie get generated (uncertain of this, sometimes it seems to generate, other times it doesn't)
the complete code is quite long, however, it's probably necessary to see whats the issue
so here is it
this is the server
require('dotenv').config()
const fastify = require('fastify')({ logger: false })
const fastifyPassport = require('fastify-passport')
const fastifySecureSession = require('fastify-secure-session')
const passportLocal = require('passport-local').Strategy
const BannedEverywhere = ["DROP", "CREATE"]
const bCrypt = require('bcryptjs')
const fs = require('fs')
const path = require('path')
const port = process.env.PORT || 3000
const routes = require('./routes')
const mysql = require('mysql2/promise');
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: process.env.DB_PASSWD,
database: 'users',
port: 3306
});
console.log("Server Connected!")
function dbQuery(dataExpression) {
if (BannedEverywhere.some(i => dataExpression.includes(i))) {
return "invalid"
}
return pool.query(dataExpression)
}
fastify.register(require('fastify-cors'), {
origin: (origin, cb) => {
cb(null, true);
return
}
})
fastify.register(fastifySecureSession, { key: fs.readFileSync(path.join(__dirname, 'secret-key'))})
fastify.register(fastifyPassport.initialize())
fastify.register(fastifyPassport.secureSession())
fastifyPassport.registerUserSerializer(async (user, request) => {
return user
});
fastifyPassport.registerUserDeserializer(async (username, request) => {
let data = await dbQuery(`SELECT * FROM users WHERE username="${username}"`);
return data[0][0]
});
fastifyPassport.use('login', new passportLocal(async function (username, password, done) {
try {
let data = await dbQuery(`SELECT * FROM \`users\` WHERE username="${username}"`)
if (data[0].length > 0) {
data = data[0][0]
if (username === data.username && bCrypt.compareSync(password, data.hashedPassword)) {
console.log("got here")
return done(null, username)
} else return done(null, false)
}
} catch (error) {
console.log(error)
done(error);
}
}))
const postData = async (req, reply, err, user, info, status) => {
if (err !== null) { console.warn("ah habido un error: " + err) }
else if (user) {
const params = req.body
const newData = {
universidad: params.universidad,
facultad: params.facultad,
nombreExamen: params.nombreExamen,
fechaExamen: params.fechaExamen,
convocatoriaEspecial: params.convocatoriaEspecial,
convocatoriaExtraordinaria: params.convocatoriaExtraordinaria,
curso: params.curso
}
const response = await dbQuery('INSERT INTO `examenes` VALUES("'
+ newData.universidad + '","' + newData.facultad + '","'
+ newData.nombreExamen + '","' + newData.fechaExamen + '",'
+ newData.convocatoriaEspecial + ',' + newData.convocatoriaExtraordinaria + ','
+ newData.curso + ")")
return reply.send({ status: 200, newData, response })
}
}
const deleteData = async (req, reply, err, user, info, status) => {
if (err !== null) { console.warn("ah habido un error: " + err) }
else if (user) {
const { universidad, facultad, nombreExamen, fechaExamen, curso } = req.body
const response = await dbQuery('DELETE FROM `examenes` WHERE universidad="' + universidad + '" and facultad="' + facultad + '" and nombreExamen="' + nombreExamen + '" and date(fechaExamen)="' + fechaExamen + '" and curso=' + curso)
return reply.send({ status: 200, response })
}
}
const logout = async (req, reply, err, user, info, status) => {
if (err !== null) { console.warn("ah habido un error: " + err) }
console.log(req)
console.log("--------------------------------")
console.log(user)
console.log("--------------------------------")
console.log(info)
console.log("--------------------------------")
console.log(status)
}
fastify.get(
"/login",
(req, reply) => {
return reply.sendFile('./login/index.html')
}
)
fastify.post(
"/login",
{preValidation: fastifyPassport.authenticate('login',(req, reply)=>{
reply.send({redirect: "/"})
})},
() => {}
)
const adminRoutes = [
{
handler: () => {},
preValidation: fastifyPassport.authenticate("login", deleteData),
url: '/api/deleteData',
method: 'POST'
},
{
handler: () => {},
preValidation: fastifyPassport.authenticate("login", postData),
url: '/api/postData',
method: 'POST'
},
{
handler: () => {},
preValidation: fastifyPassport.authenticate("login", (req, reply) => { return reply.sendFile('./entry/index.html') }),
url: '/entry',
method: 'GET'
},
{
handler: (req,res) => {console.log(req.user) },
url: "/logout",
method: "GET"
}
]
const start = async () => {
try {
await fastify.listen(port)
} catch (err) {
console.error(err)
process.exit(1)
}
}
fastify.register(require('fastify-static'), {
root: __dirname,
prefix: '/', // optional: default '/'
})
routes.forEach((route, index) => {
fastify.route(route)
})
adminRoutes.forEach((route, index) => {
fastify.route(route)
})
start()
before you comment, i know cors shouldn't be left like that to go in production, don't worry, i know
also logout
function was just a test, to try solve this very issue
this is the code that calls the login
post request
const HOST = location.origin;
const axiosApp = axios.create({
baseURL: HOST,
});
document
.querySelector("#submit")
.addEventListener("click", async function () {
let response = await axiosApp.post(`${HOST}/login`, {
username: document.querySelector("#username").value,
password: document.querySelector("#password").value,
});
console.log(response);
if(response.status == 200) {
document.location.href = response.data.redirect
}
});
unrelated, bannedEverywhere is just a rudimentary "security" check, i do plan to improve it, for now it's just a better than nothing, and, i do plan to change all the var + string + var
chains with template strings