import fastifySession from '@fastify/session' import fastifyCookie from 'fastify-cookie' import PouchDB from 'pouchdb' import PouchDBfind from 'pouchdb-find' /** * pouchdb storage * * * @extends Store * */ class PouchdbStore extends Store { /** * * * @param {Object} * */ constructor() { super() PouchDB.plugin(PouchDBfind) // create db if not already exists this.db = new PouchDB('./../../storage/session', { revs_limit: 0 }) } /** * * @param {[type]} sessionId [description] * @param {Function} callback [description] */ async set(sessionId, session, callback) { const result = await this.db.find({ 'selector': { '_id': sessionId } }) if (result.docs.length === 0) { session._id = sessionId await this.db.post(session) } callback() } /** * * @param {[type]} sessionId [description] * @param {Function} callback [description] * @return {[type]} [description] */ async get(sessionId, callback) { const result = await this.db.find({ 'selector': { '_id': sessionId } }) let session = null if (result.docs.length > 0) { session = result.docs[0] } callback(null, session) } /** * * @param {[type]} sessionId [description] * @param {Function} callback [description] * @return {[type]} [description] */ async destroy(sessionId, callback) { const result = await this.db.find({ 'selector': { '_id': sessionId } }) if (result.docs.length > 0) { await this.db.remove(result.docs[0]) } callback() } } /** * * * */ const loginSchema = { schema: { body: { username: { type: 'string' }, password: { type: 'string' } }, response: { 200: { type: 'object', properties: { token: { type: 'string' } } } } } } /** * create Plugin * * */ function plugin(fastify, options, next) { { // create cookie fastify .register(fastifyCookie) .register(fastifySession, { secret: options.secret, cookieName: 'session', cookie: { path: '/', maxAge: options.secret, secure: true, httpOnly: true, sameSite: 'Strict' }, store: new PouchdbStore() }) /** * route: logout user and destroy session * * */ fastify.get('/logout', async function(request, response) { request.destroySession(() => { response.redirect('/') }) }) /** * route: auth * * @param {object} request * @param {object} response * */ fastify.post('/auth', loginSchema, async function (request, reply) { let { username, password } = request.body // strip crap from strings username = DOMPurify.sanitize(username) password = DOMPurify.sanitize(password) const userRepository = new UserRepository() const user = await userRepository.findOneByUsername(username) // add header for json reply.header('Content-Type', 'application/json; charset=utf-8') // user not found if (!user) { return reply .code(404) .send() } // password wrong if (!bcrypt.compareSync(password, user.password)) { return reply .code(401) .send() } // setting session to store and set cookie request.sessionStore.set(request.session.sessionId, request.session, async function() { user.sessionId = request.session.sessionId await userRepository.update(user) // send 200 and send set-token reply .code(200) .send() }) }) done() } module.exports = plugin