Skip to content

Commit

Permalink
encrypt/decrypt keys
Browse files Browse the repository at this point in the history
  • Loading branch information
joahg committed Jun 18, 2019
1 parent 3e2949c commit ccec1be
Show file tree
Hide file tree
Showing 7 changed files with 244 additions and 2 deletions.
5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Expand Up @@ -46,6 +46,7 @@
"redux-persist": "4.10.2",
"redux-persist-crosstab": "3.7.0",
"sass-loader": "4.1.1",
"sjcl": "^1.0.8",
"webpack": "2.2.0",
"workbox-webpack-plugin": "^4.3.1"
},
Expand Down
1 change: 1 addition & 0 deletions src/actions/index.js
Expand Up @@ -2,3 +2,4 @@

export const ADD_KEY = `ADD_KEY`;
export const REMOVE_KEY = `REMOVE_KEY`;
export const SET_PASSWORD = `SET_PASSWORD`;
10 changes: 10 additions & 0 deletions src/actions/setPassword.js
@@ -0,0 +1,10 @@
'use strict';

import { SET_PASSWORD } from './index.js';

export function setPassword(password) {
return {
type: SET_PASSWORD,
payload: password
};
}
213 changes: 213 additions & 0 deletions src/components/exchange/AccountManager.jsx
@@ -0,0 +1,213 @@
'use strict';

import React from 'react';
import { connect } from 'react-redux';
import { addKey } from '../../actions/addKey.js';
import { removeKey } from '../../actions/removeKey.js';
import { setPassword } from '../../actions/setPassword.js';
import sjcl from 'sjcl';

const valid = `pleaseletmein`, salt = `1f2ifaz66flxr`;

class AccountManager extends React.Component {
constructor(props) {
super(props);

this.state = {
selectedKeyId: ``,
orderType: `market`,
orderSide: `buy`,
orderAmount: 0,
orderPrice: 0,

password: ``,
passwordConfirm: ``,
authenticated: false,
newKey: ``,
newSecret: ``
};
}

savePassword() {
let pw = sjcl.encrypt(this.state.password, valid, { ks: 256, salt });

pw = JSON.stringify({ ...JSON.parse(pw), salt });

this.props.setPassword(pw);
this.setState({
password: ``,
passwordConfirm: ``
});
}

addKey() {
if (this.state.newKey.length == 0) return;

let k = sjcl.encrypt(this.state.password, this.state.newKey, { ks: 256, salt });
k = JSON.stringify({ ...JSON.parse(k), salt });

let s = sjcl.encrypt(this.state.password, this.state.newSecret, { ks: 256, salt });
s = JSON.stringify({ ...JSON.parse(s), salt });

this.props.addKey(this.props.exchange, k, s);

this.setState({
newKey: ``,
newSecret: ``
});
}

render() {
if (this.props.password == ``) {
return (
<div className="account-manager">
<h3>Enter New Password</h3>
<input
type="text"
value={ this.state.password }
onChange={ (e) => this.setState({ password: e.target.value }) }
placeholder={ `New Password` } />
<input
type="text"
value={ this.state.passwordConfirm }
onChange={ (e) => this.setState({ passwordConfirm: e.target.value }) }
placeholder={ `Confirm New Password` } />
<button
onClick={ () => this.savePassword() }
disabled={ this.state.password.length == 0 || this.state.password !== this.state.passwordConfirm }>
Save
</button>
</div>
);
}

try {
if (!this.state.authenticated) {
let p = sjcl.decrypt(this.state.password, this.props.password);

if (p == valid) {
this.setState({
authenticated: true
});
}
}
} /* eslint-disable */ catch(e) { } /* eslint-enable */

if (!this.state.authenticated) {
return (
<div className="account-manager">
<h3>Enter Password To Unlock</h3>
<input
type="text"
value={ this.state.password }
onChange={ (e) => this.setState({ password: e.target.value }) }
placeholder={ `Password` } />
</div>
);
}

let keys = this.props.keys.map((key) => {
let { apiKey, apiSecret } = key;

try {
apiKey = sjcl.decrypt(this.state.password, apiKey);
} /* eslint-disable */ catch(e) { apiKey = `[ encrypted ]` } /*eslint-enable */

try {
apiSecret = sjcl.decrypt(this.state.password, apiSecret);
} /* eslint-disable */ catch(e) { apiSecret = `[ encrypted ]` } /*eslint-enable */

return {
...key,
apiKey,
apiSecret
};
});

return (
<div>
<h3>Keys</h3>
<table>
<thead>
<tr>
<th>
Key
</th>
<th>
Secret
</th>
<th>
Exchange
</th>
<th />
<th />
</tr>
</thead>
<tbody>
{
keys.map((key) => (
<tr key={ key.id }>
<td>{ key.apiKey }</td>
<td>{ key.apiSecret }</td>
<td>{ key.exchange }</td>
<td>
<button onClick={ () => this.props.removeKey(key.id) }>
remove
</button>
</td>
<td>
{
this.state.selectedKeyId !== key.id && (
<button onClick={ () => this.setState({ selectedKeyId: key.id }) }>
select
</button>
)
}
</td>
</tr>
))
}
<tr>
<td>
<input
type="text"
placeholder="API Key"
value={ this.state.newKey }
onChange={ (e) => this.setState({ newKey: e.target.value }) } />
</td>
<td>
<input
type="text"
placeholder="API Secret"
value={ this.state.newSecret }
onChange={ (e) => this.setState({ newSecret: e.target.value }) } />
</td>
<td>
{ this.props.exchange }
</td>
<td>
<button onClick={ () => this.addKey() }>
add
</button>
</td>
<td />
</tr>
</tbody>
</table>
</div>
);
}
}

const mapStateToProps = (state) => ({
password: state.keys.password,
keys: state.keys.keys
});

const mapDispatchToProps = (dispatch) => ({
setPassword: (p) => dispatch(setPassword(p)),
addKey: (e, k, s) => dispatch(addKey(e, k, s)),
removeKey: (id) => dispatch(removeKey(id))
});

export default connect(mapStateToProps, mapDispatchToProps)(AccountManager);
5 changes: 5 additions & 0 deletions src/components/exchange/MarketDataLayer.jsx
Expand Up @@ -11,6 +11,7 @@ import {
import MarketHeader from './MarketHeader.jsx';
import MarketTrades from './MarketTrades.jsx';
import MarketOrderbook from './MarketOrderbook.jsx';
import AccountManager from './AccountManager.jsx';

class MarketDataLayer extends React.Component {
constructor(props) {
Expand Down Expand Up @@ -75,6 +76,10 @@ class MarketDataLayer extends React.Component {
tickerLoaded={ this.state.tickerLoaded }
symbolInfo={ this.state.symbolInfo }
symbolInfoLoaded={ this.state.symbolInfoLoaded } />
<div className="market-widget-row">
<AccountManager
exchange={ this.props.exchange } />
</div>
<div className="market-widget-row">
<MarketTrades
trades={ this.state.trades }
Expand Down
11 changes: 9 additions & 2 deletions src/reducers/keys.js
Expand Up @@ -2,11 +2,13 @@

import {
ADD_KEY,
REMOVE_KEY
REMOVE_KEY,
SET_PASSWORD
} from '../actions';

const initialState = {
keys: []
keys: [],
password: ``
};

export default function login(state = initialState, action) {
Expand All @@ -21,6 +23,11 @@ export default function login(state = initialState, action) {
...state,
keys: state.keys.filter(({ id }) => id !== action.payload)
};
case SET_PASSWORD:
return {
...state,
password: action.payload
};
default:
return state;
}
Expand Down

0 comments on commit ccec1be

Please sign in to comment.