Skip to content

Commit

Permalink
Implement Address Book Identity Provider with Passing Tests
Browse files Browse the repository at this point in the history
  • Loading branch information
topocount committed Sep 20, 2019
1 parent 971f72e commit 5232dfe
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import AddressIdentityProvider from './AddressIdentityProvider'
import { first, map } from 'rxjs/operators'
import { getCacheKey } from '../utils/index'

const addressBookAppIds = [
'0x32ec8cc9f3136797e0ae30e7bf3740905b0417b81ff6d4a74f6100f9037425de',
// TODO Add in App Ids for rinkeby and mainnet appIds
]
/**
* An identity provider for Address Book Entries
*
* @class AddressIdentityProvider
*/
export default class AddressBookIdentityProvider extends AddressIdentityProvider {
constructor (apps, cache) {
super()
this.apps = apps
this.cache = cache
}
/**
* Optional initialization, if required by the provider
*/
async init () {
// no-op
}

/**
* Resolve the identity metadata for an address
* Should resolve to null if an identity does not exist
* Will return the first successful resolution tity could not be found
*
* @param {string} address Address to resolve
* @return {Promise} Resolved metadata or rejected error
*/
async resolve (address) {
address = address.toLowerCase()
const addressBookApps = await this.apps.pipe(
first(),
map(apps => apps.filter(app => addressBookAppIds.includes(app.appId)))
).toPromise()

return await addressBookApps.reduce(async (identity, app) => {
if (identity) {
return identity
}
const cacheKey = getCacheKey(app.proxyAddress, 'state')
const { entries = [] } = await this.cache.get(cacheKey)
const { data: entryData } = entries
.find(entry => entry.addr.toLowerCase() === address) || {}
return entryData || null
}, null)
}

/**
* Modify the identity metadata of an address
*
* @param {string} address Address to resolve
* @param {Object} metadata Metadata to modify
* @return {Promise} Resolved success action or rejected error
*/
async modify (address, metadata) {
throw new Error('Use the Address Book to change this label, or create your own local label')
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import test from 'ava'
import Cache from '../cache'
import { of } from 'rxjs'

import { AddressBookIdentityProvider } from './index'
let apps, cache
test.before(async t => {
apps = of([
{
appId: '0x32ec8cc9f3136797e0ae30e7bf3740905b0417b81ff6d4a74f6100f9037425de',
proxyAddress: '0x0'
},
{
appId: '0x123',
proxyAddress: '0x1'
},
{
appId: '0x32ec8cc9f3136797e0ae30e7bf3740905b0417b81ff6d4a74f6100f9037425de',
proxyAddress: '0x11'
}
])

cache = new Cache('stubbedAddressBook')
await cache.init()
cache.set('0x0.state', { entries: [{addr: '0x3', data: { name: 'testEntity'}}] })
cache.set('0x11.state', { entries: [{addr: '0x3', data: { name: 'testEntity2'}}] })
})

test.beforeEach(async t => {
t.context.addressBookIdentityProvider = new AddressBookIdentityProvider(apps, cache)
await t.context.addressBookIdentityProvider.init()
})

test('should resolve identity from first address book in app array', async t => {
const provider = t.context.addressBookIdentityProvider
const identityMetadata = await provider.resolve('0x3')
t.is(identityMetadata.name, 'testEntity')
})

test('should resolve to null for non-existent identity', async t => {
const provider = t.context.addressBookIdentityProvider
const identityMetadata = await provider.resolve('0x9')
t.is(identityMetadata, null)
})

test('should throw error on any modify attempt', async t => {
const provider = t.context.addressBookIdentityProvider
await t.throwsAsync(() => provider.modify('0x9', { name: 'newEntity' }))
})
1 change: 1 addition & 0 deletions packages/aragon-wrapper/src/identity/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { default as AddressIdentityProvider } from './AddressIdentityProvider'
export { default as LocalIdentityProvider } from './LocalIdentityProvider'
export { default as AddressBookIdentityProvider } from './AddressBookIdentityProvider'
25 changes: 17 additions & 8 deletions packages/aragon-wrapper/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import { isKernelAppCodeNamespace } from './core/aragonOS/kernel'
import { setConfiguration } from './configuration'
import * as configurationKeys from './configuration/keys'
import ens from './ens'
import { LocalIdentityProvider } from './identity'
import { LocalIdentityProvider, AddressBookIdentityProvider } from './identity'
import { getAbi } from './interfaces'
import {
postprocessRadspecDescription,
Expand Down Expand Up @@ -184,8 +184,8 @@ export default class Aragon {
await this.kernelProxy.updateInitializationBlock()
await this.initAccounts(options.accounts)
await this.initAcl(Object.assign({ aclAddress }, options.acl))
await this.initIdentityProviders()
this.initApps()
await this.initIdentityProviders()
this.initForwarders()
this.initAppIdentifiers()
this.initNetwork()
Expand Down Expand Up @@ -879,6 +879,10 @@ export default class Aragon {
const defaultIdentityProviders = [{
name: 'local',
provider: new LocalIdentityProvider()
},
{
name: 'addressBook',
provider: new AddressBookIdentityProvider(this.apps, this.cache)
}]
// TODO: detect other installed providers
const detectedIdentityProviders = []
Expand Down Expand Up @@ -923,12 +927,17 @@ export default class Aragon {
* @return {Promise} Resolves with the identity or null if not found
*/
resolveAddressIdentity (address) {
const providerName = 'local' // TODO - get provider
const provider = this.identityProviderRegistrar.get(providerName)
if (provider && typeof provider.resolve === 'function') {
return provider.resolve(address)
}
return Promise.reject(new Error(`Provider (${providerName}) not installed`))
const providerNames = [ 'local', 'addressBook' ] // TODO - get provider
return providerNames.reduce(async (identity, providerName, index) => {
if (await identity) {
return identity
}
const provider = this.identityProviderRegistrar.get(providerName)
if (provider && typeof provider.resolve === 'function') {
return await provider.resolve(address)
}
return Promise.reject(new Error(`Provider (${providerName}) not installed`))
}, Promise.resolve(null))
}

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/aragon-wrapper/src/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ test('should init the identity providers correctly', async (t) => {
// assert
t.truthy(instance.identityProviderRegistrar)
t.true(instance.identityProviderRegistrar instanceof Map)
t.is(instance.identityProviderRegistrar.size, 1, 'Should have only one provider')
t.is(instance.identityProviderRegistrar.size, 2, 'Should have only two providers')
})

test('should emit an intent when requesting address identity modification', async (t) => {
Expand Down

0 comments on commit 5232dfe

Please sign in to comment.