UNPKG

spartan-shield

Version:

nodejs project to package and configure common security middleware.

189 lines (188 loc) 7.36 kB
'use strict' const authPolicy = require('../security.json').accessControlsPolicy.authenticationPolicy const MAX_LOGIN_ATTEMPTS = authPolicy.passwords.lockout.attempts const LOCK_TIME = authPolicy.passwords.lockout.automaticReset var failedAttempts = 0 let admin = require('firebase-admin') const firebase = require('firebase') require('firebase/auth') require('firebase/database') const secrets = require('./secrets') let serviceAccount = require(secrets.fetchSecret('SERVICE_ACCOUNT')) function checkSignIn () { let user = firebase.auth().currentUser if (user) { return user // returns true if there's a user signed in by that name } else { return false // returns false if there's no user signed in by that name } } async function lockout (email) { let toBeLocked = await admin.auth().getUserByEmail(email).then(record => { return record }).catch(err => { return err }) await admin.auth().updateUser(toBeLocked.uid, { disabled: true }).then(ur => { // console.log(`User ${ ur.displayName } 's account has been disabled`) return ur }).catch (err => { return err }) } async function unlock(email) { let toBeUnlocked = await admin.auth().getUserByEmail(email).then(record => { return record }) console.log(`I'm planning to unlock account ${toBeUnlocked.displayName} in ${LOCK_TIME} miliseconds`) setTimeout(async () => { await admin.auth().updateUser(toBeUnlocked.uid, { disabled: false }).catch(err => console.log(err)) console.log(`User ${toBeUnlocked.displayName}'s account was previously disabled. It was unlocked at ${new Date().getDate()}`) }, LOCK_TIME) } async function register(uname, email, passwd) { if (email.length < 4) { // validate email let err = new Error('auth/invalid-email-address') err.status = 401 return err } if (passwd.length < authPolicy.passwords.minLen) { // validate password let err = new Error('auth/password-too-short') err.status = 401 return err } var passPolicy = new RegExp(authPolicy.passwords.regex, 'g') var res = passPolicy.test(passwd) if (res === false) { let err = new Error('auth/weak-password') err.status = 401 return err } let newRecord = await admin.auth().createUser({ displayName: uname, email: email, password: passwd, disabled: false }).catch(error => { return error }) if (!(newRecord instanceof Error)) { firebase.auth().signInWithEmailAndPassword(email, passwd).catch(error => console.log(error.code)) return newRecord } } async function resetPassword(email) { await firebase.auth().sendPasswordResetEmail(email).then(function () { console.log(`user ${email} requested a password reset. An reset link was sent to this address at ${new Date().getDate()}`) }).catch(function (error) { if (error) { return error } }) } async function changePassword(oldPassword, newPassword) { try { // first verify the current user's old password let user = firebase.auth().currentUser let cred = firebase.auth.EmailAuthProvider.credential(user.email, oldPassword) let updatedUser = await user.reauthenticateAndRetrieveDataWithCredential(cred) if (updatedUser !== undefined) { let message = await user.updatePassword(newPassword).then(() => { let msg = `User ${user.displayName}'s password was updated` return msg }) console.log(message) return message } } catch (err) { return err } } module.exports = async (type, config, callback) => { if (type === 'firebase') { // initalize the app let firebaseConfig = { apiKey: secrets.fetchSecret('FIREBASE_API_KEY'), authDomain: secrets.fetchSecret('FIREBASE_AUTH_DOMAIN'), databaseURL: secrets.fetchSecret('FIREBASE_DB_URL'), projectId: secrets.fetchSecret('FIREBASE_PROJECT_ID'), storageBucket: secrets.fetchSecret('FIREBASE_STORAGE_BUCKET'), senderId: secrets.fetchSecret('FIREBASE_SENDER_ID') } !firebase.apps.length ? firebase.initializeApp(firebaseConfig) : firebase.app() !admin.apps.length ? admin.initializeApp({ credential: admin.credential.cert(serviceAccount), databaseURL: secrets.fetchSecret('FIREBASE_DB_URL') }) : admin.app() // registration if (config.register) { let newUser = await register(config.register.username, config.register.email, config.register.password) if (newUser instanceof Error) { return newUser } else { let msg = `successfully created new user: ${newUser.displayName}` return { msg: msg, ur: newUser } } } else if (config.login) { // login let toBeLocked = await admin.auth().getUserByEmail(config.login.email).then(record => { return record }) let loginSuccess = await firebase.auth().signInWithEmailAndPassword(config.login.email, config.login.password).then(record => { if (record.disabled === true) { admin.auth().updateUser(record.uid, { disabled: false }) failedAttempts = 0 } return record }).catch(error => { if (error.code === 'auth/wrong-password') { failedAttempts = failedAttempts + 1 let remainingAttempts = MAX_LOGIN_ATTEMPTS - failedAttempts let err = new Error('auth/wrong-password') err.msg = `Login Failed. You have ${remainingAttempts} left` err.status = 401 if (remainingAttempts === 0) { lockout(config.login.email) unlock(config.login.email) } } else if (error.code === 'auth/user-disabled') { // check to see if the account should be unlocked if (toBeLocked.disabled === true) { unlock(config.login.email) console.log(`It's too early to unlock the account ${toBeLocked.displayName}`) return error } else { unlock(config.login.email) } } else if (error.code === 'auth/too-many-requests') { lockout(config.login.email) console.log(`It looks like user ${toBeLocked.displayName} is up to some shenanigans. Account was locked as a precaution.`) unlock(config.login.email) return error } console.log(error.code) return error }) return loginSuccess } else if (config.resetPassword) { // reset password await resetPassword(config.resetPassword.email).then(() => { return `Reset email sent to ${config.resetPassword.email}` }).catch(err => { return err }) } else if (config.changePassword) { let changedUser = await changePassword(config.changePassword.old, config.changePassword.new).then(value => { return value }).catch(err => { return err }) return changedUser } else if (config.logout) { // logout let user = checkSignIn() if (user) { // user is signed in, so sign them out let logoutSuccess = await firebase.auth().signOut().then(() => { let msg = `User ${user.displayName} has been signed out` return msg }).catch(err => { if (err) { return err } }) return logoutSuccess } // else { // let err = new Error(`No user to sign out`) // err.status = 401 // return err // } } } }