114 lines
2.6 KiB
JavaScript
114 lines
2.6 KiB
JavaScript
import 'preact/devtools'
|
|
import { h, Component } from 'preact'
|
|
import htm from 'htm'
|
|
import Crypto from 'crypto'
|
|
const html = htm.bind(h)
|
|
|
|
export class Keys extends Component {
|
|
constructor(props) {//{{{
|
|
super(props)
|
|
this.retrieveKeys()
|
|
}//}}}
|
|
render({ nodeui }) {//{{{
|
|
let keys = nodeui.keys.value
|
|
.sort((a,b)=>{
|
|
if(a.description < b.description) return -1
|
|
if(a.description > b.description) return 1
|
|
return 0
|
|
})
|
|
.map(key=>
|
|
html`<${KeyComponent} key=${`key-${key.ID}`} model=${key} />`
|
|
)
|
|
|
|
return html`
|
|
<div id="keys">
|
|
<h1>Keys</h1>
|
|
<div class="key-list">
|
|
${keys}
|
|
</div>
|
|
</div>`
|
|
}//}}}
|
|
|
|
retrieveKeys() {//{{{
|
|
window._app.current.request('/key/retrieve', {})
|
|
.then(res=>{
|
|
this.props.nodeui.keys.value = res.Keys.map(keyData=>new Key(keyData))
|
|
})
|
|
.catch(window._app.current.responseError)
|
|
}//}}}
|
|
}
|
|
|
|
export class Key {
|
|
constructor(data) {//{{{
|
|
this.ID = data.ID
|
|
this.description = data.Description
|
|
this.unlockedKey = data.Key
|
|
this.key = null
|
|
|
|
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.unlockedKey)
|
|
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))
|
|
}//}}}
|
|
}
|
|
|
|
export class KeyComponent extends Component {
|
|
render({ model }) {//{{{
|
|
let status = ''
|
|
switch(model.status()) {
|
|
case 'locked':
|
|
status = html`<div class="status locked"><img src="/images/${window._VERSION}/padlock-closed.svg" /></div>`
|
|
break
|
|
|
|
case 'unlocked':
|
|
status = html`<div class="status unlocked"><img src="/images/${window._VERSION}/padlock-open.svg" /></div>`
|
|
break
|
|
}
|
|
|
|
return html`
|
|
<div class="status" onclick=${()=>this.toggle()}>${status}</div>
|
|
<div class="description" onclick=${()=>this.toggle()}>${model.description}</div>
|
|
`
|
|
}//}}}
|
|
toggle() {//{{{
|
|
if(this.props.model.status() == 'locked')
|
|
this.unlock()
|
|
else
|
|
this.lock()
|
|
}//}}}
|
|
lock() {//{{{
|
|
this.props.model.lock()
|
|
this.forceUpdate()
|
|
}//}}}
|
|
unlock() {//{{{
|
|
let pass = prompt("Password")
|
|
if(!pass)
|
|
return
|
|
|
|
try {
|
|
this.props.model.unlock(pass)
|
|
this.forceUpdate()
|
|
} catch(err) {
|
|
alert(err)
|
|
}
|
|
}//}}}
|
|
}
|
|
|
|
// vim: foldmethod=marker
|