Browse Source

import encrypted private key and logout

master
Julian Steinwachs 9 years ago
parent
commit
ea0f8bdde7
  1. 1205
      build/app-bundle.js
  2. 16
      build/twister-lib.js
  3. 40
      jsx/App.js
  4. 6
      jsx/other/Accounts.js
  5. 39
      jsx/other/ExportAccountModalButton.js
  6. 44
      jsx/other/ImportAccountModalButton.js
  7. 67
      jsx/other/LogoutModalButton.js

1205
build/app-bundle.js

File diff suppressed because it is too large Load Diff

16
build/twister-lib.js

@ -32885,7 +32885,7 @@ TwisterPrivKey.prototype.encryptPrivateKey = function(passphrase,cbfunc,progress
var privateKeyWif = thisResource._btcKey.toWIF() var privateKeyWif = thisResource._btcKey.toWIF()
var bip38 = new Bip38() var bip38 = new Bip38();
var encrypted = bip38.encrypt(privateKeyWif, passphrase, thisResource._btcKey.getAddress(), progressfunc) var encrypted = bip38.encrypt(privateKeyWif, passphrase, thisResource._btcKey.getAddress(), progressfunc)
cbfunc(encrypted); cbfunc(encrypted);
@ -32899,6 +32899,7 @@ TwisterPrivKey.prototype.decryptAndImportPrivateKey = function(encryptedKey,pass
setTimeout(function(){ setTimeout(function(){
var bip38 = new Bip38();
var privateKeyWif = bip38.decrypt(encryptedKey, passphrase, progressfunc) var privateKeyWif = bip38.decrypt(encryptedKey, passphrase, progressfunc)
thisResource.setKey(privateKeyWif); thisResource.setKey(privateKeyWif);
cbfunc(thisResource); cbfunc(thisResource);
@ -34571,7 +34572,7 @@ Twister.importClientSideAccountFromEncryptedKey = function (name,encryptedKey,pa
Twister._wallet[name] = new TwisterAccount(name,Twister); Twister._wallet[name] = new TwisterAccount(name,Twister);
Twister._wallet[name]._privkey.decryptAndImportPrivateKey(encryptPrivateKey,passphrase,function(){ Twister._wallet[name]._privkey.decryptAndImportPrivateKey(encryptedKey,passphrase,function(){
Twister._wallet[name]._privkey.verifyKey(function(key){ Twister._wallet[name]._privkey.verifyKey(function(key){
@ -34669,6 +34670,17 @@ Twister.checkUsernameAvailable = function(username,cbfunc){
} }
/** @function
* @name checkUsernameAvailable
* @description checks if username is available by querying for its public key.
*/
Twister.removeAccount = function(username){
delete Twister._wallet[username];
}
/** @function /** @function
* @name serializeCache * @name serializeCache
* @description Flattens the complete cache into a nested object which can be used to reload the cache later. * @description Flattens the complete cache into a nested object which can be used to reload the cache later.

40
jsx/App.js

@ -54,8 +54,8 @@ App = React.createClass({
AppSettingsMixin, AppSettingsMixin,
SetIntervalMixin, SetIntervalMixin,
SafeStateChangeMixin, SafeStateChangeMixin,
EventListenerMixin('newaccountbyuser')], EventListenerMixin('newaccountbyuser'),
EventListenerMixin('accountremovedbyuser')],
getInitialState: function () { getInitialState: function () {
var state={}; var state={};
@ -123,11 +123,18 @@ App = React.createClass({
var thisComponent = this; var thisComponent = this;
Twister.getAccount(newaccoutname).activateTorrents(function(){ var afterwards = function(){
thisComponent.setStateSafe({activeAccount: newaccoutname},function(){ thisComponent.setStateSafe({activeAccount: newaccoutname},function(){
localStorage.setItem("twister-react-activeAccount", newaccoutname); localStorage.setItem("twister-react-activeAccount", newaccoutname);
}); });
}); }
if(newaccoutname){
Twister.getAccount(newaccoutname).activateTorrents(afterwards);
}else{
afterwards();
}
}, },
@ -153,6 +160,31 @@ App = React.createClass({
}, },
onaccountremovedbyuser: function(event) {
console.log("catched onaccountremovedbyuser event !!!!! ",event,this.state)
this.saveCache();
this.setState(function(oldstate,props){
oldstate.accounts = oldstate.accounts.filter(function(acc){
return acc.name!=event.detail.username;
})
return oldstate;
})
if(this.state.activeAccount && this.state.activeAccount==event.detail.username){
this.switchAccount(this.state.accounts.find(function(acc){
return acc.name!=event.detail.username && acc.status=="confirmed";
})||null);
}
},
render: function() { render: function() {
var route = this.props.location.pathname.split("/").filter(function(s){ var route = this.props.location.pathname.split("/").filter(function(s){

6
jsx/other/Accounts.js

@ -5,8 +5,9 @@ var EventListenerMixin = require('../common/EventListenerMixin.js');
var AppSettingsMixin = require('../common/AppSettingsMixin.js'); var AppSettingsMixin = require('../common/AppSettingsMixin.js');
var ImportAccountModalButton = require('../other/ImportAccountModalButton.js'); var ImportAccountModalButton = require('../other/ImportAccountModalButton.js');
var ExportAccountModalButton = require('../other/ExportAccountModalButton.js');
var GenerateAccountModalButton = require('../other/GenerateAccountModalButton.js'); var GenerateAccountModalButton = require('../other/GenerateAccountModalButton.js');
var ExportAccountModalButton = require('../other/ExportAccountModalButton.js');
var LogoutModalButton = require('../other/LogoutModalButton.js');
var ReactBootstrap = require('react-bootstrap') var ReactBootstrap = require('react-bootstrap')
, NavItem = ReactBootstrap.NavItem , NavItem = ReactBootstrap.NavItem
@ -43,7 +44,8 @@ module.exports = Accounts = React.createClass({
<MiniProfile username={acc.name} pollIntervalProfile={thisComponent.props.pollIntervalProfile}/> <MiniProfile username={acc.name} pollIntervalProfile={thisComponent.props.pollIntervalProfile}/>
<p> <p>
{acc.status} {acc.status}
<ExportAccountModalButton username={acc.name}/> <ExportAccountModalButton username={acc.name} accountStatus={acc.status}/>
<LogoutModalButton username={acc.name} accountStatus={acc.status}/>
</p> </p>
</div> </div>
); );

39
jsx/other/ExportAccountModalButton.js

@ -21,10 +21,10 @@ module.exports = ExportAccountModalButton = React.createClass({
useEncryption: true, useEncryption: true,
passphrase1: "", passphrase1: "",
passphrase2: "", passphrase2: "",
setupComplete: false,
encryptionInProgess: false, encryptionInProgess: false,
encryptionComplete: false, encryptionComplete: false,
encryptedKey: "", encryptedKey: "",
publishedOnTiwster: false,
}; };
}, },
handleUseEncryptionChange: function(e) { handleUseEncryptionChange: function(e) {
@ -32,6 +32,8 @@ module.exports = ExportAccountModalButton = React.createClass({
useEncryption: e.target.checked, useEncryption: e.target.checked,
encryptionInProgess: false, encryptionInProgess: false,
encryptionComplete: false, encryptionComplete: false,
encryptedKey: "",
publishedOnTwister: false,
}); });
}, },
handlePassphrase1Change: function(e) { handlePassphrase1Change: function(e) {
@ -39,6 +41,8 @@ module.exports = ExportAccountModalButton = React.createClass({
passphrase1: e.target.value, passphrase1: e.target.value,
encryptionInProgess: false, encryptionInProgess: false,
encryptionComplete: false, encryptionComplete: false,
encryptedKey: "",
publishedOnTwister: false,
}); });
}, },
handlePassphrase2Change: function(e) { handlePassphrase2Change: function(e) {
@ -46,6 +50,8 @@ module.exports = ExportAccountModalButton = React.createClass({
passphrase2: e.target.value, passphrase2: e.target.value,
encryptionInProgess: false, encryptionInProgess: false,
encryptionComplete: false, encryptionComplete: false,
encryptedKey: "",
publishedOnTwister: false,
}); });
}, },
handleToggle: function () { handleToggle: function () {
@ -83,6 +89,21 @@ module.exports = ExportAccountModalButton = React.createClass({
return; return;
}, },
publishOnTwister: function() {
var thisComponent = this;
if(this.state.useEncryption && this.state.encryptedKey.length && this.state.encryptedKey.startsWith("6P")){
Twister.getAccount(this.props.username).updateProfileFields({bip38:this.state.encryptedKey},function(profile){
thisComponent.setStateSafe({publishedOnTwister: true});
})
}
},
render: function() { render: function() {
var belowForm = ( var belowForm = (
@ -106,16 +127,32 @@ module.exports = ExportAccountModalButton = React.createClass({
var mailToLink = "mailto:?body=" + encodeURIComponent(formattedBody) + "&subject=" + encodeURIComponent(subject); var mailToLink = "mailto:?body=" + encodeURIComponent(formattedBody) + "&subject=" + encodeURIComponent(subject);
var dataUrl = "data:text/plain;charset=utf-8;base64,"+btoa(this.state.encryptedKey);
var publishOnTwisterDisabled = this.props.accountStatus != "confirmed";
var publishedOnTwisterButtonStr = "Publish on Twister" + (this.state.publishedOnTwister?" ✓":"");
belowForm = ( belowForm = (
<p> <p>
{"Your encrypted key: "+this.state.encryptedKey} {"Your encrypted key: "+this.state.encryptedKey}
<br/>
<Button download="twisterkey.txt" href={dataUrl}>Download</Button>
<Button href={mailToLink}>Send via Email</Button> <Button href={mailToLink}>Send via Email</Button>
<Button onClick={this.publishOnTwister} disabled={publishOnTwisterDisabled}>{publishedOnTwisterButtonStr}</Button>
</p> </p>
) )
}else{ }else{
var dataUrl = "data:text/plain;charset=utf-8;base64,"+btoa(this.state.encryptedKey);
belowForm = ( belowForm = (
<p> <p>
{"Your private key: "+this.state.encryptedKey} {"Your private key: "+this.state.encryptedKey}
<Button download="twisterkey.txt" href={dataUrl}>Download</Button>
<Button disabled>Send via Email</Button>
<Button disabled>Publish on Twister</Button>
</p> </p>
) )
} }

44
jsx/other/ImportAccountModalButton.js

@ -12,11 +12,13 @@ var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
var SetIntervalMixin = require("../common/SetIntervalMixin.js"); var SetIntervalMixin = require("../common/SetIntervalMixin.js");
module.exports = ImportAccountModalButton = React.createClass({ module.exports = ImportAccountModalButton = React.createClass({
mixins: [SafeStateChangeMixin],
getInitialState: function () { getInitialState: function () {
return { return {
isModalOpen: false, isModalOpen: false,
privkey: "", privkey: "",
username: "", username: "",
passphrase: "",
}; };
}, },
handlePrivkeyChange: function(e) { handlePrivkeyChange: function(e) {
@ -25,19 +27,40 @@ module.exports = ImportAccountModalButton = React.createClass({
handleUsernameChange: function(e) { handleUsernameChange: function(e) {
this.setState({username: e.target.value}); this.setState({username: e.target.value});
}, },
handlePassphraseChange: function(e) {
this.setState({passphrase: e.target.value});
},
handleToggle: function () { handleToggle: function () {
this.setState({ this.setState({
isModalOpen: !this.state.isModalOpen isModalOpen: !this.state.isModalOpen
}); });
}, },
pullFromTwister: function(){
var thisComponent = this;
Twister.getUser(this.state.username).doProfile(function(profile){
var key = profile.getField("bip38");
if(key) {
thisComponent.setStateSafe({privkey:key});
}
})
},
handleImportAccount: function (e) { handleImportAccount: function (e) {
var thisComponent = this;
e.preventDefault(); e.preventDefault();
var newprivkey = this.state.privkey; var newprivkey = this.state.privkey;
var newusername = this.state.username; var newusername = this.state.username;
var passphrase = this.state.passphrase;
Twister.importClientSideAccount(newusername,newprivkey,function(newaccount){ var success = function(newaccount){
console.log(newaccount._name); console.log(newaccount._name);
@ -45,9 +68,15 @@ module.exports = ImportAccountModalButton = React.createClass({
//alert("scrolled to bottom") //alert("scrolled to bottom")
window.dispatchEvent(event); window.dispatchEvent(event);
}) thisComponent.handleToggle();
}
this.handleToggle(); if(passphrase.length){
Twister.importClientSideAccountFromEncryptedKey(newusername,newprivkey,passphrase,success)
}else{
Twister.importClientSideAccount(newusername,newprivkey,success)
}
return; return;
}, },
@ -70,10 +99,17 @@ module.exports = ImportAccountModalButton = React.createClass({
/> />
<Input <Input
type='text' type='text'
label='Private Key' label='(Encrypted) Private Key'
value={this.state.privkey} value={this.state.privkey}
onChange={this.handlePrivkeyChange} onChange={this.handlePrivkeyChange}
/> />
<Button onClick={this.pullFromTwister}>Pull From Twister</Button>
<Input
type='password'
label='Passphrase (only for encrypted keys)'
value={this.state.passphrase}
onChange={this.handlePassphraseChange}
/>
<Input type='submit' value='Import Account' data-dismiss="modal" /> <Input type='submit' value='Import Account' data-dismiss="modal" />
</form> </form>
</Modal.Body> </Modal.Body>

67
jsx/other/LogoutModalButton.js

@ -0,0 +1,67 @@
var ReactBootstrap = require('react-bootstrap')
, Button = ReactBootstrap.Button
, ButtonGroup = ReactBootstrap.ButtonGroup
, Glyphicon = ReactBootstrap.Glyphicon
, Modal = ReactBootstrap.Modal
, Input = ReactBootstrap.Input
var React = require('react');
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
var SetIntervalMixin = require("../common/SetIntervalMixin.js");
module.exports = LogoutModalButton = React.createClass({
mixins: [
SafeStateChangeMixin
],
getInitialState: function () {
return {
isModalOpen: false,
};
},
handleToggle: function () {
this.setState({
isModalOpen: !this.state.isModalOpen
});
},
handleLogout: function (e) {
var thisComponent = this;
e.preventDefault();
var username = this.props.username;
Twister.removeAccount(this.props.username);
var event = new CustomEvent('accountremovedbyuser',{detail: {username:this.props.username}});
//alert("scrolled to bottom")
window.dispatchEvent(event);
thisComponent.handleToggle();
return;
},
render: function() {
return (
<Button onClick={this.handleToggle}>
Logout
<Modal show={this.state.isModalOpen} bsStyle='primary' onHide={this.handleToggle}>
<Modal.Header>
<Glyphicon glyph='export'/>
</Modal.Header>
<Modal.Body>
<form onSubmit={this.handleLogout}>
<p>
Are you sure you want to logout? Be sure that you exported your private key. Othervise your account will be lost.
</p>
<Input type='submit' value='Logout'/>
</form>
</Modal.Body>
</Modal>
</Button>
);
}
});
Loading…
Cancel
Save