Unlock a key by clicking its name. Lock it by clicking it again.
Copy the key and store it in a very secure place to have a way to access notes
in case the password is forgotten, or database is corrupted.
Click "View key" after unlocking it.
${createButton}
${createComponents}
Keys
${keys}
`
}//}}}
generateKey() {//{{{
let keyTextarea = document.getElementById('key-key')
let key = sjcl.codec.hex.fromBits(Crypto.generate_key()).replace(/(....)/g, '$1 ').trim()
keyTextarea.value = key
}//}}}
validateNewKey() {//{{{
let keyDescription = document.getElementById('key-description').value
let keyTextarea = document.getElementById('key-key').value
let pass1 = document.getElementById('key-pass1').value
let pass2 = document.getElementById('key-pass2').value
if(keyDescription.trim() == '')
throw new Error('The key has to have a description')
if(pass1.trim() == '' || pass1.length < 4)
throw new Error('The password has to be at least 4 characters long.')
if(pass1 != pass2)
throw new Error(`Passwords doesn't match`)
let cleanKey = keyTextarea.replace(/\s+/g, '')
if(!cleanKey.match(/^[0-9a-f]{64}$/i))
throw new Error('Invalid key - has to be 64 characters of 0-9 and A-F')
}//}}}
createKey() {//{{{
try {
this.validateNewKey()
let description = document.getElementById('key-description').value
let keyAscii = document.getElementById('key-key').value
let pass1 = document.getElementById('key-pass1').value
// Key in hex taken from user.
let actual_key = sjcl.codec.hex.toBits(keyAscii.replace(/\s+/g, ''))
// Key generated from password, used to encrypt the actual key.
let pass_gen = Crypto.pass_to_key(pass1)
let crypto = new Crypto(pass_gen.key)
let encrypted_actual_key = crypto.encrypt(actual_key, 0x1n, false)
// Database value is salt + actual key, needed to generate the same key from the password.
let db_encoded = sjcl.codec.hex.fromBits(
pass_gen.salt.concat(encrypted_actual_key)
)
// Create on server.
window._app.current.request('/key/create', {
description,
key: db_encoded,
})
.then(res=>{
let key = new Key(res.Key, this.props.nodeui.keyCounter)
this.props.nodeui.keys.value = this.props.nodeui.keys.value.concat(key)
})
.catch(window._app.current.responseError)
} catch(err) {
alert(err.message)
return
}
}//}}}
}
export class Key {
constructor(data, counter_callback) {//{{{
this.ID = data.ID
this.description = data.Description
this.encryptedKey = data.Key
this.key = null
this._counter_cbk = counter_callback
let hex_key = window.sessionStorage.getItem(`key-${this.ID}`)
if(hex_key)
this.key = sjcl.codec.hex.toBits(hex_key)
}//}}}
status() {//{{{
if(this.key === null)
return 'locked'
return 'unlocked'
}//}}}
lock() {//{{{
this.key = null
window.sessionStorage.removeItem(`key-${this.ID}`)
}//}}}
unlock(password) {//{{{
let db = sjcl.codec.hex.toBits(this.encryptedKey)
let salt = db.slice(0, 4)
let pass_key = Crypto.pass_to_key(password, salt)
let crypto = new Crypto(pass_key.key)
this.key = crypto.decrypt(sjcl.codec.base64.fromBits(db.slice(4)))
window.sessionStorage.setItem(`key-${this.ID}`, sjcl.codec.hex.fromBits(this.key))
}//}}}
async counter() {//{{{
return this._counter_cbk()
}//}}}
}
export class KeyComponent extends Component {
constructor({ model }) {//{{{
super({ model })
this.state = {
show_key: false,
}
}//}}}
render({ model }, { show_key }) {//{{{
let status = ''
switch(model.status()) {
case 'locked':
status = html``
break
case 'unlocked':
status = html``
break
}
let hex_key = ''
if(show_key) {
if(model.status() == 'locked')
hex_key = html`