diff --git a/ethcore/src/account_provider/mod.rs b/ethcore/src/account_provider/mod.rs index 568cbd4e3..2f6d49e75 100755 --- a/ethcore/src/account_provider/mod.rs +++ b/ethcore/src/account_provider/mod.rs @@ -23,7 +23,7 @@ use self::stores::{AddressBook, DappsSettingsStore, NewDappsPolicy}; use std::fmt; use std::collections::{HashMap, HashSet}; use std::time::{Instant, Duration}; -use util::RwLock; +use util::{FixedHash, RwLock}; use ethstore::{SimpleSecretStore, SecretStore, Error as SSError, EthStore, EthMultiStore, random_string, SecretVaultRef, StoreAccountRef}; use ethstore::dir::MemoryDirectory; @@ -241,25 +241,88 @@ impl AccountProvider { Ok(accounts.into_iter().map(|a| a.address).collect()) } - /// Sets a whitelist of accounts exposed for unknown dapps. + /// Sets addresses of accounts exposed for unknown dapps. /// `None` means that all accounts will be visible. - pub fn set_new_dapps_whitelist(&self, accounts: Option>) -> Result<(), Error> { + /// If not `None` or empty it will also override default account. + pub fn set_new_dapps_addresses(&self, accounts: Option>) -> Result<(), Error> { + let current_default = self.new_dapps_default_address()?; + self.dapps_settings.write().set_policy(match accounts { - None => NewDappsPolicy::AllAccounts, + None => NewDappsPolicy::AllAccounts { + default: current_default, + }, Some(accounts) => NewDappsPolicy::Whitelist(accounts), }); Ok(()) } - /// Gets a whitelist of accounts exposed for unknown dapps. + /// Gets addresses of accounts exposed for unknown dapps. /// `None` means that all accounts will be visible. - pub fn new_dapps_whitelist(&self) -> Result>, Error> { + pub fn new_dapps_addresses(&self) -> Result>, Error> { Ok(match self.dapps_settings.read().policy() { - NewDappsPolicy::AllAccounts => None, + NewDappsPolicy::AllAccounts { .. } => None, NewDappsPolicy::Whitelist(accounts) => Some(accounts), }) } + /// Sets a default account for unknown dapps. + /// This account will always be returned as the first one. + pub fn set_new_dapps_default_address(&self, address: Address) -> Result<(), Error> { + if !self.valid_addresses()?.contains(&address) { + return Err(SSError::InvalidAccount.into()); + } + + let mut settings = self.dapps_settings.write(); + let new_policy = match settings.policy() { + NewDappsPolicy::AllAccounts { .. } => NewDappsPolicy::AllAccounts { default: address }, + NewDappsPolicy::Whitelist(list) => NewDappsPolicy::Whitelist(Self::insert_default(list, address)), + }; + settings.set_policy(new_policy); + + Ok(()) + } + + /// Inserts given address as first in the vector, preventing duplicates. + fn insert_default(mut addresses: Vec
, default: Address) -> Vec
{ + if let Some(position) = addresses.iter().position(|address| address == &default) { + addresses.swap(0, position); + } else { + addresses.insert(0, default); + } + + addresses + } + + /// Returns a list of accounts that new dapp should see. + /// First account is always the default account. + fn new_dapps_addresses_list(&self) -> Result, Error> { + match self.dapps_settings.read().policy() { + NewDappsPolicy::AllAccounts { default } => if default.is_zero() { + self.accounts() + } else { + Ok(Self::insert_default(self.accounts()?, default)) + }, + NewDappsPolicy::Whitelist(accounts) => { + let addresses = self.filter_addresses(accounts)?; + if addresses.is_empty() { + Ok(vec![self.accounts()?.get(0).cloned().unwrap_or(0.into())]) + } else { + Ok(addresses) + } + }, + } + } + + /// Gets a default account for new dapps + /// Will return zero address in case the default is not set and there are no accounts configured. + pub fn new_dapps_default_address(&self) -> Result { + Ok(self.new_dapps_addresses_list()? + .get(0) + .cloned() + .unwrap_or(0.into()) + ) + } + /// Gets a list of dapps recently requesting accounts. pub fn recent_dapps(&self) -> Result, Error> { Ok(self.dapps_settings.read().recent_dapps()) @@ -272,41 +335,74 @@ impl AccountProvider { Ok(()) } - /// Gets addresses visile for dapp. - pub fn dapps_addresses(&self, dapp: DappId) -> Result, Error> { - let dapps = self.dapps_settings.read(); + /// Gets addresses visible for given dapp. + pub fn dapp_addresses(&self, dapp: DappId) -> Result, Error> { + let accounts = self.dapps_settings.read().settings().get(&dapp).map(|settings| { + (settings.accounts.clone(), settings.default.clone()) + }); - let accounts = dapps.settings().get(&dapp).map(|settings| settings.accounts.clone()); match accounts { - Some(accounts) => Ok(accounts), - None => match dapps.policy() { - NewDappsPolicy::AllAccounts => self.accounts(), - NewDappsPolicy::Whitelist(accounts) => self.filter_addresses(accounts), - } + Some((Some(accounts), Some(default))) => self.filter_addresses(Self::insert_default(accounts, default)), + Some((Some(accounts), None)) => self.filter_addresses(accounts), + Some((None, Some(default))) => self.filter_addresses(Self::insert_default(self.new_dapps_addresses_list()?, default)), + _ => self.new_dapps_addresses_list(), } } /// Returns default account for particular dapp falling back to other allowed accounts if necessary. - pub fn default_address(&self, dapp: DappId) -> Result { - self.dapps_addresses(dapp)? + pub fn dapp_default_address(&self, dapp: DappId) -> Result { + let dapp_default = self.dapp_addresses(dapp)? .get(0) - .cloned() - .ok_or(SSError::InvalidAccount) + .cloned(); + + match dapp_default { + Some(default) => Ok(default), + None => self.new_dapps_default_address(), + } } - /// Sets addresses visile for dapp. - pub fn set_dapps_addresses(&self, dapp: DappId, addresses: Vec
) -> Result<(), Error> { - let addresses = self.filter_addresses(addresses)?; - self.dapps_settings.write().set_accounts(dapp, addresses); + /// Sets default address for given dapp. + /// Does not alter dapp addresses, but this account will always be returned as the first one. + pub fn set_dapp_default_address(&self, dapp: DappId, address: Address) -> Result<(), Error> { + if !self.valid_addresses()?.contains(&address) { + return Err(SSError::InvalidAccount.into()); + } + + self.dapps_settings.write().set_default(dapp, address); Ok(()) } + /// Sets addresses visible for given dapp. + /// If `None` - falls back to dapps addresses + /// If not `None` and not empty it will also override default account. + pub fn set_dapp_addresses(&self, dapp: DappId, addresses: Option>) -> Result<(), Error> { + let (addresses, default) = match addresses { + Some(addresses) => { + let addresses = self.filter_addresses(addresses)?; + let default = addresses.get(0).cloned(); + (Some(addresses), default) + }, + None => (None, None), + }; + + let mut settings = self.dapps_settings.write(); + if let Some(default) = default { + settings.set_default(dapp.clone(), default); + } + settings.set_accounts(dapp, addresses); + Ok(()) + } + + fn valid_addresses(&self) -> Result, Error> { + Ok(self.addresses_info().into_iter() + .map(|(address, _)| address) + .chain(self.accounts()?) + .collect()) + } + /// Removes addresses that are neither accounts nor in address book. fn filter_addresses(&self, addresses: Vec
) -> Result, Error> { - let valid = self.addresses_info().into_iter() - .map(|(address, _)| address) - .chain(self.accounts()?) - .collect::>(); + let valid = self.valid_addresses()?; Ok(addresses.into_iter() .filter(|a| valid.contains(&a)) @@ -743,44 +839,92 @@ mod tests { } #[test] - fn should_set_dapps_addresses() { + fn should_reset_dapp_addresses_to_default() { + // given + let ap = AccountProvider::transient_provider(); + let app = DappId("app1".into()); + // add accounts to address book + ap.set_address_name(1.into(), "1".into()); + ap.set_address_name(2.into(), "2".into()); + // set `AllAccounts` policy + ap.set_new_dapps_addresses(Some(vec![1.into(), 2.into()])).unwrap(); + assert_eq!(ap.dapp_addresses(app.clone()).unwrap(), vec![1.into(), 2.into()]); + + // Alter and check + ap.set_dapp_addresses(app.clone(), Some(vec![1.into(), 3.into()])).unwrap(); + assert_eq!(ap.dapp_addresses(app.clone()).unwrap(), vec![1.into()]); + + // Reset back to default + ap.set_dapp_addresses(app.clone(), None).unwrap(); + assert_eq!(ap.dapp_addresses(app.clone()).unwrap(), vec![1.into(), 2.into()]); + } + + #[test] + fn should_set_dapps_default_address() { // given let ap = AccountProvider::transient_provider(); let app = DappId("app1".into()); // set `AllAccounts` policy - ap.set_new_dapps_whitelist(None).unwrap(); + ap.set_new_dapps_addresses(None).unwrap(); // add accounts to address book ap.set_address_name(1.into(), "1".into()); ap.set_address_name(2.into(), "2".into()); - // when - ap.set_dapps_addresses(app.clone(), vec![1.into(), 2.into(), 3.into()]).unwrap(); + ap.set_dapp_addresses(app.clone(), Some(vec![1.into(), 2.into(), 3.into()])).unwrap(); + assert_eq!(ap.dapp_addresses(app.clone()).unwrap(), vec![1.into(), 2.into()]); + assert_eq!(ap.dapp_default_address("app1".into()).unwrap(), 1.into()); - // then - assert_eq!(ap.dapps_addresses(app.clone()).unwrap(), vec![1.into(), 2.into()]); + // when setting empty list + ap.set_dapp_addresses(app.clone(), Some(vec![])).unwrap(); + + // then default account is intact + assert_eq!(ap.dapp_addresses(app.clone()).unwrap(), vec![1.into()]); + assert_eq!(ap.dapp_default_address("app1".into()).unwrap(), 1.into()); + + // alter default account + ap.set_dapp_default_address("app1".into(), 2.into()).unwrap(); + assert_eq!(ap.dapp_addresses(app.clone()).unwrap(), vec![2.into()]); + assert_eq!(ap.dapp_default_address("app1".into()).unwrap(), 2.into()); } #[test] - fn should_set_dapps_policy() { + fn should_set_dapps_policy_and_default_account() { // given let ap = AccountProvider::transient_provider(); + + // default_account should be always available + assert_eq!(ap.new_dapps_default_address().unwrap(), 0.into()); + let address = ap.new_account("test").unwrap(); ap.set_address_name(1.into(), "1".into()); - // When returning nothing - ap.set_new_dapps_whitelist(Some(vec![])).unwrap(); - assert_eq!(ap.dapps_addresses("app1".into()).unwrap(), vec![]); + // Default account set to first account by default + assert_eq!(ap.new_dapps_default_address().unwrap(), address); + assert_eq!(ap.dapp_default_address("app1".into()).unwrap(), address); + + // Even when returning nothing + ap.set_new_dapps_addresses(Some(vec![])).unwrap(); + // Default account is still returned + assert_eq!(ap.dapp_addresses("app1".into()).unwrap(), vec![address]); // change to all - ap.set_new_dapps_whitelist(None).unwrap(); - assert_eq!(ap.dapps_addresses("app1".into()).unwrap(), vec![address]); + ap.set_new_dapps_addresses(None).unwrap(); + assert_eq!(ap.dapp_addresses("app1".into()).unwrap(), vec![address]); // change to non-existent account - ap.set_new_dapps_whitelist(Some(vec![2.into()])).unwrap(); - assert_eq!(ap.dapps_addresses("app1".into()).unwrap(), vec![]); + ap.set_new_dapps_addresses(Some(vec![2.into()])).unwrap(); + assert_eq!(ap.dapp_addresses("app1".into()).unwrap(), vec![address]); - // change to a whitelist - ap.set_new_dapps_whitelist(Some(vec![1.into()])).unwrap(); - assert_eq!(ap.dapps_addresses("app1".into()).unwrap(), vec![1.into()]); + // change to a addresses + ap.set_new_dapps_addresses(Some(vec![1.into()])).unwrap(); + assert_eq!(ap.dapp_addresses("app1".into()).unwrap(), vec![1.into()]); + + // it overrides default account + assert_eq!(ap.new_dapps_default_address().unwrap(), 1.into()); + assert_eq!(ap.dapp_default_address("app1".into()).unwrap(), 1.into()); + + ap.set_new_dapps_default_address(address).unwrap(); + assert_eq!(ap.new_dapps_default_address().unwrap(), address); + assert_eq!(ap.dapp_default_address("app1".into()).unwrap(), address); } } diff --git a/ethcore/src/account_provider/stores.rs b/ethcore/src/account_provider/stores.rs index e4bd7e1b9..72bc04da6 100644 --- a/ethcore/src/account_provider/stores.rs +++ b/ethcore/src/account_provider/stores.rs @@ -92,13 +92,16 @@ impl AddressBook { #[derive(Debug, Default, Clone, Eq, PartialEq)] pub struct DappsSettings { /// A list of visible accounts - pub accounts: Vec
, + pub accounts: Option>, + /// Default account + pub default: Option
, } impl From for DappsSettings { fn from(s: JsonSettings) -> Self { DappsSettings { - accounts: s.accounts.into_iter().map(Into::into).collect(), + accounts: s.accounts.map(|accounts| accounts.into_iter().map(Into::into).collect()), + default: s.default.map(Into::into), } } } @@ -106,7 +109,8 @@ impl From for DappsSettings { impl From for JsonSettings { fn from(s: DappsSettings) -> Self { JsonSettings { - accounts: s.accounts.into_iter().map(Into::into).collect(), + accounts: s.accounts.map(|accounts| accounts.into_iter().map(Into::into).collect()), + default: s.default.map(Into::into), } } } @@ -114,14 +118,18 @@ impl From for JsonSettings { /// Dapps user settings #[derive(Debug, Clone, Eq, PartialEq)] pub enum NewDappsPolicy { - AllAccounts, + AllAccounts { + default: Address, + }, Whitelist(Vec
), } impl From for NewDappsPolicy { fn from(s: JsonNewDappsPolicy) -> Self { match s { - JsonNewDappsPolicy::AllAccounts => NewDappsPolicy::AllAccounts, + JsonNewDappsPolicy::AllAccounts { default } => NewDappsPolicy::AllAccounts { + default: default.into(), + }, JsonNewDappsPolicy::Whitelist(accounts) => NewDappsPolicy::Whitelist( accounts.into_iter().map(Into::into).collect() ), @@ -132,7 +140,9 @@ impl From for NewDappsPolicy { impl From for JsonNewDappsPolicy { fn from(s: NewDappsPolicy) -> Self { match s { - NewDappsPolicy::AllAccounts => JsonNewDappsPolicy::AllAccounts, + NewDappsPolicy::AllAccounts { default } => JsonNewDappsPolicy::AllAccounts { + default: default.into(), + }, NewDappsPolicy::Whitelist(accounts) => JsonNewDappsPolicy::Whitelist( accounts.into_iter().map(Into::into).collect() ), @@ -230,7 +240,9 @@ impl DappsSettingsStore { /// Returns current new dapps policy pub fn policy(&self) -> NewDappsPolicy { - self.policy.get("default").cloned().unwrap_or(NewDappsPolicy::AllAccounts) + self.policy.get("default").cloned().unwrap_or(NewDappsPolicy::AllAccounts { + default: 0.into(), + }) } /// Returns recent dapps with last accessed timestamp @@ -266,13 +278,22 @@ impl DappsSettingsStore { } /// Sets accounts for specific dapp. - pub fn set_accounts(&mut self, id: DappId, accounts: Vec
) { + pub fn set_accounts(&mut self, id: DappId, accounts: Option>) { { let mut settings = self.settings.entry(id).or_insert_with(DappsSettings::default); settings.accounts = accounts; } self.settings.save(JsonSettings::write); } + + /// Sets a default account for specific dapp. + pub fn set_default(&mut self, id: DappId, default: Address) { + { + let mut settings = self.settings.entry(id).or_insert_with(DappsSettings::default); + settings.default = Some(default); + } + self.settings.save(JsonSettings::write); + } } /// Disk-serializable HashMap @@ -385,13 +406,14 @@ mod tests { let mut b = DappsSettingsStore::new(&path); // when - b.set_accounts("dappOne".into(), vec![1.into(), 2.into()]); + b.set_accounts("dappOne".into(), Some(vec![1.into(), 2.into()])); // then let b = DappsSettingsStore::new(&path); assert_eq!(b.settings(), hash_map![ "dappOne".into() => DappsSettings { - accounts: vec![1.into(), 2.into()], + accounts: Some(vec![1.into(), 2.into()]), + default: None, } ]); } @@ -422,7 +444,9 @@ mod tests { let mut store = DappsSettingsStore::new(&path); // Test default policy - assert_eq!(store.policy(), NewDappsPolicy::AllAccounts); + assert_eq!(store.policy(), NewDappsPolicy::AllAccounts { + default: 0.into(), + }); // when store.set_policy(NewDappsPolicy::Whitelist(vec![1.into(), 2.into()])); diff --git a/js/src/api/rpc/parity/parity.js b/js/src/api/rpc/parity/parity.js index d7278d13a..0f1bd492c 100644 --- a/js/src/api/rpc/parity/parity.js +++ b/js/src/api/rpc/parity/parity.js @@ -170,18 +170,30 @@ export default class Parity { .execute('parity_generateSecretPhrase'); } - getDappsAddresses (dappId) { + getDappAddresses (dappId) { return this._transport - .execute('parity_getDappsAddresses', dappId) + .execute('parity_getDappAddresses', dappId) .then(outAddresses); } - getNewDappsWhitelist () { + getDappDefaultAddress (dappId) { return this._transport - .execute('parity_getNewDappsWhitelist') + .execute('parity_getDappDefaultAddress', dappId) + .then(outAddress); + } + + getNewDappsAddresses () { + return this._transport + .execute('parity_getNewDappsAddresses') .then((addresses) => addresses ? addresses.map(outAddress) : null); } + getNewDappsDefaultAddress () { + return this._transport + .execute('parity_getNewDappsDefaultAddress') + .then(outAddress); + } + getVaultMeta (vaultName) { return this._transport .execute('parity_getVaultMeta', vaultName) @@ -391,9 +403,14 @@ export default class Parity { .execute('parity_setAuthor', inAddress(address)); } - setDappsAddresses (dappId, addresses) { + setDappAddresses (dappId, addresses) { return this._transport - .execute('parity_setDappsAddresses', dappId, inAddresses(addresses)); + .execute('parity_setDappAddresses', dappId, inAddresses(addresses)); + } + + setDappDefaultAddress (dappId, address) { + return this._transport + .execute('parity_setDappDefaultAddress', dappId, address ? inAddress(address) : null); } setEngineSigner (address, password) { @@ -431,9 +448,14 @@ export default class Parity { .execute('parity_setMode', mode); } - setNewDappsWhitelist (addresses) { + setNewDappsAddresses (addresses) { return this._transport - .execute('parity_setNewDappsWhitelist', addresses ? inAddresses(addresses) : null); + .execute('parity_setNewDappsAddresses', addresses ? inAddresses(addresses) : null); + } + + setNewDappsDefaultAddress (address) { + return this._transport + .execute('parity_setNewDappsDefaultAddress', inAddress(address)); } setTransactionsLimit (quantity) { diff --git a/js/src/api/subscriptions/personal.js b/js/src/api/subscriptions/personal.js index 715f4cfe5..c1f070262 100644 --- a/js/src/api/subscriptions/personal.js +++ b/js/src/api/subscriptions/personal.js @@ -123,8 +123,10 @@ export default class Personal { this._accountsInfo(); return; - case 'parity_setDappsAddresses': - case 'parity_setNewDappsWhitelist': + case 'parity_setDappAddresses': + case 'parity_setDappDefaultAddress': + case 'parity_setNewDappsAddresses': + case 'parity_setNewDappsDefaultAddress': this._defaultAccount(true); this._listAccounts(); return; diff --git a/js/src/jsonrpc/interfaces/parity.js b/js/src/jsonrpc/interfaces/parity.js index 978c77f88..3d84ce4b4 100644 --- a/js/src/jsonrpc/interfaces/parity.js +++ b/js/src/jsonrpc/interfaces/parity.js @@ -1186,9 +1186,9 @@ export default { } }, - setDappsAddresses: { + setDappAddresses: { subdoc: SUBDOC_ACCOUNTS, - desc: 'Sets the available addresses for a dapp.', + desc: 'Sets the available addresses for a dapp. When provided with non-empty list changes the default account as well.', params: [ { type: String, @@ -1197,7 +1197,7 @@ export default { }, { type: Array, - desc: 'Array of available accounts available to the dapp.', + desc: 'Array of available accounts available to the dapp or `null` for default list.', example: ['0x407d73d8a49eeb85d32cf465507dd71d507100c1'] } ], @@ -1208,7 +1208,7 @@ export default { } }, - getDappsAddresses: { + getDappAddresses: { subdoc: SUBDOC_ACCOUNTS, desc: 'Returns the list of accounts available to a specific dapp.', params: [ @@ -1225,13 +1225,52 @@ export default { } }, - setNewDappsWhitelist: { + setDappDefaultAddress: { + subdoc: SUBDOC_ACCOUNTS, + desc: 'Changes dapp default address. Does not affect other accounts exposed for this dapp, but default account will always be retured as the first one.', + params: [ + { + type: String, + desc: 'Dapp Id.', + example: 'web' + }, + { + type: Address, + desc: 'Default Address.', + example: '0x407d73d8a49eeb85d32cf465507dd71d507100c1' + } + ], + returns: { + type: Boolean, + desc: '`true` if the call was successful', + example: true + } + }, + + getDappDefaultAddress: { + subdoc: SUBDOC_ACCOUNTS, + desc: 'Returns a default account available to a specific dapp.', + params: [ + { + type: String, + desc: 'Dapp Id.', + example: 'web' + } + ], + returns: { + type: Address, + desc: 'Default Address', + example: '0x407d73d8a49eeb85d32cf465507dd71d507100c1' + } + }, + + setNewDappsAddresses: { subdoc: SUBDOC_ACCOUNTS, desc: 'Sets the list of accounts available to new dapps.', params: [ { type: Array, - desc: 'List of accounts available by default.', + desc: 'List of accounts available by default or `null` for all accounts.', example: ['0x407d73d8a49eeb85d32cf465507dd71d507100c1'] } ], @@ -1242,7 +1281,7 @@ export default { } }, - getNewDappsWhitelist: { + getNewDappsAddresses: { subdoc: SUBDOC_ACCOUNTS, desc: 'Returns the list of accounts available to a new dapps.', params: [], @@ -1253,6 +1292,34 @@ export default { } }, + setNewDappsDefaultAddress: { + subdoc: SUBDOC_ACCOUNTS, + desc: 'Changes global default address. This setting may be overriden for a specific dapp.', + params: [ + { + type: Address, + desc: 'Default Address.', + example: '0x407d73d8a49eeb85d32cf465507dd71d507100c1' + } + ], + returns: { + type: Boolean, + desc: '`true` if the call was successful', + example: true + } + }, + + getNewDappsDefaultAddress: { + subdoc: SUBDOC_ACCOUNTS, + desc: 'Returns a default account available to dapps.', + params: [], + returns: { + type: Address, + desc: 'Default Address', + example: '0x407d73d8a49eeb85d32cf465507dd71d507100c1' + } + }, + listRecentDapps: { subdoc: SUBDOC_ACCOUNTS, desc: 'Returns a list of the most recent active dapps.', diff --git a/js/src/modals/DappPermissions/store.js b/js/src/modals/DappPermissions/store.js index 67f3de2e7..3239343c5 100644 --- a/js/src/modals/DappPermissions/store.js +++ b/js/src/modals/DappPermissions/store.js @@ -102,7 +102,7 @@ export default class Store { loadWhitelist () { return this._api.parity - .getNewDappsWhitelist() + .getNewDappsAddresses() .then((whitelist) => { this.setWhitelist(whitelist); }) @@ -113,7 +113,7 @@ export default class Store { updateWhitelist (whitelist) { return this._api.parity - .setNewDappsWhitelist(whitelist) + .setNewDappsAddresses(whitelist) .then(() => { this.setWhitelist(whitelist); }) diff --git a/js/src/modals/DappPermissions/store.spec.js b/js/src/modals/DappPermissions/store.spec.js index 1266bd057..20d927484 100644 --- a/js/src/modals/DappPermissions/store.spec.js +++ b/js/src/modals/DappPermissions/store.spec.js @@ -31,8 +31,8 @@ let store; function create () { api = { parity: { - getNewDappsWhitelist: sinon.stub().resolves(WHITELIST), - setNewDappsWhitelist: sinon.stub().resolves(true) + getNewDappsAddresses: sinon.stub().resolves(WHITELIST), + setNewDappsAddresses: sinon.stub().resolves(true) } }; @@ -46,7 +46,7 @@ describe('modals/DappPermissions/store', () => { describe('constructor', () => { it('retrieves the whitelist via api', () => { - expect(api.parity.getNewDappsWhitelist).to.be.calledOnce; + expect(api.parity.getNewDappsAddresses).to.be.calledOnce; }); it('sets the retrieved whitelist', () => { @@ -79,12 +79,12 @@ describe('modals/DappPermissions/store', () => { store.closeModal(); }); - it('calls setNewDappsWhitelist', () => { - expect(api.parity.setNewDappsWhitelist).to.have.been.calledOnce; + it('calls setNewDappsAddresses', () => { + expect(api.parity.setNewDappsAddresses).to.have.been.calledOnce; }); it('has the default account in first position', () => { - expect(api.parity.setNewDappsWhitelist).to.have.been.calledWith(['789', '456']); + expect(api.parity.setNewDappsAddresses).to.have.been.calledWith(['789', '456']); }); }); diff --git a/js/src/views/ParityBar/accountStore.js b/js/src/views/ParityBar/accountStore.js index bf854e194..fef00a142 100644 --- a/js/src/views/ParityBar/accountStore.js +++ b/js/src/views/ParityBar/accountStore.js @@ -61,7 +61,7 @@ export default class AccountStore { this.setDefaultAccount(address); return this._api.parity - .setNewDappsWhitelist(accounts) + .setNewDappsAddresses(accounts) .catch((error) => { console.warn('makeDefaultAccount', error); }); @@ -78,7 +78,7 @@ export default class AccountStore { return Promise .all([ - this._api.parity.getNewDappsWhitelist(), + this._api.parity.getNewDappsAddresses(), this._api.parity.allAccountsInfo() ]) .then(([whitelist, accounts]) => { diff --git a/js/src/views/ParityBar/accountStore.spec.js b/js/src/views/ParityBar/accountStore.spec.js index c13c62aa9..8b2a9a41a 100644 --- a/js/src/views/ParityBar/accountStore.spec.js +++ b/js/src/views/ParityBar/accountStore.spec.js @@ -76,8 +76,8 @@ describe('views/ParityBar/AccountStore', () => { store.setAccounts.restore(); }); - it('calls into parity_getNewDappsWhitelist', () => { - expect(api.parity.getNewDappsWhitelist).to.have.been.called; + it('calls into parity_getNewDappsAddresses', () => { + expect(api.parity.getNewDappsAddresses).to.have.been.called; }); it('calls into parity_allAccountsInfo', () => { @@ -104,8 +104,8 @@ describe('views/ParityBar/AccountStore', () => { return store.makeDefaultAccount(ACCOUNT_NEW); }); - it('calls into parity_setNewDappsWhitelist (with ordering)', () => { - expect(api.parity.setNewDappsWhitelist).to.have.been.calledWith([ + it('calls into parity_setNewDappsAddresses (with ordering)', () => { + expect(api.parity.setNewDappsAddresses).to.have.been.calledWith([ ACCOUNT_NEW, ACCOUNT_FIRST, ACCOUNT_DEFAULT ]); }); diff --git a/js/src/views/ParityBar/parityBar.test.js b/js/src/views/ParityBar/parityBar.test.js index 2623e4074..97c6e6251 100644 --- a/js/src/views/ParityBar/parityBar.test.js +++ b/js/src/views/ParityBar/parityBar.test.js @@ -36,8 +36,8 @@ function createApi () { parity: { defaultAccount: sinon.stub().resolves(ACCOUNT_DEFAULT), allAccountsInfo: sinon.stub().resolves(ACCOUNTS), - getNewDappsWhitelist: sinon.stub().resolves(null), - setNewDappsWhitelist: sinon.stub().resolves(true) + getNewDappsAddresses: sinon.stub().resolves(null), + setNewDappsAddresses: sinon.stub().resolves(true) } }; diff --git a/json/src/misc/dapps_settings.rs b/json/src/misc/dapps_settings.rs index 1e5565baf..5081c62b2 100644 --- a/json/src/misc/dapps_settings.rs +++ b/json/src/misc/dapps_settings.rs @@ -22,7 +22,9 @@ use hash; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct DappsSettings { /// A list of accounts this Dapp can see. - pub accounts: Vec, + pub accounts: Option>, + /// Default account + pub default: Option, } impl_serialization!(String => DappsSettings); @@ -40,7 +42,10 @@ impl_serialization!(String => DappsHistory); #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum NewDappsPolicy { /// All accounts are exposed by default. - AllAccounts, + AllAccounts { + /// Default account, which should be returned as the first one. + default: hash::Address, + }, /// Only accounts listed here are exposed by default for new dapps. Whitelist(Vec), } diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 9ad8196fe..01627ba28 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -221,7 +221,7 @@ impl EthClient where let store = take_weak!(self.accounts); store .note_dapp_used(dapp.clone()) - .and_then(|_| store.dapps_addresses(dapp)) + .and_then(|_| store.dapp_addresses(dapp)) .map_err(|e| errors::internal("Could not fetch accounts.", e)) } } @@ -308,10 +308,7 @@ impl Eth for EthClient where let author = move || { let mut miner = take_weak!(self.miner).author(); if miner == 0.into() { - let accounts = self.dapp_accounts(dapp.into())?; - if let Some(address) = accounts.get(0) { - miner = *address; - } + miner = self.dapp_accounts(dapp.into())?.get(0).cloned().unwrap_or_default(); } Ok(RpcH160::from(miner)) diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index 944b419f7..2e129d31e 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -187,7 +187,7 @@ impl Eth for EthClient { let accounts = self.accounts .note_dapp_used(dapp.clone()) - .and_then(|_| self.accounts.dapps_addresses(dapp)) + .and_then(|_| self.accounts.dapp_addresses(dapp)) .map_err(|e| errors::internal("Could not fetch accounts.", e)) .map(|accs| accs.into_iter().map(Into::::into).collect()); diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index 431c34e84..3fcc82c3a 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -18,7 +18,7 @@ use std::sync::{Arc, Weak}; use std::str::FromStr; use std::collections::{BTreeMap, HashSet}; -use futures::{self, Future, BoxFuture}; +use futures::{future, Future, BoxFuture}; use util::{RotatingLogger, Address}; use util::misc::version_data; @@ -118,7 +118,7 @@ impl Parity for ParityClient where let store = take_weak!(self.accounts); let dapp_accounts = store .note_dapp_used(dapp.clone().into()) - .and_then(|_| store.dapps_addresses(dapp.into())) + .and_then(|_| store.dapp_addresses(dapp.into())) .map_err(|e| errors::internal("Could not fetch accounts.", e))? .into_iter().collect::>(); @@ -146,16 +146,13 @@ impl Parity for ParityClient where fn default_account(&self, meta: Self::Metadata) -> BoxFuture { let dapp_id = meta.dapp_id(); - let default_account = move || { - Ok(take_weak!(self.accounts) - .dapps_addresses(dapp_id.into()) + future::ok( + take_weakf!(self.accounts) + .dapp_default_address(dapp_id.into()) + .map(Into::into) .ok() - .and_then(|accounts| accounts.get(0).cloned()) - .map(|acc| acc.into()) - .unwrap_or_default()) - }; - - futures::done(default_account()).boxed() + .unwrap_or_default() + ).boxed() } fn transactions_limit(&self) -> Result { diff --git a/rpc/src/v1/impls/parity_accounts.rs b/rpc/src/v1/impls/parity_accounts.rs index e28ea2510..60b615897 100644 --- a/rpc/src/v1/impls/parity_accounts.rs +++ b/rpc/src/v1/impls/parity_accounts.rs @@ -142,41 +142,69 @@ impl ParityAccounts for ParityAccountsClient { Ok(true) } - fn set_account_visibility(&self, _address: RpcH160, _dapp: RpcH256, _visible: bool) -> Result { - Ok(false) - } - - fn set_dapps_addresses(&self, dapp: DappId, addresses: Vec) -> Result { + fn set_dapp_addresses(&self, dapp: DappId, addresses: Option>) -> Result { let store = take_weak!(self.accounts); - store.set_dapps_addresses(dapp.into(), into_vec(addresses)) + store.set_dapp_addresses(dapp.into(), addresses.map(into_vec)) + .map_err(|e| errors::account("Couldn't set dapp addresses.", e)) + .map(|_| true) + } + + fn dapp_addresses(&self, dapp: DappId) -> Result, Error> { + let store = take_weak!(self.accounts); + + store.dapp_addresses(dapp.into()) + .map_err(|e| errors::account("Couldn't get dapp addresses.", e)) + .map(into_vec) + } + + fn set_dapp_default_address(&self, dapp: DappId, address: RpcH160) -> Result { + let store = take_weak!(self.accounts); + + store.set_dapp_default_address(dapp.into(), address.into()) + .map_err(|e| errors::account("Couldn't set dapp default address.", e)) + .map(|_| true) + } + + fn dapp_default_address(&self, dapp: DappId) -> Result { + let store = take_weak!(self.accounts); + + store.dapp_default_address(dapp.into()) + .map_err(|e| errors::account("Couldn't get dapp default address.", e)) + .map(Into::into) + } + + fn set_new_dapps_addresses(&self, addresses: Option>) -> Result { + let store = take_weak!(self.accounts); + + store + .set_new_dapps_addresses(addresses.map(into_vec)) .map_err(|e| errors::account("Couldn't set dapps addresses.", e)) .map(|_| true) } - fn dapps_addresses(&self, dapp: DappId) -> Result, Error> { + fn new_dapps_addresses(&self) -> Result>, Error> { let store = take_weak!(self.accounts); - store.dapps_addresses(dapp.into()) + store.new_dapps_addresses() .map_err(|e| errors::account("Couldn't get dapps addresses.", e)) - .map(into_vec) + .map(|accounts| accounts.map(into_vec)) } - fn set_new_dapps_whitelist(&self, whitelist: Option>) -> Result { + fn set_new_dapps_default_address(&self, address: RpcH160) -> Result { let store = take_weak!(self.accounts); - store - .set_new_dapps_whitelist(whitelist.map(into_vec)) - .map_err(|e| errors::account("Couldn't set dapps whitelist.", e)) + store.set_new_dapps_default_address(address.into()) + .map_err(|e| errors::account("Couldn't set new dapps default address.", e)) .map(|_| true) } - fn new_dapps_whitelist(&self) -> Result>, Error> { + fn new_dapps_default_address(&self) -> Result { let store = take_weak!(self.accounts); - store.new_dapps_whitelist() - .map_err(|e| errors::account("Couldn't get dapps whitelist.", e)) - .map(|accounts| accounts.map(into_vec)) + store.new_dapps_default_address() + .map_err(|e| errors::account("Couldn't get new dapps default address.", e)) + .map(Into::into) } fn recent_dapps(&self) -> Result, Error> { diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs index 966dc9a74..1f9cad92f 100644 --- a/rpc/src/v1/impls/personal.rs +++ b/rpc/src/v1/impls/personal.rs @@ -101,7 +101,7 @@ impl Personal for PersonalClient { let default = match request.from.as_ref() { Some(account) => Ok(account.clone().into()), None => accounts - .default_address(meta.dapp_id().into()) + .dapp_default_address(meta.dapp_id().into()) .map_err(|e| errors::account("Cannot find default account.", e)), }; diff --git a/rpc/src/v1/impls/signing.rs b/rpc/src/v1/impls/signing.rs index 5c52df79a..d737131a6 100644 --- a/rpc/src/v1/impls/signing.rs +++ b/rpc/src/v1/impls/signing.rs @@ -86,7 +86,7 @@ impl SigningQueueClient { let accounts = take_weakf!(self.accounts); let default_account = match default_account { DefaultAccount::Provided(acc) => acc, - DefaultAccount::ForDapp(dapp) => accounts.default_address(dapp).ok().unwrap_or_default(), + DefaultAccount::ForDapp(dapp) => accounts.dapp_default_address(dapp).ok().unwrap_or_default(), }; let dispatcher = self.dispatcher.clone(); diff --git a/rpc/src/v1/impls/signing_unsafe.rs b/rpc/src/v1/impls/signing_unsafe.rs index 1d778404c..d48935e44 100644 --- a/rpc/src/v1/impls/signing_unsafe.rs +++ b/rpc/src/v1/impls/signing_unsafe.rs @@ -55,7 +55,7 @@ impl SigningUnsafeClient { let accounts = take_weakf!(self.accounts); let default = match account { DefaultAccount::Provided(acc) => acc, - DefaultAccount::ForDapp(dapp) => accounts.default_address(dapp).ok().unwrap_or_default(), + DefaultAccount::ForDapp(dapp) => accounts.dapp_default_address(dapp).ok().unwrap_or_default(), }; let dis = self.dispatcher.clone(); diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index 40ae8c38c..2432b55e7 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -368,7 +368,7 @@ fn rpc_eth_gas_price() { fn rpc_eth_accounts() { let tester = EthTester::default(); let address = tester.accounts_provider.new_account("").unwrap(); - tester.accounts_provider.set_new_dapps_whitelist(None).unwrap(); + tester.accounts_provider.set_new_dapps_addresses(None).unwrap(); tester.accounts_provider.set_address_name(1.into(), "1".into()); tester.accounts_provider.set_address_name(10.into(), "10".into()); @@ -377,14 +377,14 @@ fn rpc_eth_accounts() { let response = r#"{"jsonrpc":"2.0","result":[""#.to_owned() + &format!("0x{:?}", address) + r#""],"id":1}"#; assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); - tester.accounts_provider.set_new_dapps_whitelist(Some(vec![1.into()])).unwrap(); + tester.accounts_provider.set_new_dapps_addresses(Some(vec![1.into()])).unwrap(); // even with some account it should return empty list (no dapp detected) let request = r#"{"jsonrpc": "2.0", "method": "eth_accounts", "params": [], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":["0x0000000000000000000000000000000000000001"],"id":1}"#; assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); // when we add visible address it should return that. - tester.accounts_provider.set_dapps_addresses("app1".into(), vec![10.into()]).unwrap(); + tester.accounts_provider.set_dapp_addresses("app1".into(), Some(vec![10.into()])).unwrap(); let request = r#"{"jsonrpc": "2.0", "method": "eth_accounts", "params": [], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":["0x000000000000000000000000000000000000000a"],"id":1}"#; let mut meta = Metadata::default(); diff --git a/rpc/src/v1/tests/mocked/parity.rs b/rpc/src/v1/tests/mocked/parity.rs index 1bf557717..a587554a3 100644 --- a/rpc/src/v1/tests/mocked/parity.rs +++ b/rpc/src/v1/tests/mocked/parity.rs @@ -110,17 +110,19 @@ fn rpc_parity_accounts_info() { assert_eq!(accounts.len(), 1); let address = accounts[0]; - deps.accounts.set_account_name(address.clone(), "Test".to_owned()).unwrap(); - deps.accounts.set_account_meta(address.clone(), "{foo: 69}".to_owned()).unwrap(); + deps.accounts.set_address_name(1.into(), "XX".into()); + deps.accounts.set_account_name(address.clone(), "Test".into()).unwrap(); + deps.accounts.set_account_meta(address.clone(), "{foo: 69}".into()).unwrap(); let request = r#"{"jsonrpc": "2.0", "method": "parity_accountsInfo", "params": [], "id": 1}"#; let response = format!("{{\"jsonrpc\":\"2.0\",\"result\":{{\"0x{}\":{{\"name\":\"Test\"}}}},\"id\":1}}", address.hex()); assert_eq!(io.handle_request_sync(request), Some(response)); // Change the whitelist - deps.accounts.set_new_dapps_whitelist(Some(vec![1.into()])).unwrap(); + let address = Address::from(1); + deps.accounts.set_new_dapps_addresses(Some(vec![address.clone()])).unwrap(); let request = r#"{"jsonrpc": "2.0", "method": "parity_accountsInfo", "params": [], "id": 1}"#; - let response = format!("{{\"jsonrpc\":\"2.0\",\"result\":{{}},\"id\":1}}"); + let response = format!("{{\"jsonrpc\":\"2.0\",\"result\":{{\"0x{}\":{{\"name\":\"XX\"}}}},\"id\":1}}", address.hex()); assert_eq!(io.handle_request_sync(request), Some(response)); } diff --git a/rpc/src/v1/tests/mocked/parity_accounts.rs b/rpc/src/v1/tests/mocked/parity_accounts.rs index 6c518945f..304ffd45e 100644 --- a/rpc/src/v1/tests/mocked/parity_accounts.rs +++ b/rpc/src/v1/tests/mocked/parity_accounts.rs @@ -125,48 +125,87 @@ fn rpc_parity_set_and_get_dapps_accounts() { // given let tester = setup(); tester.accounts.set_address_name(10.into(), "10".into()); - assert_eq!(tester.accounts.dapps_addresses("app1".into()).unwrap(), vec![]); + assert_eq!(tester.accounts.dapp_addresses("app1".into()).unwrap(), vec![]); // when - let request = r#"{"jsonrpc": "2.0", "method": "parity_setDappsAddresses","params":["app1",["0x000000000000000000000000000000000000000a","0x0000000000000000000000000000000000000001"]], "id": 1}"#; + let request = r#"{"jsonrpc": "2.0", "method": "parity_setDappAddresses","params":["app1",["0x000000000000000000000000000000000000000a","0x0000000000000000000000000000000000000001"]], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); // then - assert_eq!(tester.accounts.dapps_addresses("app1".into()).unwrap(), vec![10.into()]); - let request = r#"{"jsonrpc": "2.0", "method": "parity_getDappsAddresses","params":["app1"], "id": 1}"#; + assert_eq!(tester.accounts.dapp_addresses("app1".into()).unwrap(), vec![10.into()]); + let request = r#"{"jsonrpc": "2.0", "method": "parity_getDappAddresses","params":["app1"], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":["0x000000000000000000000000000000000000000a"],"id":1}"#; assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); } +#[test] +fn rpc_parity_set_and_get_dapp_default_address() { + // given + let tester = setup(); + tester.accounts.set_address_name(10.into(), "10".into()); + assert_eq!(tester.accounts.dapp_addresses("app1".into()).unwrap(), vec![]); + + // when + let request = r#"{"jsonrpc": "2.0", "method": "parity_setDappDefaultAddress","params":["app1", "0x000000000000000000000000000000000000000a"], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; + assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); + + // then + assert_eq!(tester.accounts.dapp_addresses("app1".into()).unwrap(), vec![10.into()]); + let request = r#"{"jsonrpc": "2.0", "method": "parity_getDappDefaultAddress","params":["app1"], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":"0x000000000000000000000000000000000000000a","id":1}"#; + assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); +} + #[test] fn rpc_parity_set_and_get_new_dapps_whitelist() { // given let tester = setup(); // when set to whitelist - let request = r#"{"jsonrpc": "2.0", "method": "parity_setNewDappsWhitelist","params":[["0x000000000000000000000000000000000000000a"]], "id": 1}"#; + let request = r#"{"jsonrpc": "2.0", "method": "parity_setNewDappsAddresses","params":[["0x000000000000000000000000000000000000000a"]], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); // then - assert_eq!(tester.accounts.new_dapps_whitelist().unwrap(), Some(vec![10.into()])); - let request = r#"{"jsonrpc": "2.0", "method": "parity_getNewDappsWhitelist","params":[], "id": 1}"#; + assert_eq!(tester.accounts.new_dapps_addresses().unwrap(), Some(vec![10.into()])); + let request = r#"{"jsonrpc": "2.0", "method": "parity_getNewDappsAddresses","params":[], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":["0x000000000000000000000000000000000000000a"],"id":1}"#; assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); // when set to empty - let request = r#"{"jsonrpc": "2.0", "method": "parity_setNewDappsWhitelist","params":[null], "id": 1}"#; + let request = r#"{"jsonrpc": "2.0", "method": "parity_setNewDappsAddresses","params":[null], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); // then - assert_eq!(tester.accounts.new_dapps_whitelist().unwrap(), None); - let request = r#"{"jsonrpc": "2.0", "method": "parity_getNewDappsWhitelist","params":[], "id": 1}"#; + assert_eq!(tester.accounts.new_dapps_addresses().unwrap(), None); + let request = r#"{"jsonrpc": "2.0", "method": "parity_getNewDappsAddresses","params":[], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":null,"id":1}"#; assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); } +#[test] +fn rpc_parity_set_and_get_new_dapps_default_address() { + // given + let tester = setup(); + tester.accounts.set_address_name(10.into(), "10".into()); + assert_eq!(tester.accounts.new_dapps_default_address().unwrap(), 0.into()); + + // when + let request = r#"{"jsonrpc": "2.0", "method": "parity_setNewDappsDefaultAddress","params":["0x000000000000000000000000000000000000000a"], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; + assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); + + // then + assert_eq!(tester.accounts.new_dapps_default_address().unwrap(), 10.into()); + let request = r#"{"jsonrpc": "2.0", "method": "parity_getNewDappsDefaultAddress","params":[], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":"0x000000000000000000000000000000000000000a","id":1}"#; + assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); +} + + #[test] fn rpc_parity_recent_dapps() { // given diff --git a/rpc/src/v1/traits/parity_accounts.rs b/rpc/src/v1/traits/parity_accounts.rs index 576786073..a3a9a8d9f 100644 --- a/rpc/src/v1/traits/parity_accounts.rs +++ b/rpc/src/v1/traits/parity_accounts.rs @@ -70,28 +70,51 @@ build_rpc_trait! { #[rpc(name = "parity_setAccountMeta")] fn set_account_meta(&self, H160, String) -> Result; - /// Sets account visibility. - /// @unimplemented - #[rpc(name = "parity_setAccountVisiblity")] - fn set_account_visibility(&self, H160, H256, bool) -> Result; - - /// Sets accounts exposed for particular dapp. - #[rpc(name = "parity_setDappsAddresses")] - fn set_dapps_addresses(&self, DappId, Vec) -> Result; + /// Sets addresses exposed for particular dapp. + /// Setting a non-empty list will also override default account. + /// Setting `None` will resets visible account to what's visible for new dapps + /// (does not affect default account though) + #[rpc(name = "parity_setDappAddresses")] + fn set_dapp_addresses(&self, DappId, Option>) -> Result; /// Gets accounts exposed for particular dapp. - #[rpc(name = "parity_getDappsAddresses")] - fn dapps_addresses(&self, DappId) -> Result, Error>; + #[rpc(name = "parity_getDappAddresses")] + fn dapp_addresses(&self, DappId) -> Result, Error>; + + /// Changes dapp default address. + /// Does not affect other accounts exposed for this dapp, but + /// default account will always be retured as the first one. + #[rpc(name = "parity_setDappDefaultAddress")] + fn set_dapp_default_address(&self, DappId, H160) -> Result; + + /// Returns current dapp default address. + /// If not set explicite for the dapp will return global default. + #[rpc(name = "parity_getDappDefaultAddress")] + fn dapp_default_address(&self, DappId) -> Result; /// Sets accounts exposed for new dapps. - /// `None` means that all accounts will be exposed. - #[rpc(name = "parity_setNewDappsWhitelist")] - fn set_new_dapps_whitelist(&self, Option>) -> Result; + /// Setting a non-empty list will also override default account. + /// Setting `None` exposes all internal-managed accounts. + /// (does not affect default account though) + #[rpc(name = "parity_setNewDappsAddresses")] + fn set_new_dapps_addresses(&self, Option>) -> Result; /// Gets accounts exposed for new dapps. - /// `None` means that all accounts will be exposed. - #[rpc(name = "parity_getNewDappsWhitelist")] - fn new_dapps_whitelist(&self) -> Result>, Error>; + /// `None` means that all accounts are exposes. + #[rpc(name = "parity_getNewDappsAddresses")] + fn new_dapps_addresses(&self) -> Result>, Error>; + + /// Changes default address for new dapps (global default address) + /// Does not affect other accounts exposed for new dapps, but + /// default account will always be retured as the first one. + #[rpc(name = "parity_setNewDappsDefaultAddress")] + fn set_new_dapps_default_address(&self, H160) -> Result; + + /// Returns current default address for new dapps (global default address) + /// In case it's not set explicite will return first available account. + /// If no accounts are available will return `0x0` + #[rpc(name = "parity_getNewDappsDefaultAddress")] + fn new_dapps_default_address(&self) -> Result; /// Returns identified dapps that recently used RPC /// Includes last usage timestamp.