mirror of
https://github.com/twisterarmy/twister-react.git
synced 2025-03-12 13:31:17 +00:00
import encrypted private key and logout
This commit is contained in:
parent
8d2bc300ff
commit
ea0f8bdde7
1209
build/app-bundle.js
1209
build/app-bundle.js
File diff suppressed because it is too large
Load Diff
@ -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
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){
|
||||||
|
@ -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>
|
||||||
);
|
);
|
||||||
|
@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -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,29 +27,56 @@ 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);
|
||||||
|
|
||||||
var event = new CustomEvent('newaccountbyuser',{detail: newaccount});
|
var event = new CustomEvent('newaccountbyuser',{detail: newaccount});
|
||||||
//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
Normal file
67
jsx/other/LogoutModalButton.js
Normal file
@ -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…
x
Reference in New Issue
Block a user