Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Signer new-token generates a link and opens browser #3379

Merged
merged 10 commits into from
Nov 16, 2016
Merged
10 changes: 9 additions & 1 deletion js/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import ReactDOM from 'react-dom';
import injectTapEventPlugin from 'react-tap-event-plugin';
import { createHashHistory } from 'history';
import { Redirect, Router, Route, useRouterHistory } from 'react-router';
import qs from 'querystring';

import SecureApi from './secureApi';
import ContractInstances from './contracts';
Expand All @@ -45,14 +46,20 @@ import './index.html';

injectTapEventPlugin();

const AUTH_HASH = '#/auth?';
const parityUrl = process.env.PARITY_URL ||
(
process.env.NODE_ENV === 'production'
? window.location.host
: '127.0.0.1:8180'
);

const api = new SecureApi(`ws://${parityUrl}`);
let token = null;
if (window.location.hash && window.location.hash.indexOf(AUTH_HASH) === 0) {
token = qs.parse(window.location.hash.substr(AUTH_HASH.length)).token;
}

const api = new SecureApi(`ws://${parityUrl}`, token);
ContractInstances.create(api);

const store = initStore(api);
Expand All @@ -67,6 +74,7 @@ ReactDOM.render(
<ContextProvider api={ api } muiTheme={ muiTheme } store={ store }>
<Router className={ styles.reset } history={ routerHistory }>
<Redirect from='/' to='/accounts' />
<Redirect from='/auth' to='/accounts' query={ {} } />
<Redirect from='/settings' to='/settings/views' />
<Route path='/' component={ Application }>
<Route path='accounts' component={ Accounts } />
Expand Down
9 changes: 7 additions & 2 deletions js/src/secureApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@ import Api from './api';
const sysuiToken = window.localStorage.getItem('sysuiToken');

export default class SecureApi extends Api {
constructor (url) {
constructor (url, nextToken) {
super(new Api.Transport.Ws(url, sysuiToken));

this._isConnecting = true;
this._connectState = sysuiToken === 'initial' ? 1 : 0;
this._needsToken = false;
this._nextToken = nextToken;
this._dappsPort = 8080;
this._dappsInterface = null;
this._signerPort = 8180;
Expand Down Expand Up @@ -57,7 +58,11 @@ export default class SecureApi extends Api {
if (isConnected) {
return this.connectSuccess();
} else if (lastError) {
this.updateToken('initial', 1);
const nextToken = this._nextToken || 'initial';
const nextState = this._nextToken ? 0 : 1;

this._nextToken = null;
this.updateToken(nextToken, nextState);
}
break;

Expand Down
18 changes: 10 additions & 8 deletions parity/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use params::{ResealPolicy, AccountsConfig, GasPricerConfig, MinerExtras};
use ethcore_logger::Config as LogConfig;
use dir::Directories;
use dapps::Configuration as DappsConfiguration;
use signer::{Configuration as SignerConfiguration, SignerCommand};
use signer::{Configuration as SignerConfiguration};
use run::RunCmd;
use blockchain::{BlockchainCmd, ImportBlockchain, ExportBlockchain, DataFormat};
use presale::ImportWallet;
Expand All @@ -49,7 +49,7 @@ pub enum Cmd {
Account(AccountCmd),
ImportPresaleWallet(ImportWallet),
Blockchain(BlockchainCmd),
SignerToken(SignerCommand),
SignerToken(SignerConfiguration),
Snapshot(SnapshotCommand),
Hash(Option<String>),
}
Expand Down Expand Up @@ -103,9 +103,7 @@ impl Configuration {
let cmd = if self.args.flag_version {
Cmd::Version
} else if self.args.cmd_signer && self.args.cmd_new_token {
Cmd::SignerToken(SignerCommand {
path: dirs.signer
})
Cmd::SignerToken(signer_conf)
} else if self.args.cmd_tools && self.args.cmd_hash {
Cmd::Hash(self.args.arg_file)
} else if self.args.cmd_account {
Expand Down Expand Up @@ -690,7 +688,7 @@ mod tests {
use ethcore::miner::{MinerOptions, PrioritizationStrategy};
use helpers::{replace_home, default_network_config};
use run::RunCmd;
use signer::{Configuration as SignerConfiguration, SignerCommand};
use signer::{Configuration as SignerConfiguration};
use blockchain::{BlockchainCmd, ImportBlockchain, ExportBlockchain, DataFormat};
use presale::ImportWallet;
use account::{AccountCmd, NewAccount, ImportAccounts};
Expand Down Expand Up @@ -827,8 +825,12 @@ mod tests {
let args = vec!["parity", "signer", "new-token"];
let conf = parse(&args);
let expected = replace_home("$HOME/.parity/signer");
assert_eq!(conf.into_command().unwrap().cmd, Cmd::SignerToken(SignerCommand {
path: expected,
assert_eq!(conf.into_command().unwrap().cmd, Cmd::SignerToken(SignerConfiguration {
enabled: true,
signer_path: expected,
interface: "127.0.0.1".into(),
port: 8180,
skip_origin_validation: false,
}));
}

Expand Down
27 changes: 20 additions & 7 deletions parity/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,29 @@ pub struct RunCmd {
pub check_seal: bool,
}

pub fn open_ui(dapps_conf: &dapps::Configuration, signer_conf: &signer::Configuration) -> Result<(), String> {
if !dapps_conf.enabled {
return Err("Cannot use UI command with Dapps turned off.".into())
}

if !signer_conf.enabled {
return Err("Cannot use UI command with UI turned off.".into())
}

let token = try!(signer::generate_token_and_url(signer_conf));
// Open a browser
url::open(&token.url);
// Print a message
println!("{}", token.message);
Ok(())
}

pub fn execute(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<(), String> {
if cmd.ui && cmd.dapps_conf.enabled {
// Check if Parity is already running
let addr = format!("{}:{}", cmd.dapps_conf.interface, cmd.dapps_conf.port);
if !TcpListener::bind(&addr as &str).is_ok() {
url::open(&format!("http://{}:{}/", cmd.dapps_conf.interface, cmd.dapps_conf.port));
return Ok(());
return open_ui(&cmd.dapps_conf, &cmd.signer_conf);
}
}

Expand Down Expand Up @@ -309,7 +325,7 @@ pub fn execute(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<(), String> {
};

// start signer server
let signer_server = try!(signer::start(cmd.signer_conf, signer_deps));
let signer_server = try!(signer::start(cmd.signer_conf.clone(), signer_deps));

let informant = Arc::new(Informant::new(
service.client(),
Expand Down Expand Up @@ -363,10 +379,7 @@ pub fn execute(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<(), String> {

// start ui
if cmd.ui {
if !cmd.dapps_conf.enabled {
return Err("Cannot use UI command with Dapps turned off.".into())
}
url::open(&format!("http://{}:{}/", cmd.dapps_conf.interface, cmd.dapps_conf.port));
try!(open_ui(&cmd.dapps_conf, &cmd.signer_conf));
}

// Handle exit
Expand Down
35 changes: 27 additions & 8 deletions parity/signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub use ethcore_signer::Server as SignerServer;

const CODES_FILENAME: &'static str = "authcodes";

#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Clone)]
pub struct Configuration {
pub enabled: bool,
pub port: u16,
Expand All @@ -53,6 +53,12 @@ pub struct Dependencies {
pub apis: Arc<rpc_apis::Dependencies>,
}

pub struct NewToken {
pub token: String,
pub url: String,
pub message: String,
}

pub fn start(conf: Configuration, deps: Dependencies) -> Result<Option<SignerServer>, String> {
if !conf.enabled {
Ok(None)
Expand All @@ -68,20 +74,33 @@ fn codes_path(path: String) -> PathBuf {
p
}

#[derive(Debug, PartialEq)]
pub struct SignerCommand {
pub path: String,
pub fn execute(cmd: Configuration) -> Result<String, String> {
Ok(try!(generate_token_and_url(&cmd)).message)
}

pub fn execute(cmd: SignerCommand) -> Result<String, String> {
generate_new_token(cmd.path)
.map(|code| format!("This key code will authorise your System Signer UI: {}", Colour::White.bold().paint(code)))
.map_err(|err| format!("Error generating token: {:?}", err))
pub fn generate_token_and_url(conf: &Configuration) -> Result<NewToken, String> {
let code = try!(generate_new_token(conf.signer_path.clone()).map_err(|err| format!("Error generating token: {:?}", err)));
let auth_url = format!("http://{}:{}/#/auth?token={}", conf.interface, conf.port, code);
// And print in to the console
Ok(NewToken {
token: code.clone(),
url: auth_url.clone(),
message: format!(
r#"
Open: {}
to authorize your browser.
Or use the generated token:
{}"#,
Colour::White.bold().paint(auth_url),
code
)
})
}

pub fn generate_new_token(path: String) -> io::Result<String> {
let path = codes_path(path);
let mut codes = try!(signer::AuthCodes::from_file(&path));
codes.clear_garbage();
let code = try!(codes.generate_new());
try!(codes.to_file(&path));
trace!("New key code created: {}", Colour::White.bold().paint(&code[..]));
Expand Down
Loading