* Adjusted theme colors to add more contrast on white theme while making black more OLED friendly
* Links now get an underline on hover * Cleaned up CSS variable names, added another theme color for more control * Cleaned up unused CSS, removed scrollbars popping up, tons of other little UI tweaks * Renamed shared notes to inbox * Tweaked form display, seperated login and create accouts * Put login/sign up form on home page * Created more legitimate marketing for home page * Tons up updates to note page and note input panel * Better support for two users editing a note * MUCH better diff handling, web sockets restore notes with unsaved diffs * Moved all squire text modifier functions into a mixin class * It now says saving when closing a note * Lots of cleanup and better handiling of events on mount and destroy * Scroll behavior modified to load notes when closer to bottom of page * Pretty decent shared notes and sharable link support * Updated help text * Search now includes tag suggestions and attachment suggestions * Cleaned up scratch pad a ton, allow for users to create new scratch pads * Created a 404 Page and a Shared note page * So many other small improvements. Oh my god, what is wrong with me, not doing commits!?
This commit is contained in:
1 parent
8e5e06be9b
commit
6bb856689d
31 files changed
+1605
-1095
No files matched your search
+175
-121
@@ -12,19 +12,19 @@ let ShareNote = module.exports = {}
|
||||
const crypto = require('crypto')
|
||||
const cs = require('@helpers/CryptoString')
|
||||
|
||||
ShareNote.migrateNoteToShared = (userId, noteId, shareUserId, masterKey) => {
|
||||
ShareNote.addUserToSharedNote = (userId, noteId, shareUserId, masterKey) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
const Note = require('@models/Note')
|
||||
const User = require('@models/User')
|
||||
|
||||
//generate new random salts and password
|
||||
const sharedNoteMasterKey = cs.createSmallSalt()
|
||||
let sharedNoteMasterKey = null
|
||||
|
||||
let encryptedSharedKey = null //new key for note encrypted with shared users pubic key
|
||||
|
||||
//Current note object
|
||||
let note = null
|
||||
let noteObject = null
|
||||
let publicKey = null
|
||||
|
||||
db.promise().query('SELECT id FROM user WHERE id = ?', [shareUserId])
|
||||
@@ -34,20 +34,16 @@ ShareNote.migrateNoteToShared = (userId, noteId, shareUserId, masterKey) => {
|
||||
throw new Error('User Does Not Exist')
|
||||
}
|
||||
|
||||
return Note.get(userId, noteId, masterKey)
|
||||
return ShareNote.migrateToShared(userId, noteId, masterKey)
|
||||
|
||||
})
|
||||
.then( noteObject => {
|
||||
.then(({note, sharedNoteKey})=> {
|
||||
|
||||
if(!noteObject){
|
||||
throw new Error('Note Not Found')
|
||||
}
|
||||
|
||||
note = noteObject
|
||||
sharedNoteMasterKey = sharedNoteKey
|
||||
noteObject = note
|
||||
|
||||
return db.promise()
|
||||
.query('SELECT id FROM note WHERE user_id = ? AND note_raw_text_id = ?', [shareUserId, note.rawTextId])
|
||||
|
||||
})
|
||||
.then((rows, fields) => {
|
||||
|
||||
@@ -55,46 +51,6 @@ ShareNote.migrateNoteToShared = (userId, noteId, shareUserId, masterKey) => {
|
||||
throw new Error('User Already has this note shared with them')
|
||||
}
|
||||
|
||||
//All check pass, proceed with sharing note
|
||||
return User.getPublicKey(userId)
|
||||
})
|
||||
.then( userPublicKey => {
|
||||
|
||||
//Get users public key
|
||||
publicKey = userPublicKey
|
||||
|
||||
//
|
||||
// Modify note to have a shared password, encrypt text with this password
|
||||
//
|
||||
const sharedNoteSalt = cs.createSmallSalt()
|
||||
|
||||
//Encrypt note text with new password
|
||||
const textObject = JSON.stringify([note.title, note.text])
|
||||
const encryptedText = cs.encrypt(sharedNoteMasterKey, sharedNoteSalt, textObject)
|
||||
|
||||
//Update note raw text with new data
|
||||
return db.promise()
|
||||
.query("UPDATE `application`.`note_raw_text` SET `text` = ?, `salt` = ? WHERE (`id` = ?)",
|
||||
[encryptedText, sharedNoteSalt, note.rawTextId])
|
||||
|
||||
})
|
||||
.then((rows, fields) => {
|
||||
|
||||
//New Encrypted snippet, using new shared password
|
||||
const sharedNoteSnippetSalt = cs.createSmallSalt()
|
||||
const snippet = JSON.stringify([note.title, note.text.substring(0, 500)])
|
||||
const encryptedSnippet = cs.encrypt(sharedNoteMasterKey, sharedNoteSnippetSalt, snippet)
|
||||
|
||||
//Encrypt shared password for this user
|
||||
const encryptedSharedKey = crypto.publicEncrypt(publicKey, Buffer.from(sharedNoteMasterKey, 'utf8')).toString('base64')
|
||||
|
||||
//Update note snippet for current user with public key encoded snippet
|
||||
return db.promise().query('UPDATE note SET snippet = ?, snippet_salt = ?, encrypted_share_password_key = ?, shared = 2 WHERE id = ? AND user_id = ?',
|
||||
[encryptedSnippet, sharedNoteSnippetSalt, encryptedSharedKey, noteId, userId])
|
||||
|
||||
})
|
||||
.then((rows, fields) => {
|
||||
|
||||
return User.getPublicKey(shareUserId)
|
||||
|
||||
})
|
||||
@@ -102,7 +58,7 @@ ShareNote.migrateNoteToShared = (userId, noteId, shareUserId, masterKey) => {
|
||||
|
||||
//New Encrypted snippet, using new shared password
|
||||
const newSnippetSalt = cs.createSmallSalt()
|
||||
const snippet = JSON.stringify([note.title, note.text.substring(0, 500)])
|
||||
const snippet = JSON.stringify([noteObject.title, noteObject.text.substring(0, 500)])
|
||||
const encryptedSnippet = cs.encrypt(sharedNoteMasterKey, newSnippetSalt, snippet)
|
||||
|
||||
//Encrypt shared password for this user
|
||||
@@ -111,7 +67,7 @@ ShareNote.migrateNoteToShared = (userId, noteId, shareUserId, masterKey) => {
|
||||
//Insert new note for shared user
|
||||
return db.promise().query(`
|
||||
INSERT INTO note (user_id, note_raw_text_id, created, color, share_user_id, snippet, snippet_salt, encrypted_share_password_key) VALUES (?,?,?,?,?,?,?,?);
|
||||
`, [shareUserId, note.rawTextId, note.created, note.color, userId, encryptedSnippet, newSnippetSalt, encryptedSharedKey])
|
||||
`, [shareUserId, noteObject.rawTextId, noteObject.created, noteObject.color, userId, encryptedSnippet, newSnippetSalt, encryptedSharedKey])
|
||||
|
||||
})
|
||||
.then((rows, fields) => {
|
||||
@@ -119,7 +75,7 @@ ShareNote.migrateNoteToShared = (userId, noteId, shareUserId, masterKey) => {
|
||||
const sharedUserNoteId = rows[0]['insertId']
|
||||
|
||||
//Emit update count event to user shared with - so they see the note in real time
|
||||
SocketIo.to(sharedUserNoteId).emit('update_counts')
|
||||
SocketIo.to(shareUserId).emit('update_counts')
|
||||
|
||||
let success = true
|
||||
return resolve({success, shareUserId, sharedUserNoteId})
|
||||
@@ -133,7 +89,7 @@ ShareNote.migrateNoteToShared = (userId, noteId, shareUserId, masterKey) => {
|
||||
})
|
||||
}
|
||||
|
||||
ShareNote.removeUserFromShared = (userId, noteId, shareNoteUserId, masterKey) => {
|
||||
ShareNote.removeUserFromSharedNote = (userId, noteId, shareNoteUserId, masterKey) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
let rawTextId = null
|
||||
@@ -160,32 +116,9 @@ ShareNote.removeUserFromShared = (userId, noteId, shareNoteUserId, masterKey) =>
|
||||
//Convert back to normal note if there is only one person with this note
|
||||
if(rows[0][0]['count'] == 1){
|
||||
|
||||
Note.get(userId, noteId, masterKey)
|
||||
.then(noteObject => {
|
||||
|
||||
const salt = cs.createSmallSalt()
|
||||
const snippetSalt = cs.createSmallSalt()
|
||||
|
||||
const snippetObj = JSON.stringify([noteObject.title, noteObject.text.substring(0, 500)])
|
||||
const snippet = cs.encrypt(masterKey, snippetSalt, snippetObj)
|
||||
|
||||
const textObject = JSON.stringify([noteObject.title, noteObject.text])
|
||||
const encryptedText = cs.encrypt(masterKey, salt, textObject)
|
||||
|
||||
db.promise()
|
||||
.query(`UPDATE note SET snippet = ?, snippet_salt = ?, encrypted_share_password_key = ?, shared = 0 WHERE id = ? AND user_id = ?`,
|
||||
[snippet, snippetSalt, null, noteId, userId])
|
||||
.then((r,f) => {
|
||||
|
||||
db.promise()
|
||||
.query('UPDATE note_raw_text SET text = ?, salt = ? WHERE id = ?',
|
||||
[encryptedText, salt, noteObject.rawTextId])
|
||||
.then(() => {
|
||||
return resolve(true)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
return ShareNote.migrateToNormal(userId, noteId, masterKey)
|
||||
.then(results => {
|
||||
resolve(true)
|
||||
})
|
||||
|
||||
} else {
|
||||
@@ -196,9 +129,163 @@ ShareNote.removeUserFromShared = (userId, noteId, shareNoteUserId, masterKey) =>
|
||||
})
|
||||
}
|
||||
|
||||
// Get users who see a shared note
|
||||
ShareNote.getUsers = (userId, rawTextId) => {
|
||||
//Encrypt note with private shared key
|
||||
ShareNote.migrateToShared = (userId, noteId, masterKey) => {
|
||||
|
||||
const User = require('@models/User')
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
//generate new random password
|
||||
const sharedNoteMasterKey = cs.createSmallSalt()
|
||||
let userPublicKey = null
|
||||
let userPrivateKey = null
|
||||
let note = null
|
||||
|
||||
User.generateKeypair(userId, masterKey)
|
||||
.then( ({publicKey, privateKey}) => {
|
||||
|
||||
//Get users public key
|
||||
userPublicKey = publicKey
|
||||
userPrivateKey = privateKey
|
||||
|
||||
return Note.get(userId, noteId, masterKey)
|
||||
})
|
||||
.then(noteObject => {
|
||||
|
||||
note = noteObject
|
||||
|
||||
if(note.shared == 2){
|
||||
|
||||
//Note is already shared, decrypt sharedKey
|
||||
let sharedNoteKey = null
|
||||
const encryptedShareKey = note.encrypted_share_password_key
|
||||
if(encryptedShareKey != null){
|
||||
sharedNoteKey = crypto.privateDecrypt(userPrivateKey,
|
||||
Buffer.from(encryptedShareKey, 'base64') )
|
||||
}
|
||||
|
||||
return resolve({note, sharedNoteKey})
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// Update raw_text to have a shared password, encrypt text with this password
|
||||
//
|
||||
const sharedNoteSalt = cs.createSmallSalt()
|
||||
|
||||
//Encrypt note text with new password
|
||||
const textObject = JSON.stringify([note.title, note.text])
|
||||
const encryptedText = cs.encrypt(sharedNoteMasterKey, sharedNoteSalt, textObject)
|
||||
|
||||
//Update note raw text with new data
|
||||
db.promise()
|
||||
.query("UPDATE `application`.`note_raw_text` SET `text` = ?, `salt` = ? WHERE (`id` = ?)",
|
||||
[encryptedText, sharedNoteSalt, note.rawTextId])
|
||||
.then((rows, fields) => {
|
||||
|
||||
//
|
||||
// Update snippet using new shared password
|
||||
// + Save shared password (encrypted with public key)
|
||||
//
|
||||
const sharedNoteSnippetSalt = cs.createSmallSalt()
|
||||
const snippet = JSON.stringify([note.title, note.text.substring(0, 500)])
|
||||
const encryptedSnippet = cs.encrypt(sharedNoteMasterKey, sharedNoteSnippetSalt, snippet)
|
||||
|
||||
//Encrypt shared password for this user
|
||||
const encryptedSharedKey = crypto.publicEncrypt(userPublicKey, Buffer.from(sharedNoteMasterKey, 'utf8')).toString('base64')
|
||||
|
||||
//Update note snippet for current user with public key encoded snippet
|
||||
return db.promise().query('UPDATE note SET snippet = ?, snippet_salt = ?, encrypted_share_password_key = ?, shared = 2 WHERE id = ? AND user_id = ?',
|
||||
[encryptedSnippet, sharedNoteSnippetSalt, encryptedSharedKey, noteId, userId])
|
||||
|
||||
})
|
||||
.then((rows, fields) => {
|
||||
return resolve({note, 'sharedNoteKey':sharedNoteMasterKey})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
})
|
||||
}
|
||||
//Remove private shared key, encrypt note with users master password
|
||||
ShareNote.migrateToNormal = (userId, noteId, masterKey) => {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
Note.get(userId, noteId, masterKey)
|
||||
.then(noteObject => {
|
||||
|
||||
const salt = cs.createSmallSalt()
|
||||
const snippetSalt = cs.createSmallSalt()
|
||||
|
||||
const snippetObj = JSON.stringify([noteObject.title, noteObject.text.substring(0, 500)])
|
||||
const snippet = cs.encrypt(masterKey, snippetSalt, snippetObj)
|
||||
|
||||
const textObject = JSON.stringify([noteObject.title, noteObject.text])
|
||||
const encryptedText = cs.encrypt(masterKey, salt, textObject)
|
||||
|
||||
db.promise()
|
||||
.query(`UPDATE note SET snippet = ?, snippet_salt = ?, encrypted_share_password_key = ?, shared = 0 WHERE id = ? AND user_id = ?`,
|
||||
[snippet, snippetSalt, null, noteId, userId])
|
||||
.then((r,f) => {
|
||||
|
||||
db.promise()
|
||||
.query('UPDATE note_raw_text SET text = ?, salt = ? WHERE id = ?',
|
||||
[encryptedText, salt, noteObject.rawTextId])
|
||||
.then(() => {
|
||||
return resolve(true)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
ShareNote.decryptSharedKey = (userId, noteId, masterKey) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
let userPrivateKey = null
|
||||
|
||||
const User = require('@models/User')
|
||||
User.generateKeypair(userId, masterKey)
|
||||
.then( ({publicKey, privateKey}) => {
|
||||
|
||||
userPrivateKey = privateKey
|
||||
|
||||
return Note.get(userId, noteId, masterKey)
|
||||
})
|
||||
.then(noteObject => {
|
||||
|
||||
//Shared notes use encrypted key - decrypt key then return it.
|
||||
const encryptedShareKey = noteObject.encrypted_share_password_key
|
||||
|
||||
if(encryptedShareKey != null && userPrivateKey != null){
|
||||
const currentNoteKey = crypto.privateDecrypt(userPrivateKey,
|
||||
Buffer.from(encryptedShareKey, 'base64') )
|
||||
|
||||
return resolve(currentNoteKey)
|
||||
|
||||
} else {
|
||||
return resolve(null)
|
||||
}
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Get users who see a shared note
|
||||
ShareNote.getShareInfo = (userId, noteId, rawTextId) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
let shareUsers = []
|
||||
let shareStatus = 0
|
||||
|
||||
db.promise()
|
||||
.query(`
|
||||
SELECT username, note.id as noteId
|
||||
@@ -211,47 +298,14 @@ ShareNote.getUsers = (userId, rawTextId) => {
|
||||
.then((rows, fields) => {
|
||||
|
||||
//Return a list of user names
|
||||
return resolve (rows[0])
|
||||
shareUsers = rows[0]
|
||||
return db.promise().query('SELECT shared FROM note WHERE id = ? AND user_id = ?', [noteId, userId])
|
||||
})
|
||||
})
|
||||
}
|
||||
.then((rows, fields) => {
|
||||
|
||||
// Remove a user from a shared note
|
||||
ShareNote.removeUser = (userId, noteId) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
const Note = require('@models/Note')
|
||||
|
||||
let rawTextId = null
|
||||
let removeUserId = null
|
||||
|
||||
//note.id = noteId, share_user_id = userId
|
||||
db.promise()
|
||||
.query('SELECT note_raw_text_id, user_id FROM note WHERE id = ? AND share_user_id = ?', [noteId, userId])
|
||||
.then( (rows, fields) => {
|
||||
|
||||
rawTextId = rows[0][0]['note_raw_text_id']
|
||||
removeUserId = rows[0][0]['user_id']
|
||||
|
||||
//Delete note entry for other user - remove users access
|
||||
if(removeUserId && Number.isInteger(removeUserId)){
|
||||
//Delete this users access to the note
|
||||
return Note.delete(removeUserId, noteId, masterKey)
|
||||
|
||||
} else {
|
||||
|
||||
return new Promise((resolve, reject) => { resolve(true) })
|
||||
}
|
||||
shareStatus = rows[0][0]['shared']
|
||||
|
||||
return resolve({ shareStatus, shareUsers })
|
||||
})
|
||||
.then(stuff => {
|
||||
resolve(true)
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
resolve(false)
|
||||
})
|
||||
|
||||
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user