Skip to content

Commit

Permalink
feat: Server config
Browse files Browse the repository at this point in the history
  • Loading branch information
simonas-notcat committed Oct 13, 2020
1 parent 21f5ace commit b3b9639
Show file tree
Hide file tree
Showing 16 changed files with 203 additions and 113 deletions.
27 changes: 23 additions & 4 deletions testing.yml → alice.yml
@@ -1,3 +1,22 @@
server:
hostname: localhost
port: 3332
schemaPath: /open-api.json
apiBasePath: /agent
apiDocsPath: /api-docs
defaultIdentity:
create: true
messagingServiceEndpoint: /messaging
publicProfileServiceEndpoint: /public-profile
publicName: Alice
publicPicture: https://picsum.photos/200
ngrok:
connect: true
subdomain: alice-did
region: eu
# exposedMethods:
# - resolveDid
# - dataStoreORMGetIdentities
constants:
secretKey: 29739248cad1bd1a0fc4d9b75cd4d2990de535baf5caadfdf8d8f86664aa830c
databaseFile: ./database.sqlite
Expand Down Expand Up @@ -115,10 +134,10 @@ agent:
- $require: daf-typeorm#DataStore
$args:
- $ref: /dbConnection
# - $require: daf-typeorm#DataStoreORM
# $args:
# - $ref: /dbConnection
# - $ref: /messageHandler
- $require: daf-typeorm#DataStoreORM
$args:
- $ref: /dbConnection
- $ref: /messageHandler
- $require: daf-did-comm#DIDComm
- $require: daf-w3c#CredentialIssuer
- $require: daf-selective-disclosure#SelectiveDisclosure
2 changes: 1 addition & 1 deletion docs/api/daf-rest.md
Expand Up @@ -4,7 +4,7 @@

## daf-rest package

Provides a [plugin](./daf-rest.agentrestclient.md) for the [Agent](./daf-core.agent.md) that can proxy method execution over HTTPS using
Provides a [plugin](./daf-rest.agentrestclient.md) for the [Agent](./daf-core.agent.md) that can proxy method execution over HTTPS

## Classes

Expand Down
2 changes: 1 addition & 1 deletion docs/api/daf-typeorm.datastoreorm.md

Large diffs are not rendered by default.

4 changes: 1 addition & 3 deletions docs/api/daf-typeorm.datastoreorm.schema.md
Expand Up @@ -75,7 +75,7 @@ readonly schema: {
};
required: string[];
};
IIdentity: {
PartialIdentity: {
type: string;
properties: {
did: {
Expand Down Expand Up @@ -109,8 +109,6 @@ readonly schema: {
description: string;
};
};
required: string[];
description: string;
};
IKey: {
type: string;
Expand Down
2 changes: 1 addition & 1 deletion docs/api/index.md
Expand Up @@ -19,7 +19,7 @@
| [daf-message-handler](./daf-message-handler.md) | Provides a [plugin](./daf-message-handler.messagehandler.md) for the [Agent](./daf-core.agent.md) that implements [IMessageHandler](./daf-core.imessagehandler.md) interface |
| [daf-resolver](./daf-resolver.md) | Provides a [plugin](./daf-resolver.dafresolver.md) for the [Agent](./daf-core.agent.md) that implements [IResolver](./daf-core.iresolver.md) interface |
| [daf-resolver-universal](./daf-resolver-universal.md) | Provides a [plugin](./daf-resolver-universal.dafuniversalresolver.md) for the [Agent](./daf-core.agent.md) that implements [IResolver](./daf-core.iresolver.md) interface. Uses external "universal" resolver |
| [daf-rest](./daf-rest.md) | Provides a [plugin](./daf-rest.agentrestclient.md) for the [Agent](./daf-core.agent.md) that can proxy method execution over HTTPS using |
| [daf-rest](./daf-rest.md) | Provides a [plugin](./daf-rest.agentrestclient.md) for the [Agent](./daf-core.agent.md) that can proxy method execution over HTTPS |
| [daf-selective-disclosure](./daf-selective-disclosure.md) | Provides a [plugin](./daf-selective-disclosure.iselectivedisclosure.md) for the [Agent](./daf-core.agent.md) that implements [SelectiveDisclosure](./daf-selective-disclosure.selectivedisclosure.md) interface. Provides a [plugin](./daf-selective-disclosure.sdrmessagehandler.md) for the [MessageHandler](./daf-message-handler.messagehandler.md) that detects Selective Disclosure Request in a message |
| [daf-typeorm](./daf-typeorm.md) | [TypeORM](https://typeorm.io/) backed plugins. [Agent](./daf-core.agent.md) [plugin](./daf-typeorm.datastore.md) that implements [IDataStore](./daf-core.idatastore.md) interface. [Agent](./daf-core.agent.md) [plugin](./daf-typeorm.datastoreorm.md) that implements [IDataStoreORM](./daf-typeorm.idatastoreorm.md) interface. Provides [KeyStore](./daf-typeorm.keystore.md) for [KeyManager](./daf-key-manager.keymanager.md) and [IdentityStore](./daf-typeorm.identitystore.md) for [IdentityManager](./daf-identity-manager.identitymanager.md) |
| [daf-url](./daf-url.md) | Provides a [plugin](./daf-url.urlmessagehandler.md) for the [MessageHandler](./daf-message-handler.messagehandler.md) that finds a standard URL in a raw message |
Expand Down
19 changes: 19 additions & 0 deletions packages/daf-cli/default/config.yml
@@ -1,3 +1,22 @@
server:
hostname: localhost
port: 3332
schemaPath: /open-api.json
apiBasePath: /agent
apiDocsPath: /api-docs
defaultIdentity:
create: true
messagingServiceEndpoint: /messaging
publicProfileServiceEndpoint: /public-profile
publicName: Alice
publicPicture: https://picsum.photos/200
ngrok:
connect: true
# subdomain: alice-did
# region: eu
# exposedMethods:
# - resolveDid
# - dataStoreORMGetIdentities
constants:
secretKey: 29739248cad1bd1a0fc4d9b75cd4d2990de535baf5caadfdf8d8f86664aa830c
databaseFile: ./database.sqlite
Expand Down
86 changes: 45 additions & 41 deletions packages/daf-cli/src/server.ts
Expand Up @@ -5,55 +5,32 @@ import parse from 'url-parse'
import { AgentRouter } from 'daf-express'
import { getOpenApiSchema } from 'daf-rest'
import swaggerUi from "swagger-ui-express";
import { getAgent } from './setup'
import { getAgent, getConfig } from './setup'

program
.command('server')
.description('Launch OpenAPI server')
.option('--port <port>', 'Port', '3332')
.option('--hostname <string>', 'Server hostname', 'localhost')
.option('--ngrok', 'Open ngrok tunnel')
.option('--ngrokSubdomain <string>', 'ngrok subdomain')
.option('--ngrokRegion <string>', 'ngrok region')
.option('--createDefaultIdentity <boolean>', 'Should the agent create default web did', true)
.option('--messagingServiceEndpoint <path>', 'Path of the messaging service endpoint', '/messaging')
.option(
'--publicProfileServiceEndpoint <path>',
'Path of the public profile service endpoint',
'/public-profile',
)
.option('--publicName <string>', 'Public name', 'Service')
.option('--publicPicture <string>', 'Public picture', 'https://picsum.photos/200')
.option(
'--exposedMethods <string>',
'Comma separated list of exposed agent methods (example: "resolveDid,handleMessage")',
)
.action(async (options) => {
.action(async () => {
const app = express()
const agent = getAgent(program.config)
const { server: options } = getConfig(program.config)

const exposedMethods = options.exposedMethods
? options.exposedMethods.split(',')
? options.exposedMethods
: agent.availableMethods()

const basePath = '/agent'
const apiBasePath = options.apiBasePath

const agentRouter = AgentRouter({
basePath,
basePath: apiBasePath,
getAgentForRequest: async (req) => agent,
exposedMethods,
serveSchema: true,
})

app.use(basePath, agentRouter)
app.use(apiBasePath, agentRouter)


app.use(
"/api-docs",
swaggerUi.serve,
swaggerUi.setup(
getOpenApiSchema(agent, basePath, exposedMethods)
)
);

app.listen(options.port, async () => {
console.log(`🚀 Agent server ready at http://localhost:${options.port}`)
Expand All @@ -64,23 +41,40 @@ program

let baseUrl = 'http://' + hostname + ':' + options.port

if (options.ngrok) {
if (options.ngrok?.connect) {
baseUrl = await ngrok.connect({
addr: options.port,
subdomain: options.ngrokSubdomain,
region: options.ngrokRegion,
subdomain: options.ngrok.subdomain,
region: options.ngrok.region,
})
hostname = parse(baseUrl).hostname
}

if (options.createDefaultIdentity) {
const openApiSchema = getOpenApiSchema(agent, apiBasePath, exposedMethods)
openApiSchema.servers = [
{ url: baseUrl }
]

app.use(
options.apiDocsPath,
swaggerUi.serve,
swaggerUi.setup(openApiSchema)
)
console.log('📖 API Documentation', baseUrl + options.apiDocsPath)

app.get(options.schemaPath, (req, res) => { res.json(openApiSchema) })


console.log('🗺 OpenAPI schema', baseUrl + options.schemaPath)

if (options.defaultIdentity.create) {
let serverIdentity = await agent.identityManagerGetOrCreateIdentity({
provider: 'did:web',
alias: hostname,
})
console.log('🆔', serverIdentity.did)

const messagingServiceEndpoint = 'https://' + hostname + options.messagingServiceEndpoint
const messagingServiceEndpoint = baseUrl + options.defaultIdentity.messagingServiceEndpoint

await agent.identityManagerAddService({
did: serverIdentity.did,
Expand All @@ -93,7 +87,7 @@ program
})
console.log('📨 Messaging endpoint', messagingServiceEndpoint)

app.post(options.messagingServiceEndpoint, express.text({ type: '*/*' }), async (req, res) => {
app.post(options.defaultIdentity.messagingServiceEndpoint, express.text({ type: '*/*' }), async (req, res) => {
try {
const message = await agent.handleMessage({ raw: req.body, save: true })
console.log('Received message', message.type, message.id)
Expand All @@ -104,7 +98,7 @@ program
}
})

const publicProfileServiceEndpoint = 'https://' + hostname + options.publicProfileServiceEndpoint
const publicProfileServiceEndpoint = baseUrl + options.defaultIdentity.publicProfileServiceEndpoint

await agent.identityManagerAddService({
did: serverIdentity.did,
Expand All @@ -117,7 +111,7 @@ program
})
console.log('🌍 Public Profile', publicProfileServiceEndpoint)

app.get(options.publicProfileServiceEndpoint, async (req, res) => {
app.get(options.defaultIdentity.publicProfileServiceEndpoint, async (req, res) => {
try {
const nameCredential = await agent.createVerifiableCredential({
credential: {
Expand All @@ -127,7 +121,7 @@ program
issuanceDate: new Date().toISOString(),
credentialSubject: {
id: serverIdentity.did,
name: options.publicName,
name: options.defaultIdentity.publicName,
},
},
proofFormat: 'jwt',
Expand All @@ -141,7 +135,7 @@ program
issuanceDate: new Date().toISOString(),
credentialSubject: {
id: serverIdentity.did,
picture: options.publicPicture,
picture: options.defaultIdentity.publicPicture,
},
},
proofFormat: 'jwt',
Expand Down Expand Up @@ -195,6 +189,16 @@ program
res.json(didDoc)
})
console.log('📋 DID Document ' + baseUrl + didDocEndpoint)

app.get('/', (req, res) => {
const links = [
{ label: "API Docs", url: options.apiDocsPath},
{ label: "API Schema", url: options.apiBasePath},
]

const html = `<html><head><title>DID Agent</title></head><body>${links.map(l=>`<a href="${l.url}">${l.label}</a>`).join('<br/>')}</body></html>`
res.send(html)
})
}
})
})
6 changes: 3 additions & 3 deletions packages/daf-cli/src/setup.ts
Expand Up @@ -7,13 +7,13 @@ import { ISelectiveDisclosure } from 'daf-selective-disclosure'
import { IDIDComm } from 'daf-did-comm'
import { IDataStoreORM } from 'daf-typeorm'
const fs = require('fs')
const { dirname } = require('path')
const { dirname, resolve } = require('path')
import { createAgentFromConfig } from './lib/agentCreator'

const defaultConfig = process.env.HOME + '/.daf/config.yml'
const defaultConfig = './agent.yml'
program.option('--config <path>', 'Configuration file', defaultConfig)

const getConfig = (fileName: string): object => {
export const getConfig = (fileName: string): any => {
if (!fs.existsSync(dirname(fileName))) {
fs.mkdirSync(dirname(fileName))
}
Expand Down
5 changes: 4 additions & 1 deletion packages/daf-core/src/agent.ts
@@ -1,5 +1,6 @@
import { IAgent, IPluginMethodMap, IAgentPlugin, TAgent, IAgentPluginSchema } from './types/IAgent'
import { validateArguments, validateReturnType } from './validator'
import ValidationErrorSchema from './schemas/ValidationError'
import Debug from 'debug'

/**
Expand Down Expand Up @@ -97,7 +98,9 @@ export class Agent implements IAgent {

this.schema = {
components: {
schemas: {},
schemas: {
...ValidationErrorSchema.components.schemas
},
methods: {}
}
}
Expand Down
39 changes: 39 additions & 0 deletions packages/daf-core/src/schemas/ValidationError.ts
@@ -0,0 +1,39 @@
export default {
"components": {
"schemas": {
"ValidationError": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Error name"
},
"method": {
"type": "string",
"description": "Method"
},
"message": {
"type": "string",
"description": "Error message"
},
"path": {
"type": "string",
"description": "Error path"
},
"code": {
"type": "string",
"description": "Error code"
},
"description": {
"type": "string",
"description": "Error description"
},
},
"required": [
"didUrl"
],
"description": "Agent method arguments validation error"
}
}
}
}
1 change: 1 addition & 0 deletions packages/daf-express/src/index.ts
Expand Up @@ -82,6 +82,7 @@ export const AgentRouter = (options: AgentRouterOptions): Router => {
res.status(400).json({
name: 'ValidationError',
message: e.message,
method: e.method,
path: e.path,
code: e.code,
description: e.description
Expand Down
2 changes: 1 addition & 1 deletion packages/daf-rest/api/daf-rest.api.json
Expand Up @@ -7,7 +7,7 @@
},
"kind": "Package",
"canonicalReference": "daf-rest!",
"docComment": "/**\n * Provides a {@link daf-rest#AgentRestClient | plugin} for the {@link daf-core#Agent} that can proxy method execution over HTTPS using {@link daf-rest#openApiSchema | OpenAPI}\n *\n * @packageDocumentation\n */\n",
"docComment": "/**\n * Provides a {@link daf-rest#AgentRestClient | plugin} for the {@link daf-core#Agent} that can proxy method execution over HTTPS\n *\n * @packageDocumentation\n */\n",
"name": "daf-rest",
"members": [
{
Expand Down

0 comments on commit b3b9639

Please sign in to comment.