Upgraded password hashing algo to argon2id.
This commit is contained in:
parent
895a8201a5
commit
5caa679b92
|
|
@ -6,11 +6,15 @@
|
|||
"protocol": "http",
|
||||
"domain": "localhost",
|
||||
"ytdlpPath": "/home/canopy/.local/pipx/venvs/yt-dlp/bin/yt-dlp",
|
||||
"sessionSecret": "CHANGE_ME",
|
||||
"altchaSecret": "CHANGE_ME",
|
||||
"ipSecret": "CHANGE_ME",
|
||||
"migrate": false,
|
||||
"dropLegacyTokes": false,
|
||||
"secrets":{
|
||||
"passwordSecret": "CHANGE_ME",
|
||||
"rememberMeSecret": "CHANGE_ME",
|
||||
"sessionSecret": "CHANGE_ME",
|
||||
"altchaSecret": "CHANGE_ME",
|
||||
"ipSecret": "CHANGE_ME"
|
||||
},
|
||||
"ssl":{
|
||||
"cert": "./server.cert",
|
||||
"key": "./server.key"
|
||||
|
|
|
|||
|
|
@ -16,14 +16,6 @@
|
|||
//Path to YT-DLP Executable for scraping youtube, dailymotion, and vimeo
|
||||
//Dailymotion and Vimeo could work using official apis w/o keys, but you wouldn't have any raw file playback options :P
|
||||
"ytdlpPath": "/home/canopy/.local/pipx/venvs/yt-dlp/bin/yt-dlp",
|
||||
//Be careful with what you keep in secrets, you should use special chars, but test your deployment, as some chars may break account registration
|
||||
//An update to either kill the server and bitch about the issue in console is planned so it's not so confusing for new admins
|
||||
//Session secret used to secure session keys
|
||||
"sessionSecret": "CHANGE_ME",
|
||||
//Altacha secret used to generate altcha challenges
|
||||
"altchaSecret": "CHANGE_ME",
|
||||
//IP Secret used to salt IP Hashes
|
||||
"ipSecret": "CHANGE_ME",
|
||||
//Enable to migrate legacy DB and toke files dumped into the ./migration/ directory
|
||||
//WARNING: The migration folder is cleared after server boot, whether or not a migration took place or this option is enabled.
|
||||
//Keep your backups in a safe place, preferably a machine that DOESN'T have open inbound ports exposed to the internet/a publically accessible reverse proxy!
|
||||
|
|
@ -32,6 +24,21 @@
|
|||
//Requires migration to be disabled before it takes effect.
|
||||
//WARNING: this does NOT affect user toke counts, migrated or otherwise. Use carefully!
|
||||
"dropLegacyTokes": false,
|
||||
//Server Secrets
|
||||
//Be careful with what you keep in secrets, you should use special chars, but test your deployment, as some chars may break account registration
|
||||
//An update to either kill the server and bitch about the issue in console is planned so it's not so confusing for new admins
|
||||
"secrets":{
|
||||
//Password secret used to pepper password hashes
|
||||
"passwordSecret": "CHANGE_ME",
|
||||
//Password secret used to pepper rememberMe token hashes
|
||||
"rememberMeSecret": "CHANGE_ME",
|
||||
//Session secret used to secure session keys
|
||||
"sessionSecret": "CHANGE_ME",
|
||||
//Altacha secret used to generate altcha challenges
|
||||
"altchaSecret": "CHANGE_ME",
|
||||
//IP Secret used to pepper IP Hashes
|
||||
"ipSecret": "CHANGE_ME"
|
||||
},
|
||||
//SSL cert and key locations
|
||||
"ssl":{
|
||||
"cert": "./server.cert",
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ userSchema.pre('save', async function (next){
|
|||
//If the password was changed
|
||||
if(this.isModified("pass")){
|
||||
//Hash that sunnovabitch, no questions asked.
|
||||
this.pass = hashUtil.hashPassword(this.pass);
|
||||
this.pass = await hashUtil.hashPassword(this.pass);
|
||||
}
|
||||
|
||||
//If the flair was changed
|
||||
|
|
@ -321,7 +321,7 @@ userSchema.statics.authenticate = async function(user, pass, failLine = "Bad Use
|
|||
}
|
||||
|
||||
//Check our password is correct
|
||||
if(userDB.checkPass(pass)){
|
||||
if(await userDB.checkPass(pass)){
|
||||
return userDB;
|
||||
}else{
|
||||
//if not scream and shout
|
||||
|
|
@ -492,8 +492,8 @@ userSchema.statics.processAgedIPRecords = async function(){
|
|||
* @param {String} pass - Password to authenticate
|
||||
* @returns {Boolean} True if authenticated
|
||||
*/
|
||||
userSchema.methods.checkPass = function(pass){
|
||||
return hashUtil.comparePassword(pass, this.pass)
|
||||
userSchema.methods.checkPass = async function(pass){
|
||||
return await hashUtil.comparePassword(pass, this.pass)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -824,7 +824,7 @@ userSchema.methods.killAllSessions = async function(reason = "A full log-out fro
|
|||
* @param {Object} passChange - passChange object handed down from Browser
|
||||
*/
|
||||
userSchema.methods.changePassword = async function(passChange){
|
||||
if(this.checkPass(passChange.oldPass)){
|
||||
if(await this.checkPass(passChange.oldPass)){
|
||||
if(passChange.newPass == passChange.confirmPass){
|
||||
//Note: We don't have to worry about hashing here because the schema is written to do it auto-magically
|
||||
this.pass = passChange.newPass;
|
||||
|
|
@ -877,7 +877,7 @@ userSchema.methods.nuke = async function(pass){
|
|||
}
|
||||
|
||||
//Check that the password is correct
|
||||
if(this.checkPass(pass)){
|
||||
if(await this.checkPass(pass)){
|
||||
//delete the user
|
||||
var oldUser = await this.deleteOne();
|
||||
}else{
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ module.exports.store = mongoStore.create({mongoUrl: dbUrl});
|
|||
|
||||
//define sessionMiddleware
|
||||
const sessionMiddleware = session({
|
||||
secret: config.sessionSecret,
|
||||
secret: config.secrets.sessionSecret,
|
||||
resave: false,
|
||||
saveUninitialized: false,
|
||||
store: module.exports.store
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ module.exports.genCaptcha = async function(difficulty = 2, uniqueSecret = ''){
|
|||
|
||||
//Generate Altcha Challenge
|
||||
return await createChallenge({
|
||||
hmacKey: [config.altchaSecret, uniqueSecret].join(''),
|
||||
hmacKey: [config.secrets.altchaSecret, uniqueSecret].join(''),
|
||||
maxNumber: 100000 * difficulty,
|
||||
expires: expiration
|
||||
});
|
||||
|
|
@ -73,5 +73,5 @@ module.exports.verify = async function(payload, uniqueSecret = ''){
|
|||
setTimeout(() => {spent.splice(payloadIndex,1);}, lifetime * 60 * 1000);
|
||||
|
||||
//Return verification results
|
||||
return await verifySolution(payload, [config.altchaSecret, uniqueSecret].join(''));
|
||||
return await verifySolution(payload, [config.secrets.altchaSecret, uniqueSecret].join(''));
|
||||
}
|
||||
|
|
@ -40,18 +40,28 @@ module.exports.securityCheck = function(){
|
|||
loggerUtil.consoleWarn("Mail transport security disabled! This server should be used for development purposes only!");
|
||||
}
|
||||
|
||||
//check password pepper
|
||||
if(!validator.isStrongPassword(config.secrets.passwordSecret) || config.secrets.passwordSecret == "CHANGE_ME"){
|
||||
loggerUtil.consoleWarn("Insecure Password Secret! Change Password Secret!");
|
||||
}
|
||||
|
||||
//check RememberMe pepper
|
||||
if(!validator.isStrongPassword(config.secrets.rememberMeSecret) || config.secrets.rememberMeSecret == "CHANGE_ME"){
|
||||
loggerUtil.consoleWarn("Insecure RememberMe Secret! Change RememberMe Secret!");
|
||||
}
|
||||
|
||||
//check session secret
|
||||
if(!validator.isStrongPassword(config.sessionSecret) || config.sessionSecret == "CHANGE_ME"){
|
||||
if(!validator.isStrongPassword(config.secrets.sessionSecret) || config.secrets.sessionSecret == "CHANGE_ME"){
|
||||
loggerUtil.consoleWarn("Insecure Session Secret! Change Session Secret!");
|
||||
}
|
||||
|
||||
//check altcha secret
|
||||
if(!validator.isStrongPassword(config.altchaSecret) || config.altchaSecret == "CHANGE_ME"){
|
||||
if(!validator.isStrongPassword(config.secrets.altchaSecret) || config.secrets.altchaSecret == "CHANGE_ME"){
|
||||
loggerUtil.consoleWarn("Insecure Altcha Secret! Change Altcha Secret!");
|
||||
}
|
||||
|
||||
//check ipHash secret
|
||||
if(!validator.isStrongPassword(config.ipSecret) || config.ipSecret == "CHANGE_ME"){
|
||||
if(!validator.isStrongPassword(config.secrets.ipSecret) || config.secrets.ipSecret == "CHANGE_ME"){
|
||||
loggerUtil.consoleWarn("Insecure IP Hashing Secret! Change IP Hashing Secret!");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,9 +29,9 @@ const bcrypt = require('bcrypt');
|
|||
* @param {String} pass - Password to hash
|
||||
* @returns {String} Hashed/Salted password
|
||||
*/
|
||||
module.exports.hashPassword = function(pass){
|
||||
const salt = bcrypt.genSaltSync();
|
||||
return bcrypt.hashSync(pass, salt);
|
||||
module.exports.hashPassword = async function(pass){
|
||||
//Hash password with argon2id
|
||||
return await argon2.hash(pass, {secret: Buffer.from(config.secrets.passwordSecret)});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -40,8 +40,9 @@ module.exports.hashPassword = function(pass){
|
|||
* @param {String} hash - Salty Hash
|
||||
* @returns {Boolean} True if authentication success
|
||||
*/
|
||||
module.exports.comparePassword = function(pass, hash){
|
||||
return bcrypt.compareSync(pass, hash);
|
||||
module.exports.comparePassword = async function(pass, hash){
|
||||
//Verify password against argon2 hash
|
||||
return await argon2.verify(hash, pass, {secret: Buffer.from(config.secrets.passwordSecret)});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -59,14 +60,14 @@ module.exports.compareLegacyPassword = function(pass, hash){
|
|||
*
|
||||
* Provides a basic level of privacy by only logging salted hashes of IP's
|
||||
* @param {String} ip - IP to hash
|
||||
* @returns {String} Hashed/Salted IP Adress
|
||||
* @returns {String} Hashed/Peppered IP Adress
|
||||
*/
|
||||
module.exports.hashIP = function(ip){
|
||||
//Create hash object
|
||||
const hashObj = crypto.createHash('sha512');
|
||||
|
||||
//add IP and salt to the hash
|
||||
hashObj.update(`${ip}${config.ipSecret}`);
|
||||
//add IP and pepper to the hash
|
||||
hashObj.update(`${ip}${config.secrets.ipSecret}`);
|
||||
|
||||
//return the IP hash as a string
|
||||
return hashObj.digest('hex');
|
||||
|
|
@ -78,7 +79,8 @@ module.exports.hashIP = function(ip){
|
|||
* @returns {String} - Hashed token
|
||||
*/
|
||||
module.exports.hashRememberMeToken = async function(token){
|
||||
return await argon2.hash(token);
|
||||
//hash token with argon2id
|
||||
return await argon2.hash(token, {secret: Buffer.from(config.secrets.rememberMeSecret)});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -89,5 +91,5 @@ module.exports.hashRememberMeToken = async function(token){
|
|||
*/
|
||||
module.exports.compareRememberMeToken = async function(token, hash){
|
||||
//Compare hash and return result
|
||||
return await argon2.verify(hash, token);
|
||||
return await argon2.verify(hash, token, {secret: Buffer.from(config.secrets.rememberMeSecret)});
|
||||
}
|
||||
Loading…
Reference in a new issue