diff --git a/main.go b/main.go index 3c0afb6..2da625f 100644 --- a/main.go +++ b/main.go @@ -279,6 +279,7 @@ func nodeCreate(w http.ResponseWriter, r *http.Request) {// {{{ }) }// }}} func nodeUpdate(w http.ResponseWriter, r *http.Request) {// {{{ + log.Println("/node/update") var err error var session Session diff --git a/static/js/node.mjs b/static/js/node.mjs index bec4d80..22df9e7 100644 --- a/static/js/node.mjs +++ b/static/js/node.mjs @@ -54,7 +54,11 @@ export class NodeUI extends Component { let page = '' switch(this.page.value) { case 'node': - if(node.ID > 0) { + if(node.ID == 0) { + page = html` + ${children.length > 0 ? html`
${children}
` : html``} + ` + } else { let padlock = '' if(node.CryptoKeyID > 0) padlock = html`` @@ -209,7 +213,8 @@ export class NodeUI extends Component { }//}}} saveNode() {//{{{ let content = this.nodeContent.current.contentDiv.current.value - this.node.value.save(content, ()=>this.props.app.nodeModified.value = false) + this.node.value.setContent(content) + this.node.value.save(()=>this.props.app.nodeModified.value = false) }//}}} renameNode() {//{{{ let name = prompt("New name") @@ -299,7 +304,7 @@ class NodeContent extends Component { textarea.parentNode.dataset.replicatedValue = textarea.value }//}}} unlock() {//{{{ - let pass = prompt("Password") + let pass = prompt(`Password for "${this.props.model.description}"`) if(!pass) return @@ -397,21 +402,21 @@ export class Node { }) .catch(this.app.responseError) }//}}} - async save(content, callback) {//{{{ - let update_content = content - /* - * XXX - fix encrypting when saving - if(this.CryptoKeyID != 0) - update_content = await this.#encrypt(content) - */ + async save(callback) {//{{{ + try { + await this.#encrypt() - this.app.request('/node/update', { - NodeID: this.ID, - Content: update_content, - CryptoKeyID: this.CryptoKeyID, - }) - .then(callback) - .catch(this.app.responseError) + let req = { + NodeID: this.ID, + Content: this._content, + CryptoKeyID: this.CryptoKeyID, + } + this.app.request('/node/update', req) + .then(callback) + .catch(this.app.responseError) + } catch (err) { + this.app.responseError(err) + } }//}}} rename(name, callback) {//{{{ this.app.request('/node/rename', { @@ -454,30 +459,26 @@ export class Node { }) }//}}} content() {//{{{ - if(this.CryptoKeyID != 0 && !this._decrypted) { + if(this.CryptoKeyID != 0 && !this._decrypted) this.#decrypt() - } return this._content }//}}} - - async encrypt(obj_key) {//{{{ - if(obj_key.ID != this.CryptoKeyID) - throw('Invalid key') - - let crypto = new Crypto(obj_key.key) - this._decrypted = false - - let counter = await obj_key.counter() - - this.content = sjcl.codec.base64.fromBits( - crypto.encrypt( - sjcl.codec.utf8String.toBits(this.content), - counter, - false, - ) - ) + setContent(new_content) {//{{{ + this._content = new_content + if(this.CryptoKeyID == 0) + // Logic behind plaintext not being decrypted is that + // only encrypted values can be in a decrypted state. + this._decrypted = false + else + this._decrypted = true + }//}}} + async setCryptoKey(new_key) {//{{{ + return this.#encrypt(true, new_key) }//}}} #decrypt() {//{{{ + if(this.CryptoKeyID == 0 || this._decrypted) + return + let obj_key = this.app.nodeUI.current.getKey(this.CryptoKeyID) if(obj_key === null || obj_key.ID != this.CryptoKeyID) throw('Invalid key') @@ -485,7 +486,7 @@ export class Node { // Ask user to unlock key first var pass = null while(pass || obj_key.status() == 'locked') { - pass = prompt("Password") + pass = prompt(`Password for "${obj_key.description}"`) if(!pass) throw new Error(`Key "${obj_key.description}" is locked`) @@ -506,10 +507,25 @@ export class Node { crypto.decrypt(this._content) ) }//}}} - /* - async #encrypt(content) {//{{{ - let obj_key = this.app.nodeUI.current.getKey(this.CryptoKeyID) - if(obj_key === null || obj_key.ID != this.CryptoKeyID) + async #encrypt(change_key = false, new_key = null) {//{{{ + // Nothing to do if not changing key and already encrypted. + if(!change_key && this.CryptoKeyID != 0 && !this._decrypted) + return this._content + + let content = this.content() + + // Changing key to no encryption or already at no encryption - + // set to not decrypted (only encrypted values can be + // decrypted) and return plain value. + if((change_key && new_key === null) || (!change_key && this.CryptoKeyID == 0)) { + this._decrypted = false + this.CryptoKeyID = 0 + return content + } + + let key_id = change_key ? new_key.ID : this.CryptoKeyID + let obj_key = this.app.nodeUI.current.getKey(key_id) + if(obj_key === null || obj_key.ID != key_id) throw('Invalid key') if(obj_key.status() == 'locked') @@ -518,9 +534,11 @@ export class Node { let crypto = new Crypto(obj_key.key) let content_bits = sjcl.codec.utf8String.toBits(content) let counter = await this.app.nodeUI.current.keyCounter() - return crypto.encrypt(content_bits, counter, true) + this.CryptoKeyID = obj_key.ID + this._content = crypto.encrypt(content_bits, counter, true) + this._decrypted = false + return this._content }//}}} - */ } class Menu extends Component { @@ -681,38 +699,26 @@ class NodeProperties extends Component { ` }//}}} - save() {//{{{ + async save() {//{{{ let nodeui = this.props.nodeui let node = nodeui.node.value // Find the actual key object used for encryption - let encrypt_key = nodeui.getKey(this.selected_key_id) - let decrypt_key = nodeui.getKey(node.CryptoKeyID) + let new_key = nodeui.getKey(this.selected_key_id) + let current_key = nodeui.getKey(node.CryptoKeyID) - if(decrypt_key && decrypt_key.status() == 'locked') { + if(current_key && current_key.status() == 'locked') { alert("Decryption key is locked and can not be used.") return } - if(encrypt_key && encrypt_key.status() == 'locked') { + if(new_key && new_key.status() == 'locked') { alert("Key is locked and can not be used.") return } - // Currently not encrypted - encrypt with new key. - let crypto = new Crypto(selected_key.key) - if(node.CryptoKeyID == 0) { - let encrypted = crypto.encrypt( - sjcl.codec.utf8String.toBits(node.Content()), - 1n, - ) - console.log(encrypted) - } - - /* - crypto.encrypt( - ) - */ + await node.setCryptoKey(new_key) + node.save(()=>this.props.nodeui.showPage('node')) }//}}} }