Added privacy policy

Updated marketing
Added some keyboard shortcuts
Added settings page
Added accent theming
Added beta 2FA
This commit is contained in:
Max G
2020-07-07 04:04:55 +00:00
parent 2ae84ab73e
commit 06b8f0ad6a
29 changed files with 1428 additions and 362 deletions

View File

@@ -182,7 +182,7 @@ Note.create = (userId, noteTitle = '', noteText = '', masterKey) => {
const encryptedText = cs.encrypt(masterKey, salt, textObject)
db.promise()
.query(`INSERT INTO note_raw_text (text, salt, updated) VALUE (?, ?, ?)`, [encryptedText, salt, created])
.query(`INSERT INTO note_raw_text (text, salt, updated) VALUE (?, ?, ?)`, [encryptedText, salt, (+new Date)])
.then( (rows, fields) => {
const rawTextId = rows[0].insertId
@@ -515,7 +515,7 @@ Note.setPinned = (userId, noteId, pinnedBoolean) => {
return new Promise((resolve, reject) => {
const pinned = pinnedBoolean ? 1:0
const now = Math.round((+new Date)/1000)
const now = (+new Date)
//Update other note attributes
return db.promise()
@@ -532,7 +532,7 @@ Note.setArchived = (userId, noteId, archivedBoolead) => {
return new Promise((resolve, reject) => {
const archived = archivedBoolead ? 1:0
const now = Math.round((+new Date)/1000)
const now = (+new Date)
//Update other note attributes
return db.promise()
@@ -549,7 +549,7 @@ Note.setTrashed = (userId, noteId, trashedBoolean, masterKey) => {
return new Promise((resolve, reject) => {
const trashed = trashedBoolean ? 1:0
const now = Math.round((+new Date)/1000)
const now = (+new Date)
//Update other note attributes
return db.promise()
@@ -1048,7 +1048,7 @@ Note.search = (userId, searchQuery, searchTags, fastFilters, masterKey) => {
// Always prioritize pinned notes in searches.
//Default Sort, order by last updated
let defaultOrderBy = ' ORDER BY note.pinned DESC, updated DESC, note.created DESC, note.opened DESC, id DESC'
let defaultOrderBy = ' ORDER BY note.pinned DESC, updated DESC, note.created DESC, note.opened DESC'
//Order by Last Created Date
if(fastFilters.lastCreated == 1){

View File

@@ -5,22 +5,32 @@ const Note = require('@models/Note')
const db = require('@config/database')
const Auth = require('@helpers/Auth')
const cs = require('@helpers/CryptoString')
const speakeasy = require('speakeasy')
let User = module.exports = {}
const version = '3.0.1'
const version = '3.1.3'
//Login a user, if that user does not exist create them
//Issues login token
User.login = (username, password) => {
User.login = (username, password, authToken = null) => {
return new Promise((resolve, reject) => {
const lowerName = username.toLowerCase();
const lowerName = username.toLowerCase()
let statusObject = {
success: false,
token: null,
userId: null,
verificationRequired: false,
message: 'Incorrect Username or Password'
}
db.promise()
.query('SELECT * FROM user WHERE username = ? LIMIT 1', [lowerName])
.then((rows, fields) => {
//
// Login User
//
if(rows[0].length == 1){
@@ -28,34 +38,76 @@ User.login = (username, password) => {
//Pull out user data from database results
const lookedUpUser = rows[0][0]
//hash the password and check for a match
// const salt = new Buffer(lookedUpUser.salt, 'binary')
const salt = Buffer.from(lookedUpUser.salt, 'binary')
crypto.pbkdf2(password, salt, lookedUpUser.iterations, 512, 'sha512', function(err, delivered_key){
if(delivered_key.toString('hex') === lookedUpUser.password){
//Verify Token if set
const tokenValidates = speakeasy.totp.verify({
'secret': lookedUpUser['two_fa_secret'],
'encoding': 'base32',
'token': authToken,
'window': 2
})
User.generateMasterKey(lookedUpUser.id, password)
.then( result => User.getMasterKey(lookedUpUser.id, password))
.then(masterKey => {
if(lookedUpUser.two_fa_enabled == 1 && !authToken){
User.generateKeypair(lookedUpUser.id, masterKey)
.then(({publicKey, privateKey}) => {
statusObject['verificationRequired'] = true
statusObject['message'] = '2FA authentication required.'
//Passback a json web token
Auth.createToken(lookedUpUser.id, masterKey)
.then(token => {
return resolve({ token: token, userId:lookedUpUser.id })
return resolve(statusObject)
}
if(lookedUpUser.two_fa_enabled == 1 && !tokenValidates){
statusObject['verificationRequired'] = true
statusObject['message'] = 'Invalid Authorization Token.'
return resolve(statusObject)
}
if(lookedUpUser.two_fa_enabled == 0 || (lookedUpUser.two_fa_enabled == 1 && tokenValidates) ){
//hash the password and check for a match
const salt = Buffer.from(lookedUpUser.salt, 'binary')
crypto.pbkdf2(password, salt, lookedUpUser.iterations, 512, 'sha512', function(err, delivered_key){
if(delivered_key.toString('hex') === lookedUpUser.password){
User.generateMasterKey(lookedUpUser.id, password)
.then( result => User.getMasterKey(lookedUpUser.id, password))
.then(masterKey => {
User.generateKeypair(lookedUpUser.id, masterKey)
.then(({publicKey, privateKey}) => {
//Passback a json web token
Auth.createToken(lookedUpUser.id, masterKey)
.then(token => {
statusObject['token'] = token
statusObject['userId'] = lookedUpUser.id
statusObject['success'] = true
return resolve(statusObject)
})
})
})
})
} else {
} else {
return resolve(statusObject)
}
})
}
reject('Password does not match database')
}
})
} else {
return reject('Incorrect Username or Password')
//If user is not found, say two factor authentication is required
statusObject['verificationRequired'] = true
statusObject['message'] = '2FA authentication required.'
//Show fake auth token message
if(authToken){
statusObject['message'] = 'Invalid Authorization Token.'
}
return resolve(statusObject)
}
})
.catch(console.log)
@@ -186,6 +238,12 @@ User.getCounts = (userId) => {
Object.assign(countTotals, rows[0][0]) //combine results
return db.promise().query('SELECT two_fa_enabled FROM user WHERE id = ?', [userId])
}).then( (rows, fields) => {
Object.assign(countTotals, rows[0][0]) //combine results
//Convert everything to an int or 0
Object.keys(countTotals).forEach( key => {
const count = parseInt(countTotals[key])
@@ -253,13 +311,12 @@ User.generateMasterKey = (userId, password) => {
}
User.getMasterKey = (userId, password) => {
if(!userId || !password){
reject('Need userId and password to fetch key')
}
return new Promise((resolve, reject) => {
if(!userId || !password){
reject('Need userId and password to fetch key')
}
db.promise().query('SELECT * FROM user_key WHERE user_id = ? LIMIT 1', [userId])
.then((rows, fields) => {