Skip to content

Commit

Permalink
478 fix create account's form issue and a couple of more minor fixes (s…
Browse files Browse the repository at this point in the history
…teemit#480)

* fix  issue when get_accounts API call fails

* reset an error before making api call

* one more fix

* better handle existing email edge case

* use 302 redirects not 301

* Replace Math.random with secure-random. steemit#478

* Lock down confirm email lookup to email identity provider records. steemit#478

* Start over link more consistent order by in Identites sql. steemit#478

* Revert "Start over link more consistent order by in Identites sql. steemit#478"

This reverts commit dea06a5.

* reset session.user in /enter_email

* start registration process if user get to create_account page and has no id in session yet

* Add a few DESC to Identity.ID order by.

* update comment
  • Loading branch information
Valentine Zavgorodnev authored Oct 14, 2016
1 parent ed55b5e commit 28c2952
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 42 deletions.
7 changes: 6 additions & 1 deletion app/components/elements/ChangePassword.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,18 @@ class ChangePassword extends React.Component {
if (name.length > 0) {
nameError = validate_account_name(name);
if (!nameError) {
this.setState({nameError: ''});
promise = Apis.db_api('get_accounts', [name]).then(res => {
return !(res && res.length > 0) ? 'Account not found' : '';
});
}
}
if (promise) {
promise.then(error => this.setState({nameError: error}));
promise
.then(nameError => this.setState({nameError}))
.catch(() => this.setState({
nameError: "Account name can't be verified right now due to server failure. Please try again later."
}));
} else {
this.setState({nameError});
}
Expand Down
23 changes: 14 additions & 9 deletions app/components/pages/CreateAccount.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/* eslint react/prop-types: 0 */
import React from 'react';
import { connect } from 'react-redux';
import {connect} from 'react-redux';
import LoadingIndicator from 'app/components/elements/LoadingIndicator';
import Apis from 'shared/api_client/ApiInstances';
import { PrivateKey } from 'shared/ecc';
import {PrivateKey} from 'shared/ecc';
import user from 'app/redux/User';
import {validate_account_name} from 'app/utils/ChainValidation';
import SignUp from 'app/components/modules/SignUp';
Expand Down Expand Up @@ -119,13 +119,18 @@ class CreateAccount extends React.Component {
if (name.length > 0) {
name_error = validate_account_name(name);
if (!name_error) {
this.setState({name_error: ''});
promise = Apis.db_api('get_accounts', [name]).then(res => {
return res && res.length > 0 ? 'Account name is not available' : '';
});
}
}
if (promise) {
promise.then(error => this.setState({name_error: error}));
promise
.then(name_error => this.setState({name_error}))
.catch(() => this.setState({
name_error: "Account name can't be verified right now due to server failure. Please try again later."
}));
} else {
this.setState({name_error});
}
Expand All @@ -147,9 +152,7 @@ class CreateAccount extends React.Component {

const {loggedIn, logout, offchainUser, serverBusy} = this.props;
const submit_btn_disabled =
loading ||
!name ||
!password_valid ||
loading || !name || !password_valid ||
name_error;
const submit_btn_class = 'button action' + (submit_btn_disabled ? ' disabled' : '');

Expand All @@ -168,7 +171,8 @@ class CreateAccount extends React.Component {
<div className="callout alert">
<h4>Cryptography test failed</h4>
<p>We will be unable to create your Steem account with this browser.</p>
<p>The latest versions of <a href="https://www.google.com/chrome/">Chrome</a> and <a href="https://www.mozilla.org/en-US/firefox/new/">Firefox</a> are well tested and known to work with steemit.com.</p>
<p>The latest versions of <a href="https://www.google.com/chrome/">Chrome</a> and <a href="https://www.mozilla.org/en-US/firefox/new/">Firefox</a>
are well tested and known to work with steemit.com.</p>
</div>
</div>
</div>;
Expand Down Expand Up @@ -196,7 +200,7 @@ class CreateAccount extends React.Component {
<p>Our records indicate that you already have steem account: <strong>{existingUserAccount}</strong></p>
<p>In order to prevent abuse (each registered account costs 3 STEEM) Steemit can only register one account per verified user.</p>
<p>You can either <a href="/login.html">login</a> to your existing account
or <a href="mailto:[email protected]">send us email</a> if you need a new account.</p>
or <a href="mailto:[email protected]">send us email</a> if you need a new account.</p>
</div>
</div>
</div>;
Expand Down Expand Up @@ -243,7 +247,8 @@ class CreateAccount extends React.Component {
</div>
<hr />
</div> : <div className="text-center">
<a className="CreateAccount__rules-button" href="#" onClick={() => this.setState({showRules: true})}>Steemit Rules &nbsp; &raquo;</a>
<a className="CreateAccount__rules-button" href="#" onClick={() => this.setState({showRules: true})}>Steemit
Rules &nbsp; &raquo;</a>
</div>}
<form onSubmit={this.onSubmit} autoComplete="off" noValidate method="post">
<div className={name_error ? 'error' : ''}>
Expand Down
3 changes: 2 additions & 1 deletion scripts/send_waiting_list_invites.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import models from '../db/models';
import sendEmail from '../server/sendEmail';
import secureRandom from 'secure-random'

function inviteUser(u, email, number) {
const confirmation_code = Math.random().toString(36).slice(2);
const confirmation_code = secureRandom.randomBuffer(13).toString('hex');
console.log(`\n***** invite #${number} ***** `, u.id, email, confirmation_code);
const i_attrs = {
provider: 'email',
Expand Down
1 change: 1 addition & 0 deletions server/server-html.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export default function ServerHTML({ body, assets, locale, title, meta }) {
<link href="https://fonts.googleapis.com/css?family=Source+Serif+Pro:400,600" rel="stylesheet" type="text/css" />
{ assets.style.map((href, idx) =>
<link href={href} key={idx} rel="stylesheet" type="text/css" />) }
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=Intl.~locale.en"></script>
<title>{page_title}</title>
</head>
<body>
Expand Down
18 changes: 13 additions & 5 deletions server/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import flash from 'koa-flash';
import minimist from 'minimist';
import Grant from 'grant-koa';
import config from '../config';
import secureRandom from 'secure-random'

const grant = new Grant(config.grant);
// import uploadImage from 'server/upload-image' //medium-editor
Expand All @@ -36,14 +37,21 @@ csrf(app);
app.use(mount(grant));
app.use(flash({key: 'flash'}));

// redirect to home page if known account
// remember ch, cn, r url params in the session and remove them from url
// some redirects
app.use(function *(next) {
// redirect to home page/feed if known account
if (this.method === 'GET' && this.url === '/' && this.session.a) {
this.status = 301;
this.status = 302;
this.redirect(`/@${this.session.a}/feed`);
return;
}
// start registration process if user get to create_account page and has no id in session yet
if(this.url === '/create_account' && !this.session.user) {
this.status = 302;
this.redirect('/enter_email');
return;
}
// remember ch, cn, r url params in the session and remove them from url
if (this.method === 'GET' && /\?[^\w]*(ch=|cn=|r=)/.test(this.url)) {
let redir = this.url.replace(/((ch|cn|r)=[^&]+)/gi, r => {
const p = r.split('=');
Expand All @@ -53,7 +61,7 @@ app.use(function *(next) {
redir = redir.replace(/&&&?/, '');
redir = redir.replace(/\?&?$/, '');
console.log(`server redirect ${this.url} -> ${redir}`);
this.status = 301;
this.status = 302;
this.redirect(redir);
} else {
yield next;
Expand Down Expand Up @@ -85,7 +93,7 @@ app.use(function* (next) {
const last_visit = this.session.last_visit;
this.session.last_visit = (new Date()).getTime() / 1000 | 0;
if (!this.session.uid) {
this.session.uid = Math.random().toString(36).slice(2);
this.session.uid = secureRandom.randomBuffer(13).toString('hex');
this.session.new_visit = true;
} else {
this.session.new_visit = this.session.last_visit - last_visit > 1800;
Expand Down
35 changes: 13 additions & 22 deletions server/server_pages/enter_confirm_email.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {checkCSRF, getRemoteIp} from '../utils';
import config from '../../config';
import SignupProgressBar from 'app/components/elements/SignupProgressBar';
import MiniHeader from 'app/components/modules/MiniHeader';
import secureRandom from 'secure-random'

const assets_file = process.env.NODE_ENV === 'production' ? 'tmp/webpack-stats-prod.json' : 'tmp/webpack-stats-dev.json';
const assets = Object.assign({}, require(assets_file), {script: []});
Expand All @@ -18,9 +19,10 @@ assets.script.push('https://www.google.com/recaptcha/api.js');
function *confirmEmailHandler() {
const confirmation_code = this.params && this.params.code ? this.params.code : this.request.body.code;
console.log('-- /confirm_email -->', this.session.uid, this.session.user, confirmation_code);
const eid = yield models.Identity.findOne(
{attributes: ['id', 'user_id', 'email', 'updated_at', 'verified'], where: {confirmation_code}, order: 'id DESC'}
);
const eid = yield models.Identity.findOne({
attributes: ['id', 'user_id', 'email', 'updated_at', 'verified'],
where: {confirmation_code, provider: 'email'}, order: 'id DESC'
});
if (!eid) {
this.status = 401;
this.body = 'confirmation code not found';
Expand Down Expand Up @@ -51,18 +53,7 @@ export default function useEnterAndConfirmEmailPages(app) {

router.get('/enter_email', function *() {
console.log('-- /enter_email -->', this.session.uid, this.session.user);
let eid = null;
const user_id = this.session.user;
if (user_id) {
eid = yield models.Identity.findOne(
{attributes: ['email', 'verified'], where: {user_id, provider: 'email'}, order: 'id DESC'}
);
if (eid && eid.verified) {
this.flash = {success: 'Email has already been verified'};
this.redirect('/enter_mobile');
return;
}
}
this.session.user = null;
let default_email = '';
if (this.request.query && this.request.query.email) default_email = this.request.query.email;
const body = renderToString(<div className="App">
Expand Down Expand Up @@ -133,22 +124,22 @@ export default function useEnterAndConfirmEmailPages(app) {
}

const existing_email = yield models.Identity.findOne(
{attributes: ['id', 'user_id', 'confirmation_code'], where: {email, provider: 'email', verified: true}, order: 'id'}
{attributes: ['id', 'user_id', 'confirmation_code'], where: {email, provider: 'email'}, order: 'id DESC'}
);
let user_id = this.session.user;
if (existing_email && existing_email.user_id != user_id) {
if (existing_email) {
console.log('-- /submit_email existing_email -->', user_id, this.session.uid, email, existing_email.user_id);
const act = yield models.Account.findOne({
attributes: ['id'],
where: {user_id: existing_email.user_id, ignored: false},
order: 'id DESC'
})
if(act) {
if (act) {
this.flash = {error: 'This email has already been taken.'};
this.redirect('/enter_email?email=' + email);
return
}
// We must resend the email to get teh session going again if the user gets interrupted (clears cookies or changes browser) after email verify.
// We must resend the email to get the session going again if the user gets interrupted (clears cookies or changes browser) after email verify.
const {confirmation_code, id} = existing_email
console.log('-- /submit_email resend -->', email, id, confirmation_code);
sendEmail('confirm_email', email, {confirmation_code});
Expand All @@ -165,9 +156,9 @@ export default function useEnterAndConfirmEmailPages(app) {
this.session.user = user_id = user.id;
}

const confirmation_code = Math.random().toString(36).slice(2);
const confirmation_code = secureRandom.randomBuffer(13).toString('hex');
let eid = yield models.Identity.findOne(
{attributes: ['id', 'email'], where: {user_id, provider: 'email'}, order: 'id'}
{attributes: ['id', 'email'], where: {user_id, provider: 'email'}, order: 'id DESC'}
);
if (eid) {
yield eid.update({confirmation_code, email});
Expand Down Expand Up @@ -220,4 +211,4 @@ function* checkRecaptcha(ctx) {
console.error('-- /submit_email recaptcha request failed -->', verificationUrl, e);
}
return !captcha_failed
}
}
7 changes: 4 additions & 3 deletions server/server_pages/enter_confirm_mobile.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {verify} from 'server/teleSign';
import SignupProgressBar from 'app/components/elements/SignupProgressBar';
import {getRemoteIp, checkCSRF} from 'server/utils';
import MiniHeader from 'app/components/modules/MiniHeader';
import secureRandom from 'secure-random'

const assets_file = process.env.NODE_ENV === 'production' ? 'tmp/webpack-stats-prod.json' : 'tmp/webpack-stats-dev.json';
const assets = Object.assign({}, require(assets_file), {script: []});
Expand Down Expand Up @@ -117,7 +118,7 @@ export default function useEnterAndConfirmMobilePages(app) {
}

const existing_phone = yield models.Identity.findOne(
{attributes: ['user_id'], where: {phone: mobile, provider: 'phone', verified: true}, order: 'id'}
{attributes: ['user_id'], where: {phone: mobile, provider: 'phone', verified: true}, order: 'id DESC'}
);
if (existing_phone && existing_phone.user_id != user_id) {
console.log('-- /submit_email existing_phone -->', user_id, this.session.uid, mobile, existing_phone.user_id);
Expand All @@ -126,9 +127,9 @@ export default function useEnterAndConfirmMobilePages(app) {
return;
}

const confirmation_code = Math.random().toString().substring(2, 6);
const confirmation_code = parseInt(secureRandom.randomBuffer(8).toString('hex'), 16).toString(10).substring(0, 4); // 4 digit code
let mid = yield models.Identity.findOne(
{attributes: ['id', 'phone', 'verified', 'updated_at'], where: {user_id, provider: 'phone'}, order: 'id'}
{attributes: ['id', 'phone', 'verified', 'updated_at'], where: {user_id, provider: 'phone'}, order: 'id DESC'}
);
if (mid) {
if (mid.verified) {
Expand Down
3 changes: 2 additions & 1 deletion server/teleSign.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import fetch from 'node-fetch';
import config from '../config';
import crypto from 'crypto'
import secureRandom from 'secure-random'

const {customer_id} = config.telesign
const api_key = new Buffer(config.telesign.rest_api_key, 'base64')
Expand Down Expand Up @@ -106,7 +107,7 @@ function authHeaders({
}) {
const auth_method = 'HMAC-SHA256'
const currDate = new Date().toUTCString()
const nonce = Math.random().toString(36).slice(15)
const nonce = parseInt(secureRandom.randomBuffer(8).toString('hex'), 16).toString(36)

let content_type = ''
if(/POST|PUT/.test(method))
Expand Down

0 comments on commit 28c2952

Please sign in to comment.