Skip to content

Commit

Permalink
refactor(RpcClient)!: remove custom set of accounts
Browse files Browse the repository at this point in the history
BREAKING CHANGE: wallet-rpc can't handle specific account set for app anymore
If you need this feature, create a custom wallet implementation.
  • Loading branch information
davidyuk committed Jun 7, 2022
1 parent 1bcaca2 commit 5c26f3a
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 123 deletions.
64 changes: 1 addition & 63 deletions src/utils/aepp-wallet-communication/rpc/rpc-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*/
import stampit from '@stamp/it'

import { METHODS, RpcError, RpcInternalError } from '../schema'
import { RpcError, RpcInternalError } from '../schema'
import { InvalidRpcMessageError, MissingCallbackError } from '../../errors'

/**
Expand All @@ -30,11 +30,6 @@ export default stampit({
// [msg.id]: { resolve, reject }
// }
this.callbacks = {}
// {
// connected: { [pub]: {...meta} },
// current: { [pub]: {...meta} }
// }
this.accounts = {}

this._messageId = 0

Expand All @@ -59,26 +54,6 @@ export default stampit({

connection.connect(handleMessage, onDisconnect)
},
propertyDescriptors: {
currentAccount: {
enumerable: true,
configurable: false,
get () {
return this.isHasAccounts()
? Object.keys(this.accounts.current)[0]
: undefined
}
},
addresses: {
enumerable: true,
configurable: false,
get () {
return this.isHasAccounts()
? [...Object.keys(this.accounts.current), ...Object.keys(this.accounts.connected)]
: []
}
}
},
methods: {
_sendMessage ({ id, method, params, result, error }, isNotificationOrResponse = false) {
if (!isNotificationOrResponse) this._messageId += 1
Expand All @@ -96,43 +71,6 @@ export default stampit({
})
return id
},
isHasAccounts () {
return typeof this.accounts === 'object' &&
typeof this.accounts.connected === 'object' &&
typeof this.accounts.current === 'object'
},
/**
* Check if aepp has access to account
* @function hasAccessToAccount
* @instance
* @rtype (address: String) => Boolean
* @param {String} address Account address
* @return {Boolean} is connected
*/
hasAccessToAccount (address) {
return !!address && this.addresses.find(a => a === address)
},
/**
* Get selected account
* @function getCurrentAccount
* @instance
* @rtype ({ onAccount } = {}) => String
* @param {Object} options Options
* @return {String}
*/
getCurrentAccount ({ onAccount } = {}) {
return onAccount || Object.keys(this.accounts.current)[0]
},
/**
* Update accounts and sent `update.address` notification to AEPP
* @param {{ current: Object, connected: Object }} accounts Current and connected accounts
* @param {Object} [options]
* @param {Boolean} [options.forceNotification] Don't sent update notification to AEPP
*/
setAccounts (accounts, { forceNotification } = {}) {
this.accounts = accounts
if (!forceNotification) this.notify(METHODS.updateAddress, this.accounts)
},
/**
* Make a request
* @function request
Expand Down
56 changes: 18 additions & 38 deletions src/utils/aepp-wallet-communication/rpc/wallet-rpc.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
RpcNotAuthorizeError, RpcPermissionDenyError, RpcUnsupportedProtocolError, SUBSCRIPTION_TYPES
} from '../schema'
import { ArgumentError, UnknownRpcClientError } from '../../errors'
import { filterObject, mapObject } from '../../other'
import { mapObject } from '../../other'
import { unpackTx } from '../../../tx/builder'

const METHOD_HANDLERS = {
Expand Down Expand Up @@ -45,8 +45,7 @@ const METHOD_HANDLERS = {
async [METHODS.subscribeAddress] (callInstance, instance, client, clientInfo, { type, value }) {
if (!instance._isRpcClientConnected(client.id)) throw new RpcNotAuthorizeError()

const accounts = await callInstance('onSubscription', { type, value })
const clientAccounts = accounts || instance.getAccounts()
await callInstance('onSubscription', { type, value })

switch (type) {
case SUBSCRIPTION_TYPES.subscribe:
Expand All @@ -57,22 +56,22 @@ const METHOD_HANDLERS = {
break
}

client.setAccounts(clientAccounts, { forceNotification: true })
return {
subscription: Array.from(clientInfo.addressSubscription),
address: clientAccounts
address: instance.getAccounts()
}
},
async [METHODS.address] (callInstance, instance, client) {
if (!instance._isRpcClientSubscribed(client.id)) throw new RpcNotAuthorizeError()

const accounts = await callInstance('onAskAccounts') ?? client.accounts
return [...Object.keys(accounts.current), ...Object.keys(accounts.connected)]
await callInstance('onAskAccounts')
return instance.addresses()
},
async [METHODS.sign] (callInstance, instance, client, clientInfo, { tx, onAccount, returnSigned }) {
onAccount ??= client.currentAccount
async [METHODS.sign] (
callInstance, instance, client, clientInfo, { tx, onAccount, returnSigned }
) {
if (!instance._isRpcClientConnected(client.id)) throw new RpcNotAuthorizeError()
if (!client.hasAccessToAccount(onAccount)) throw new RpcPermissionDenyError(onAccount)
onAccount ??= await instance.address()
if (!instance.addresses().includes(onAccount)) throw new RpcPermissionDenyError(onAccount)

const overrides = await callInstance(
'onSign', { tx, returnSigned, onAccount, txObject: unpackTx(tx) }
Expand All @@ -92,8 +91,8 @@ const METHOD_HANDLERS = {
},
async [METHODS.signMessage] (callInstance, instance, client, clientInfo, { message, onAccount }) {
if (!instance._isRpcClientConnected(client.id)) throw new RpcNotAuthorizeError()
onAccount ??= client.currentAccount
if (!client.hasAccessToAccount(onAccount)) throw new RpcPermissionDenyError(onAccount)
onAccount ??= await instance.address()
if (!instance.addresses().includes(onAccount)) throw new RpcPermissionDenyError(onAccount)

const overrides = await callInstance('onMessageSign', { message, onAccount })
onAccount = overrides?.onAccount ?? onAccount
Expand Down Expand Up @@ -142,35 +141,17 @@ export default Ae.compose(AccountMultiple, {
const _addAccount = this.addAccount.bind(this)
const _selectNode = this.selectNode.bind(this)

const pushAccountsToApps = () => Object.keys(this.rpcClients)
.filter(clientId => this._isRpcClientSubscribed(clientId))
.map(clientId => this.rpcClients[clientId])
.forEach(client => client.notify(METHODS.updateAddress, this.getAccounts()))
this.selectAccount = (address) => {
_selectAccount(address)
Object.keys(this.rpcClients)
.filter(clientId => {
return this._isRpcClientSubscribed(clientId) &&
this.rpcClients[clientId].hasAccessToAccount(address)
})
.map(clientId => this.rpcClients[clientId])
.forEach(client => client.setAccounts({
current: { [address]: {} },
connected: {
...client.accounts.current,
...filterObject(client.accounts.connected, ([k]) => k !== address)
}
}))
pushAccountsToApps()
}
this.addAccount = async (account, { select } = {}) => {
await _addAccount(account, { select })
const address = await account.address()
Object.keys(this.rpcClients)
.filter(clientId => this._isRpcClientSubscribed(clientId))
.map(clientId => this.rpcClients[clientId])
.forEach(client => client.setAccounts({
current: { ...select ? { [address]: {} } : client.accounts.current },
connected: {
...select ? client.accounts.current : { [address]: {} },
...client.accounts.connected
}
}))
pushAccountsToApps()
}
this.selectNode = (name) => {
_selectNode(name)
Expand Down Expand Up @@ -200,7 +181,6 @@ export default Ae.compose(AccountMultiple, {
const clientInfo = this._rpcClientsInfo[clientId]
if (client == null || clientInfo == null) throw new UnknownRpcClientError(clientId)
client.connection.disconnect()
client.accounts = {}
clientInfo.status = RPC_STATUS.DISCONNECTED
clientInfo.addressSubscription = new Set()
},
Expand Down
32 changes: 10 additions & 22 deletions test/integration/rpc.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,9 @@ describe('Aepp<->Wallet', function () {
await spendPromise
wallet = await RpcWallet({
compilerUrl,
accounts: [MemoryAccount({ keypair: account })],
accounts: [
MemoryAccount({ keypair: account }), MemoryAccount({ keypair: generateKeyPair() })
],
nodes: [{ name: 'local', instance: node }],
id: 'test',
type: WALLET_TYPE.window,
Expand Down Expand Up @@ -150,13 +152,7 @@ describe('Aepp<->Wallet', function () {
})

it('Subscribe to address: wallet accept', async () => {
const accounts = {
connected: { [keypair.publicKey]: {} },
current: wallet.addresses().reduce((acc, v) => ({ ...acc, [v]: {} }), {})
}
wallet.onSubscription = () => {
return accounts
}
wallet.onSubscription = () => {}
await aepp.subscribeAddress('subscribe', 'connected')
await aepp.subscribeAddress('unsubscribe', 'connected')
const subscriptionResponse = await aepp.subscribeAddress('subscribe', 'connected')
Expand Down Expand Up @@ -230,7 +226,7 @@ describe('Aepp<->Wallet', function () {
amount: 0,
payload: 'zerospend'
})
await expect(aepp.signTransaction(tx, { onAccount: keypair.publicKey }))
await expect(aepp.signTransaction(tx, { onAccount: account.publicKey }))
.to.be.rejectedWith('The peer failed to execute your request due to unknown error')
})

Expand Down Expand Up @@ -299,21 +295,13 @@ describe('Aepp<->Wallet', function () {
isValid.should.be.equal(true)
})

it('Sign message using account not from sdk instance: do not provide account', async () => {
wallet.onMessageSign = () => {}
const onAccount = aepp.addresses()[1]
await expect(aepp.signMessage('test', { onAccount })).to.be.eventually
.rejectedWith('The peer failed to execute your request due to unknown error')
.with.property('code', 12)
})

it('Sign message using account not from sdk instance', async () => {
it('Sign message using custom account', async () => {
wallet.onMessageSign = (aepp, action) => {
if (action.params.onAccount === keypair.publicKey) {
return { onAccount: MemoryAccount({ keypair }) }
if (action.params.onAccount === account.publicKey) {
return { onAccount: MemoryAccount({ keypair: account }) }
}
}
const onAccount = keypair.publicKey
const onAccount = account.publicKey
const messageSig = await aepp.signMessage('test', { onAccount })
messageSig.should.be.instanceof(Buffer)
const isValid = await aepp.verifyMessage('test', messageSig, { onAccount })
Expand Down Expand Up @@ -476,7 +464,7 @@ describe('Aepp<->Wallet', function () {
subscriptionResponse.address.current.should.be.an('object')
Object.keys(subscriptionResponse.address.current)[0].should.be.equal(account.publicKey)
subscriptionResponse.address.connected.should.be.an('object')
Object.keys(subscriptionResponse.address.connected).length.should.be.equal(1)
Object.keys(subscriptionResponse.address.connected).length.should.be.equal(0)
})

it('Sign by wallet and broadcast transaction by aepp ', async () => {
Expand Down

0 comments on commit 5c26f3a

Please sign in to comment.