Unverified Commit cf5fad02 authored by roadscape's avatar roadscape Committed by GitHub
Browse files

Merge pull request #109 from steemit/bridge-api-keychain

bridge api keychain
parents a0254519 66cc44e1
...@@ -263,9 +263,6 @@ const mapDispatchToProps = dispatch => ({ ...@@ -263,9 +263,6 @@ const mapDispatchToProps = dispatch => ({
}, },
}); });
const connectedHeader = connect( const connectedHeader = connect(mapStateToProps, mapDispatchToProps)(Header);
mapStateToProps,
mapDispatchToProps
)(Header);
export default connectedHeader; export default connectedHeader;
...@@ -6,6 +6,7 @@ import * as transactionActions from 'app/redux/TransactionReducer'; ...@@ -6,6 +6,7 @@ import * as transactionActions from 'app/redux/TransactionReducer';
import * as globalActions from 'app/redux/GlobalReducer'; import * as globalActions from 'app/redux/GlobalReducer';
import * as userActions from 'app/redux/UserReducer'; import * as userActions from 'app/redux/UserReducer';
import { validate_account_name } from 'app/utils/ChainValidation'; import { validate_account_name } from 'app/utils/ChainValidation';
import { hasCompatibleKeychain } from 'app/utils/SteemKeychain';
import runTests from 'app/utils/BrowserTests'; import runTests from 'app/utils/BrowserTests';
import shouldComponentUpdate from 'app/utils/shouldComponentUpdate'; import shouldComponentUpdate from 'app/utils/shouldComponentUpdate';
import reactForm from 'app/utils/ReactForm'; import reactForm from 'app/utils/ReactForm';
...@@ -34,7 +35,8 @@ class LoginForm extends Component { ...@@ -34,7 +35,8 @@ class LoginForm extends Component {
); );
cryptographyFailure = true; cryptographyFailure = true;
} }
this.state = { cryptographyFailure }; const useKeychain = hasCompatibleKeychain();
this.state = { useKeychain, cryptographyFailure };
this.usernameOnChange = e => { this.usernameOnChange = e => {
const value = e.target.value.toLowerCase(); const value = e.target.value.toLowerCase();
this.state.username.props.onChange(value); this.state.username.props.onChange(value);
...@@ -55,7 +57,7 @@ class LoginForm extends Component { ...@@ -55,7 +57,7 @@ class LoginForm extends Component {
password.props.onChange(data); password.props.onChange(data);
}); });
}; };
this.initForm(props); this.initForm(props, useKeychain);
} }
componentDidMount() { componentDidMount() {
...@@ -67,7 +69,7 @@ class LoginForm extends Component { ...@@ -67,7 +69,7 @@ class LoginForm extends Component {
shouldComponentUpdate = shouldComponentUpdate(this, 'LoginForm'); shouldComponentUpdate = shouldComponentUpdate(this, 'LoginForm');
initForm(props) { initForm(props, useKeychain) {
reactForm({ reactForm({
name: 'login', name: 'login',
instance: this, instance: this,
...@@ -77,11 +79,13 @@ class LoginForm extends Component { ...@@ -77,11 +79,13 @@ class LoginForm extends Component {
username: !values.username username: !values.username
? tt('g.required') ? tt('g.required')
: validate_account_name(values.username.split('/')[0]), : validate_account_name(values.username.split('/')[0]),
password: !values.password password: useKeychain
? tt('g.required') ? null
: PublicKey.fromString(values.password) : !values.password
? tt('loginform_jsx.you_need_a_private_password_or_key') ? tt('g.required')
: null, : PublicKey.fromString(values.password)
? tt('loginform_jsx.you_need_a_private_password_or_key')
: null,
}), }),
}); });
} }
...@@ -99,6 +103,11 @@ class LoginForm extends Component { ...@@ -99,6 +103,11 @@ class LoginForm extends Component {
serverApiRecordEvent('SignIn', onType); serverApiRecordEvent('SignIn', onType);
} }
onUseKeychainCheckbox = e => {
const useKeychain = e.target.checked;
this.setState({ useKeychain });
};
saveLoginToggle = () => { saveLoginToggle = () => {
const { saveLogin } = this.state; const { saveLogin } = this.state;
saveLoginDefault = !saveLoginDefault; saveLoginDefault = !saveLoginDefault;
...@@ -167,7 +176,7 @@ class LoginForm extends Component { ...@@ -167,7 +176,7 @@ class LoginForm extends Component {
} }
const { loginBroadcastOperation, dispatchSubmit, msg } = this.props; const { loginBroadcastOperation, dispatchSubmit, msg } = this.props;
const { username, password, saveLogin } = this.state; const { username, password, useKeychain, saveLogin } = this.state;
const { submitting, valid, handleSubmit } = this.state.login; const { submitting, valid, handleSubmit } = this.state.login;
const { usernameOnChange, onCancel /*qrReader*/ } = this; const { usernameOnChange, onCancel /*qrReader*/ } = this;
const disabled = submitting || !valid; const disabled = submitting || !valid;
...@@ -254,7 +263,7 @@ class LoginForm extends Component { ...@@ -254,7 +263,7 @@ class LoginForm extends Component {
} }
} }
const password_info = const password_info =
checkPasswordChecksum(password.value) === false !useKeychain && checkPasswordChecksum(password.value) === false
? tt('loginform_jsx.password_info') ? tt('loginform_jsx.password_info')
: null; : null;
...@@ -305,7 +314,11 @@ class LoginForm extends Component { ...@@ -305,7 +314,11 @@ class LoginForm extends Component {
onSubmit={handleSubmit(({ data }) => { onSubmit={handleSubmit(({ data }) => {
// bind redux-form to react-redux // bind redux-form to react-redux
console.log('Login\tdispatchSubmit'); console.log('Login\tdispatchSubmit');
return dispatchSubmit(data, loginBroadcastOperation); return dispatchSubmit(
data,
useKeychain,
loginBroadcastOperation
);
})} })}
onChange={this.props.clearError} onChange={this.props.clearError}
method="post" method="post"
...@@ -328,26 +341,34 @@ class LoginForm extends Component { ...@@ -328,26 +341,34 @@ class LoginForm extends Component {
<div className="error">{username.error}&nbsp;</div> <div className="error">{username.error}&nbsp;</div>
) : null} ) : null}
<div> {useKeychain ? (
<input <div>
type="password" {error && <div className="error">{error}&nbsp;</div>}
required </div>
ref="pw" ) : (
placeholder={ <div>
loginType === 'basic' <input
? tt('loginform_jsx.enter_steem_key') type="password"
: tt('loginform_jsx.password_or_wif') required
} ref="pw"
{...password.props} placeholder={
autoComplete="on" loginType === 'basic'
disabled={submitting} ? tt('loginform_jsx.enter_steem_key')
/> : tt('loginform_jsx.password_or_wif')
{error && <div className="error">{error}&nbsp;</div>} }
{error && {...password.props}
password_info && ( autoComplete="on"
<div className="warning">{password_info}&nbsp;</div> disabled={submitting}
)} />
</div> {error && <div className="error">{error}&nbsp;</div>}
{error &&
password_info && (
<div className="warning">
{password_info}&nbsp;
</div>
)}
</div>
)}
{loginBroadcastOperation && ( {loginBroadcastOperation && (
<div> <div>
<div className="info"> <div className="info">
...@@ -358,6 +379,22 @@ class LoginForm extends Component { ...@@ -358,6 +379,22 @@ class LoginForm extends Component {
</div> </div>
</div> </div>
)} )}
{hasCompatibleKeychain() && (
<div>
<label
className="LoginForm__save-login"
htmlFor="useKeychain"
>
<input
id="useKeychain"
type="checkbox"
checked={useKeychain}
onChange={this.onUseKeychainCheckbox}
disabled={submitting}
/>&nbsp;{tt('loginform_jsx.use_keychain')}
</label>
</div>
)}
<div> <div>
<label <label
className="LoginForm__save-login" className="LoginForm__save-login"
...@@ -487,7 +524,7 @@ export default connect( ...@@ -487,7 +524,7 @@ export default connect(
// mapDispatchToProps // mapDispatchToProps
dispatch => ({ dispatch => ({
dispatchSubmit: (data, loginBroadcastOperation) => { dispatchSubmit: (data, useKeychain, loginBroadcastOperation) => {
const { password, saveLogin } = data; const { password, saveLogin } = data;
const username = data.username.trim().toLowerCase(); const username = data.username.trim().toLowerCase();
if (loginBroadcastOperation) { if (loginBroadcastOperation) {
...@@ -503,6 +540,7 @@ export default connect( ...@@ -503,6 +540,7 @@ export default connect(
operation, operation,
username, username,
password, password,
useKeychain,
successCallback, successCallback,
errorCallback, errorCallback,
}) })
...@@ -511,6 +549,7 @@ export default connect( ...@@ -511,6 +549,7 @@ export default connect(
userActions.usernamePasswordLogin({ userActions.usernamePasswordLogin({
username, username,
password, password,
useKeychain,
saveLogin, saveLogin,
operationType: type, operationType: type,
}) })
...@@ -522,6 +561,7 @@ export default connect( ...@@ -522,6 +561,7 @@ export default connect(
userActions.usernamePasswordLogin({ userActions.usernamePasswordLogin({
username, username,
password, password,
useKeychain,
saveLogin, saveLogin,
}) })
); );
......
...@@ -83,7 +83,9 @@ const SidePanel = ({ alignment, visible, hideSidePanel, username }) => { ...@@ -83,7 +83,9 @@ const SidePanel = ({ alignment, visible, hideSidePanel, username }) => {
value: 'blocktrades', value: 'blocktrades',
label: 'Blocktrades', label: 'Blocktrades',
link: username link: username
? `https://blocktrades.us/?input_coin_type=eth&output_coin_type=steem&receive_address=${username}` ? `https://blocktrades.us/?input_coin_type=eth&output_coin_type=steem&receive_address=${
username
}`
: `https://blocktrades.us/?input_coin_type=eth&output_coin_type=steem`, : `https://blocktrades.us/?input_coin_type=eth&output_coin_type=steem`,
}, },
{ {
......
...@@ -724,6 +724,7 @@ ...@@ -724,6 +724,7 @@
"returning_users": "Returning Users: ", "returning_users": "Returning Users: ",
"login_to_wallet": "Login to Wallet", "login_to_wallet": "Login to Wallet",
"sign_transfer": "Sign to complete transfer", "sign_transfer": "Sign to complete transfer",
"use_keychain": "Use keychain extension",
"dont_have_an_account": "Don't have a Steem account?" "dont_have_an_account": "Don't have a Steem account?"
}, },
"chainvalidation_js": { "chainvalidation_js": {
......
...@@ -617,7 +617,8 @@ ...@@ -617,7 +617,8 @@
"sign_up_get_steem": "Crea una cuenta. Comienza en STEEM", "sign_up_get_steem": "Crea una cuenta. Comienza en STEEM",
"signup_button": "Crea una cuenta, comienza a ganar ", "signup_button": "Crea una cuenta, comienza a ganar ",
"signup_button_emphasis": "FREE STEEM!", "signup_button_emphasis": "FREE STEEM!",
"returning_users": "Inicia sesion" "returning_users": "Inicia sesion",
"use_keychain": "Use keychain extension"
}, },
"chainvalidation_js": { "chainvalidation_js": {
"account_name_should": "El nombre de la cuenta debería", "account_name_should": "El nombre de la cuenta debería",
......
...@@ -638,7 +638,8 @@ ...@@ -638,7 +638,8 @@
"sign_up_get_steem": "Sign up. Get STEEM", "sign_up_get_steem": "Sign up. Get STEEM",
"signup_button": "Sign up now to earn ", "signup_button": "Sign up now to earn ",
"signup_button_emphasis": "FREE STEEM!", "signup_button_emphasis": "FREE STEEM!",
"returning_users": "Utilisateurs de retour: " "returning_users": "Utilisateurs de retour: ",
"use_keychain": "Use keychain extension"
}, },
"chainvalidation_js": { "chainvalidation_js": {
"account_name_should": "Le nom du compte doit ", "account_name_should": "Le nom du compte doit ",
......
...@@ -627,7 +627,8 @@ ...@@ -627,7 +627,8 @@
"sign_up_get_steem": "Sign up. Get STEEM", "sign_up_get_steem": "Sign up. Get STEEM",
"signup_button": "Sign up now to earn ", "signup_button": "Sign up now to earn ",
"signup_button_emphasis": "FREE STEEM!", "signup_button_emphasis": "FREE STEEM!",
"returning_users": "Utenti di ritorno:" "returning_users": "Utenti di ritorno:",
"use_keychain": "Use keychain extension"
}, },
"chainvalidation_js": { "chainvalidation_js": {
"account_name_should": "Il nome account", "account_name_should": "Il nome account",
......
...@@ -619,7 +619,8 @@ ...@@ -619,7 +619,8 @@
"signup_button": "サインアップして", "signup_button": "サインアップして",
"signup_button_emphasis": "STEEMを手に入れよう!", "signup_button_emphasis": "STEEMを手に入れよう!",
"sign_up_get_steem": "登録してSTEEMを手に入れよう!", "sign_up_get_steem": "登録してSTEEMを手に入れよう!",
"returning_users": "再" "returning_users": "再",
"use_keychain": "Use keychain extension"
}, },
"chainvalidation_js": { "chainvalidation_js": {
"account_name_should": "アカウント名", "account_name_should": "アカウント名",
......
...@@ -619,7 +619,8 @@ ...@@ -619,7 +619,8 @@
"signup_button_emphasis": "FREE STEEM!", "signup_button_emphasis": "FREE STEEM!",
"sign_up_get_steem": "sign_up_get_steem":
"계정을 만들고 가상화폐 STEEM 을 보상으로 받으세요.", "계정을 만들고 가상화폐 STEEM 을 보상으로 받으세요.",
"returning_users": "Returning Users: " "returning_users": "Returning Users: ",
"use_keychain": "Use keychain extension"
}, },
"chainvalidation_js": { "chainvalidation_js": {
"account_name_should": "Account name should ", "account_name_should": "Account name should ",
......
...@@ -607,7 +607,8 @@ ...@@ -607,7 +607,8 @@
"keep_me_logged_in": "Nie wylogowuj mnie", "keep_me_logged_in": "Nie wylogowuj mnie",
"sign_up_now_to_earn": "Zarejestruj się aby zarabiać ", "sign_up_now_to_earn": "Zarejestruj się aby zarabiać ",
"free_money": "DARMOWY STEEM!", "free_money": "DARMOWY STEEM!",
"returning_users": "Powracający użytkownicy: " "returning_users": "Powracający użytkownicy: ",
"use_keychain": "Use keychain extension"
}, },
"chainvalidation_js": { "chainvalidation_js": {
"account_name_should": "Nazwa konta powinna ", "account_name_should": "Nazwa konta powinna ",
......
...@@ -637,7 +637,8 @@ ...@@ -637,7 +637,8 @@
"sign_up_get_steem": "Sign up. Get STEEM", "sign_up_get_steem": "Sign up. Get STEEM",
"signup_button": "Зарегистрируйтесь", "signup_button": "Зарегистрируйтесь",
"signup_button_emphasis": " сейчас!", "signup_button_emphasis": " сейчас!",
"returning_users": "Вернувшиеся пользователи: " "returning_users": "Вернувшиеся пользователи: ",
"use_keychain": "Use keychain extension"
}, },
"chainvalidation_js": { "chainvalidation_js": {
"account_name_should": "Имя аккаунта должно быть ", "account_name_should": "Имя аккаунта должно быть ",
......
...@@ -570,7 +570,8 @@ ...@@ -570,7 +570,8 @@
"keep_me_logged_in": "保持登录状态", "keep_me_logged_in": "保持登录状态",
"sign_up_now_to_earn": "现在就来注册赚取", "sign_up_now_to_earn": "现在就来注册赚取",
"free_money": "免费的钱!", "free_money": "免费的钱!",
"returning_users": "返回用户:" "returning_users": "返回用户:",
"use_keychain": "Use keychain extension"
}, },
"chainvalidation_js": { "chainvalidation_js": {
"account_name_should": "帐户名称应该", "account_name_should": "帐户名称应该",
......
...@@ -7,7 +7,7 @@ import { getAccount } from 'app/redux/SagaShared'; ...@@ -7,7 +7,7 @@ import { getAccount } from 'app/redux/SagaShared';
import * as userActions from 'app/redux/UserReducer'; import * as userActions from 'app/redux/UserReducer';
// operations that require only posting authority // operations that require only posting authority
const postingOps = Set( export const postingOps = Set(
`vote, comment, delete_comment, custom_json, claim_reward_balance` `vote, comment, delete_comment, custom_json, claim_reward_balance`
.trim() .trim()
.split(/,\s*/) .split(/,\s*/)
......
...@@ -8,7 +8,7 @@ import { PrivateKey, PublicKey } from '@steemit/steem-js/lib/auth/ecc'; ...@@ -8,7 +8,7 @@ import { PrivateKey, PublicKey } from '@steemit/steem-js/lib/auth/ecc';
import { api, broadcast, auth, memo } from '@steemit/steem-js'; import { api, broadcast, auth, memo } from '@steemit/steem-js';
import { getAccount } from 'app/redux/SagaShared'; import { getAccount } from 'app/redux/SagaShared';
import { findSigningKey } from 'app/redux/AuthSaga'; import { postingOps, findSigningKey } from 'app/redux/AuthSaga';
import * as appActions from 'app/redux/AppReducer'; import * as appActions from 'app/redux/AppReducer';
import * as globalActions from 'app/redux/GlobalReducer'; import * as globalActions from 'app/redux/GlobalReducer';
import * as transactionActions from 'app/redux/TransactionReducer'; import * as transactionActions from 'app/redux/TransactionReducer';
...@@ -16,6 +16,7 @@ import * as userActions from 'app/redux/UserReducer'; ...@@ -16,6 +16,7 @@ import * as userActions from 'app/redux/UserReducer';
import * as proposalActions from 'app/redux/ProposalReducer'; import * as proposalActions from 'app/redux/ProposalReducer';
import { DEBT_TICKER } from 'app/client_config'; import { DEBT_TICKER } from 'app/client_config';
import { serverApiRecordEvent } from 'app/utils/ServerApiClient'; import { serverApiRecordEvent } from 'app/utils/ServerApiClient';
import { isLoggedInWithKeychain } from 'app/utils/SteemKeychain';
export const transactionWatches = [ export const transactionWatches = [
takeEvery(transactionActions.BROADCAST_OPERATION, broadcastOperation), takeEvery(transactionActions.BROADCAST_OPERATION, broadcastOperation),
...@@ -92,6 +93,7 @@ export function* broadcastOperation({ ...@@ -92,6 +93,7 @@ export function* broadcastOperation({
keys, keys,
username, username,
password, password,
useKeychain,
successCallback, successCallback,
errorCallback, errorCallback,
allowPostUnsafe, allowPostUnsafe,
...@@ -103,6 +105,7 @@ export function* broadcastOperation({ ...@@ -103,6 +105,7 @@ export function* broadcastOperation({
keys, keys,
username, username,
password, password,
useKeychain,
successCallback, successCallback,
errorCallback, errorCallback,
allowPostUnsafe, allowPostUnsafe,
...@@ -144,29 +147,33 @@ export function* broadcastOperation({ ...@@ -144,29 +147,33 @@ export function* broadcastOperation({
return; return;
} }
try { try {
if (!keys || keys.length === 0) { if (!isLoggedInWithKeychain()) {
payload.keys = []; if (!keys || keys.length === 0) {
// user may already be logged in, or just enterend a signing passowrd or wif payload.keys = [];
const signingKey = yield call(findSigningKey, { // user may already be logged in, or just enterend a signing passowrd or wif
opType: type, const signingKey = yield call(findSigningKey, {
username, opType: type,
password, username,
}); password,
if (signingKey) payload.keys.push(signingKey); });
else if (!password) { if (signingKey) payload.keys.push(signingKey);
yield put( else {
userActions.showLogin({ if (!password) {
operation: { yield put(
type, userActions.showLogin({
operation, operation: {
username, type,
successCallback, operation,
errorCallback, username,
saveLogin: true, successCallback,
}, errorCallback,
}) saveLogin: true,
); },
return; })
);
return;
}
}
} }
} }
yield call(broadcastPayload, { payload }); yield call(broadcastPayload, { payload });
...@@ -207,11 +214,18 @@ function hasPrivateKeys(payload) { ...@@ -207,11 +214,18 @@ function hasPrivateKeys(payload) {
function* broadcastPayload({ function* broadcastPayload({
payload: { operations, keys, username, successCallback, errorCallback }, payload: { operations, keys, username, successCallback, errorCallback },
}) { }) {
let needsActiveAuth = false;
// console.log('broadcastPayload')
if ($STM_Config.read_only_mode) return; if ($STM_Config.read_only_mode) return;
for (const [type] of operations) // see also transaction/ERROR for (const [type] of operations) {
// see also transaction/ERROR
yield put( yield put(
transactionActions.remove({ key: ['TransactionError', type] }) transactionActions.remove({ key: ['TransactionError', type] })
); );
if (!postingOps.has(type)) {
needsActiveAuth = true;
}
}
{ {
const newOps = []; const newOps = [];
...@@ -243,6 +257,11 @@ function* broadcastPayload({ ...@@ -243,6 +257,11 @@ function* broadcastPayload({
} }
}; };
// get username
const currentUser = yield select(state => state.user.get('current'));