Skip to content

Commit

Permalink
Feature: Improve secure storage nomenclature. Split storage and datab…
Browse files Browse the repository at this point in the history
…ase support into separate endpoints. Update tests. Related to #1.
  • Loading branch information
Chris committed Aug 22, 2021
1 parent febc9fc commit ff7d5f3
Show file tree
Hide file tree
Showing 17 changed files with 142 additions and 103 deletions.
2 changes: 1 addition & 1 deletion packages/account/src/account-interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export default interface AccountInterface {
*
* @param storageConfig
*/
linkStorage(storageConfig: Interfaces.SecureStorageContextConfig): Promise<void>
linkStorage(storageConfig: Interfaces.SecureContextConfig): Promise<void>

/**
* Unlink storage for this user
Expand Down
4 changes: 2 additions & 2 deletions packages/account/src/auto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ export default class AutoAccount implements AccountInterface {
*
* @param storageConfig
*/
public async linkStorage(storageConfig: Interfaces.SecureStorageContextConfig): Promise<void> {
await StorageLink.setLink(this.ceramic, this.ceramic.did!.id, storageConfig, false)
public async linkStorage(storageConfig: Interfaces.SecureContextConfig): Promise<void> {
await StorageLink.setLink(this.ceramic, this.ceramic.did!.id, storageConfig)
}

/**
Expand Down
4 changes: 2 additions & 2 deletions packages/network-ts/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const config: any = {
local: {
// For core development
ceramicUrl: 'http://localhost:7001/',
defaultStorageServerUrl: "http://localhost:5000/",
defaultDatabaseServerUrl: "http://localhost:5000/",
defaultMessageServerUrl: "http://localhost:5000/",
schemaPaths: {
'/': 'https://schemas.verida.io/',
Expand All @@ -15,7 +15,7 @@ const config: any = {
},
testnet: {
ceramicUrl: 'https://gateway-clay.ceramic.network/',
defaultStorageServerUrl: "https://dataserver.testnet.verida.io:5000/",
defaultDatabaseServerUrl: "https://dataserver.testnet.verida.io:5000/",
defaultMessageServerUrl: "https://dataserver.testnet.verida.io:5000/",
schemaPaths: {
'/': 'https://schemas.verida.io/',
Expand Down
42 changes: 21 additions & 21 deletions packages/network-ts/src/context/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ import BaseStorageEngine from './engines/base'
import { StorageEngineTypes } from './interfaces'
import StorageEngineVerida from './engines/verida/engine'
import DIDContextManager from '../did-context-manager'
import { StorageEngines } from '../interfaces'
import { DatabaseEngines } from '../interfaces'
import { DatabaseOpenConfig, DatastoreOpenConfig } from './interfaces'
import Database from './database'
import Datastore from './datastore'

const _ = require('lodash')

const STORAGE_ENGINES: StorageEngineTypes = {
'VeridaStorage': StorageEngineVerida
'VeridaDatabase': StorageEngineVerida,
'VeridaMessage': StorageEngineVerida
}

/**
Expand All @@ -24,7 +25,7 @@ export default class Context {
private account?: AccountInterface
private contextName: string
private didContextManager: DIDContextManager
private storageEngines: StorageEngines = {}
private databaseEngines: DatabaseEngines = {}

constructor(contextName: string, didContextManager: DIDContextManager, account?: AccountInterface) {
this.contextName = contextName
Expand All @@ -33,7 +34,7 @@ export default class Context {
this.account = account
}

public async getStorageConfig(did?: string): Promise<Interfaces.SecureStorageContextConfig> {
public async getContextConfig(did?: string): Promise<Interfaces.SecureContextConfig> {
if (!did) {
if (!this.account) {
throw new Error('No DID specified and no authenticated user')
Expand All @@ -55,31 +56,30 @@ export default class Context {
* @param did
* @returns
*/
private async getStorageEngine(did: string): Promise<BaseStorageEngine> {
if (this.storageEngines[did]) {
return this.storageEngines[did]
private async getDatabaseEngine(did: string): Promise<BaseStorageEngine> {
if (this.databaseEngines[did]) {
return this.databaseEngines[did]
}

const storageConfig = await this.getStorageConfig(did)

const engineType = storageConfig.services.storageServer.type
const contextConfig = await this.getContextConfig(did)
const engineType = contextConfig.services.databaseServer.type

if (!STORAGE_ENGINES[engineType]) {
throw new Error(`Unsupported storage engine type specified: ${engineType}`)
throw new Error(`Unsupported database engine type specified: ${engineType}`)
}
const engine = STORAGE_ENGINES[engineType] // @todo type cast correctly
const storageEngine = new engine(this.contextName, storageConfig.services.storageServer.endpointUri)
const databaseEngine = new engine(this.contextName, contextConfig.services.databaseServer.endpointUri)

/**
* Connect the current user if we have one
*/
if (this.account) {
await storageEngine.connectAccount(this.account)
await databaseEngine.connectAccount(this.account)
}

// cache storage engine for this did and context
this.storageEngines[did] = storageEngine
return storageEngine
this.databaseEngines[did] = databaseEngine
return databaseEngine
}

/**
Expand All @@ -95,23 +95,23 @@ export default class Context {
}

const accountDid = await this.account!.did()
const storageEngine = await this.getStorageEngine(accountDid)
return storageEngine.openDatabase(databaseName, options)
const databaseEngine = await this.getDatabaseEngine(accountDid)
return databaseEngine.openDatabase(databaseName, options)
}

/**
* Open a database owned by any user
*/
public async openExternalDatabase(databaseName: string, did: string, options: DatabaseOpenConfig): Promise<Database> {
const storageEngine = await this.getStorageEngine(did)
const storageConfig = await this.getStorageConfig(did)
const databaseEngine = await this.getDatabaseEngine(did)
const contextConfig = await this.getContextConfig(did)

options = _.merge({
did,
dsn: storageConfig.services.storageServer.endpointUri
dsn: contextConfig.services.databaseServer.endpointUri
}, options)

return storageEngine.openDatabase(databaseName, options)
return databaseEngine.openDatabase(databaseName, options)
}

public async openDatastore(schemaName: string, config: DatastoreOpenConfig = {}): Promise<Datastore> {
Expand Down
4 changes: 4 additions & 0 deletions packages/network-ts/src/context/engines/verida/base-db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -400,4 +400,8 @@ export default class BaseDb extends EventEmitter implements Database {
}
}

public async info(): Promise<any> {
throw new Error('Not implemented')
}

}
48 changes: 33 additions & 15 deletions packages/network-ts/src/did-context-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,16 @@ export default class DIDContextManager {

private didContexts: DIDContextConfigs = {}

private defaultStorageServer: Interfaces.SecureStorageServer
private defaultMessageServer: Interfaces.SecureStorageServer
private defaultDatabaseServer: Interfaces.SecureContextEndpoint
private defaultMessageServer: Interfaces.SecureContextEndpoint
private defaultStorageServer?: Interfaces.SecureContextEndpoint

private ceramic: CeramicClient
private account?: AccountInterface

public constructor(ceramic: CeramicClient, defaultStorageServer: Interfaces.SecureStorageServer, defaultMessageServer: Interfaces.SecureStorageServer) {
public constructor(ceramic: CeramicClient, defaultDatabaseServer: Interfaces.SecureContextEndpoint, defaultMessageServer: Interfaces.SecureContextEndpoint, defaultStorageServer?: Interfaces.SecureContextEndpoint) {
this.ceramic = ceramic
this.defaultDatabaseServer = defaultDatabaseServer
this.defaultStorageServer = defaultStorageServer
this.defaultMessageServer = defaultMessageServer
}
Expand All @@ -29,14 +32,23 @@ export default class DIDContextManager {
this.account = account
}

public async getContextStorageServer(did: string, contextName: string, forceCreate: boolean = true): Promise<Interfaces.SecureStorageServer> {
const storageConfig = await this.getDIDContextConfig(did, contextName, forceCreate)
return storageConfig.services.storageServer
public async getContextDatabaseServer(did: string, contextName: string, forceCreate: boolean = true): Promise<Interfaces.SecureContextEndpoint> {
const contextConfig = await this.getDIDContextConfig(did, contextName, forceCreate)
return contextConfig.services.databaseServer
}

public async getContextStorageServer(did: string, contextName: string, forceCreate: boolean = true): Promise<Interfaces.SecureContextEndpoint> {
const contextConfig = await this.getDIDContextConfig(did, contextName, forceCreate)
if (!contextConfig.services.storageServer) {
throw new Error('Storage server not specified')
}

return contextConfig.services.storageServer
}

public async getContextMessageServer(did: string, contextName: string, forceCreate: boolean = true): Promise<Interfaces.SecureStorageServer> {
const storageConfig = await this.getDIDContextConfig(did, contextName, forceCreate)
return storageConfig.services.messageServer
public async getContextMessageServer(did: string, contextName: string, forceCreate: boolean = true): Promise<Interfaces.SecureContextEndpoint> {
const contextConfig = await this.getDIDContextConfig(did, contextName, forceCreate)
return contextConfig.services.messageServer
}

public async getDIDContextHashConfig(did: string, contextHash: string) {
Expand All @@ -53,14 +65,14 @@ export default class DIDContextManager {
return storageConfig
}

public async getDIDContextConfig(did: string, contextName: string, forceCreate: boolean = true): Promise<Interfaces.SecureStorageContextConfig> {
public async getDIDContextConfig(did: string, contextName: string, forceCreate: boolean = true): Promise<Interfaces.SecureContextConfig> {
const contextHash = StorageLink.hash(`${did}/${contextName}`)

if (this.didContexts[contextHash]) {
return this.didContexts[contextHash]
}

let storageConfig = await StorageLink.getLink(this.ceramic, did, contextName)
let storageConfig = await StorageLink.getLink(this.ceramic, did, contextName, true)

if (!storageConfig) {
if (!forceCreate) {
Expand All @@ -77,11 +89,17 @@ export default class DIDContextManager {
throw new Error('Unable to create storage context for a different DID than the one authenticated')
}

// Force creation of storage context using default server configurations
storageConfig = await DIDStorageConfig.generate(this.account, contextName, {
storageServer: this.defaultStorageServer,
const endpoints: Interfaces.SecureContextServices = {
databaseServer: this.defaultDatabaseServer,
messageServer: this.defaultMessageServer
})
}

if (this.defaultStorageServer) {
endpoints.storageServer = this.defaultStorageServer
}

// Force creation of storage context using default server configurations
storageConfig = await DIDStorageConfig.generate(this.account, contextName, endpoints)

await this.account!.linkStorage(storageConfig)
}
Expand Down
8 changes: 4 additions & 4 deletions packages/network-ts/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@ import BaseStorageEngine from './context/engines/base'
export interface ManagerConfig {
environment?: string
ceramicUrl?: string
defaultStorageServer?: Interfaces.SecureStorageServer,
defaultMessageServer?: Interfaces.SecureStorageServer,
defaultDatabaseServer?: Interfaces.SecureContextEndpoint,
defaultMessageServer?: Interfaces.SecureContextEndpoint,
schemaPaths?: object
}

// key = contextName
// value = SecureStorageContextConfig
export interface DIDContextConfigs {
[key: string]: Interfaces.SecureStorageContextConfig
[key: string]: Interfaces.SecureContextConfig
}

// key = DID string
// value = BaseStorageEngine
export interface StorageEngines {
export interface DatabaseEngines {
[key: string]: BaseStorageEngine
}
2 changes: 1 addition & 1 deletion packages/network-ts/src/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default class Network {

this.ceramicUrl = config.ceramicUrl
this.ceramic = new CeramicClient(this.ceramicUrl)
this.didContextManager = new DIDContextManager(this.ceramic, config.defaultStorageServer, config.defaultMessageServer)
this.didContextManager = new DIDContextManager(this.ceramic, config.defaultDatabaseServer, config.defaultMessageServer, config.defaultStorageServer)
Schema.setSchemaPaths(config.schemaPaths)
}

Expand Down
2 changes: 1 addition & 1 deletion packages/network-ts/test/config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

export default {
STORAGE_LINK_SCHEMA: 'kjzl6cwe1jw1477jghfhwzru8a9kvec774jv4tylbyvqrh4z66px37b7zh3jfo3',
STORAGE_LINK_SCHEMA: 'kjzl6cwe1jw14653bh1mchb0sneoq1o1kcnky9w4gqa0e8cryrc4ax83vlm9dh7',
CERAMIC_URL: 'http://localhost:7007',
ETH_PRIVATE_KEY: '0x18d3b996ec98a9a536efdffbae40e5eaaf117765a587483c69195c9460165c8f',
DID: 'did:3:kjzl6cwe1jw1482rjifeq5ai96teeas0vm6hmcp9q5rmhk14th76f4d2tlnvy4d',
Expand Down
10 changes: 5 additions & 5 deletions packages/network-ts/test/storage.context.tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ describe('Storage initialization tests', () => {
let ceramic, context

const network = new VeridaNetwork({
defaultStorageServer: {
type: 'VeridaStorage',
defaultDatabaseServer: {
type: 'VeridaDatabase',
endpointUri: 'http://localhost:5000/'
},
defaultMessageServer: {
type: 'VeridaStorage',
type: 'VeridaMessage',
endpointUri: 'http://localhost:5000/'
},
ceramicUrl: CONFIG.CERAMIC_URL
Expand All @@ -44,8 +44,8 @@ describe('Storage initialization tests', () => {
assert.ok(context, 'Account context opened')

const fetchedStorageConfig = await StorageLink.getLink(ceramic, ceramic.did.id, CONFIG.CONTEXT_NAME)
const storageConfig = await context.getStorageConfig()
assert.deepEqual(fetchedStorageConfig, storageConfig, 'Storage context config matches')
const contextConfig = await context.getContextConfig()
assert.deepEqual(fetchedStorageConfig, contextConfig, 'Storage context config matches')
})

it('can open a database with owner/owner permissions', async function() {
Expand Down
12 changes: 6 additions & 6 deletions packages/network-ts/test/storage.init.tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ describe('Storage initialization tests', () => {
const utils = new Utils(CONFIG.CERAMIC_URL)
let ceramic
const network = new VeridaNetwork({
defaultStorageServer: {
type: 'VeridaStorage',
defaultDatabaseServer: {
type: 'VeridaDatabase',
endpointUri: 'https://localhost:7001/'
},
defaultMessageServer: {
type: 'VeridaStorage',
type: 'VeridaMessage',
endpointUri: 'https://localhost:7001/'
},
ceramicUrl: CONFIG.CERAMIC_URL
Expand Down Expand Up @@ -73,10 +73,10 @@ describe('Storage initialization tests', () => {
const accountContext = await network.openContext(CONFIG.CONTEXT_NAME, true)
assert.ok(accountContext, 'Account storage opened')

const accountStoageConfig = await accountContext.getStorageConfig()

const accountStorageConfig = await accountContext.getContextConfig()
const fetchedStorageConfig = await StorageLink.getLink(ceramic, ceramic.did.id, CONFIG.CONTEXT_NAME)
assert.deepEqual(fetchedStorageConfig, accountStoageConfig, 'Storage context config matches')

assert.deepEqual(fetchedStorageConfig, accountStorageConfig, 'Storage context config matches')
})
})
})
Loading

0 comments on commit ff7d5f3

Please sign in to comment.