Skip to content

Commit

Permalink
feat: web3 headless provider and wallet
Browse files Browse the repository at this point in the history
  • Loading branch information
nklomp committed Aug 25, 2023
1 parent 62dc7df commit c69cf9e
Show file tree
Hide file tree
Showing 10 changed files with 95 additions and 1,306 deletions.
4 changes: 2 additions & 2 deletions packages/ssi-express-support/__tests__/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ async function init() {
const devMetadata: ClientMetadata = {
client_id: env('OIDC_CLIENT_ID', PREFIX) ?? 'EnergySHRDev',
client_secret: env('OIDC_CLIENT_SECRET', PREFIX) ?? 'iZDmseeTIpuVFcodqc3cQpJ6gak7xMfa',
redirect_uris: ['http://localhost:3001/authentication/callback'],
post_logout_redirect_uris: ['http://localhost:3001/authentication/logout-callback'],
redirect_uris: ['http://localhost:8000/authentication/callback'],
post_logout_redirect_uris: ['http://localhost:8000/authentication/logout-callback'],
response_types: ['code'],
token_endpoint_auth_method: 'client_secret_basic',
}
Expand Down
8 changes: 7 additions & 1 deletion packages/ssi-express-support/src/express-utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import express, { NextFunction } from 'express'
export function sendErrorResponse(response: express.Response, statusCode: number, message: string | object, error?: any) {
console.log(`sendErrorResponse: ${message}`)
if (!message) {
console.log('Message was null when calling sendErrorResponse. This should not happen')
console.log(Error().stack)
message = 'An unexpected error occurred'
statusCode = 500
}
if (error) {
console.log(JSON.stringify(error))
}
Expand All @@ -21,7 +27,7 @@ export function sendErrorResponse(response: express.Response, statusCode: number

export const jsonErrorHandler = (err: any, req: express.Request, res: express.Response, next: NextFunction) => {
const statusCode: number = 'statusCode' in err ? err.statusCode : 500
const errorMsg = typeof err === 'string' ? err : err.message
const errorMsg = typeof err === 'string' ? err : (err.message ?? err)
if (res.headersSent) {
console.log('Headers already sent, when calling error handler. Will defer to next error handler')
console.log(`Error was: ${JSON.stringify(err)}`)
Expand Down
15 changes: 12 additions & 3 deletions packages/ssi-express-support/src/openid-connect-rp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,18 @@ export function getLogoutCallbackEndpoint(router: Router, opts?: ISingleEndpoint
return
}
const path = opts?.path ?? '/authentication/logout-callback'
router.get(path, (req, res) => {
req.logout((err) => console.log(err))
res.redirect(env('OIDC_FRONTEND_LOGOUT_REDIRECT_URL', PREFIX) ?? '/')
router.get(path, (req, res, next) => {
try {
req.logout((err) => {
if (err) {
console.log(`Error during calling logout-callback: ${JSON.stringify(err)}`)
}
}
)
return res.redirect(env('OIDC_FRONTEND_LOGOUT_REDIRECT_URL', PREFIX) ?? '/')
} catch (e) {
return sendErrorResponse(res, 500, 'An unexpected error occurred during logout callback', e)
}
})
}

Expand Down
11 changes: 9 additions & 2 deletions packages/web3-provider-headless/__tests__/agent.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {ExpressBuilder, ExpressCorsConfigurer} from "@sphereon/ssi-express-support";
import {SphereonKeyManager} from "@sphereon/ssi-sdk-ext.key-manager";
import {SphereonKeyManagementSystem} from "@sphereon/ssi-sdk-ext.kms-local";
import {createAgent, IDIDManager, IKeyManager, IResolver, TAgent} from "@veramo/core";
Expand Down Expand Up @@ -39,7 +40,7 @@ const agent: TAgent<IKeyManager & IDIDManager & IResolver> = createAgent({
const context: IRequiredContext = {agent}
agent.keyManagerImport({
// privateKeyHex: '8f2695a99c416ab9241fc75ae53f90b083aecff9e4463e046a1527f456b502c6',
privateKeyHex: 'f5c0438db93a60a191530c0dd61a118bfb26ce4afb1ee54ea67deb15ec92d164',
privateKeyHex: process.env.WEB3_IMPORT_PRIVATEKEY_HEX ?? 'f5c0438db93a60a191530c0dd61a118bfb26ce4afb1ee54ea67deb15ec92d164',
kms: 'local',
type: 'Secp256k1'
}).then(key => {
Expand All @@ -54,7 +55,13 @@ agent.keyManagerImport({
[signers, web3Provider] = injectWeb3Provider({signers: [kmsSigner]})
const headlessProvider = web3Provider as EthersHeadlessProvider
console.log(`Signers: ${signers}`)
createRpcServer(headlessProvider)
const expressSupport = ExpressBuilder.fromServerOpts({
hostname: "0.0.0.0",
port: 3000,
basePath: "/web3/rpc"
}).withCorsConfigurer(new ExpressCorsConfigurer().allowOrigin("*")).build()
createRpcServer(headlessProvider, expressSupport)
expressSupport.start()
})
console.log('DONE')

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/*
import {SphereonKeyManager} from "@sphereon/ssi-sdk-ext.key-manager";
import {SphereonKeyManagementSystem} from "@sphereon/ssi-sdk-ext.kms-local";
import {createAgent, IDIDManager, IKeyManager, IResolver, ManagedKeyInfo, TAgent} from "@veramo/core";
Expand Down Expand Up @@ -89,3 +90,4 @@ describe('Headless web3 provider', () => {
console.log('DONE')
}, 60000)
})
*/
2 changes: 1 addition & 1 deletion packages/web3-provider-headless/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@
"start:dev": "ts-node __tests__/agent.ts"
},
"dependencies": {
"@sphereon/ssi-express-support": "^0.15.1",
"@ethersproject/abstract-provider": "^5.7.0",
"@ethersproject/abstract-signer": "^5.7.0",
"@ethersproject/properties": "^5.7.0",
"@ethersproject/strings": "^5.7.0",
"@ethersproject/transactions": "^5.7.0",
"web3": "1.10.1",
"bn.js": "^5.2.1",
"elliptic": "6.5.4",
"@metamask/eth-sig-util": "^6.0.0",
Expand Down
56 changes: 35 additions & 21 deletions packages/web3-provider-headless/src/rpc-server.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,40 @@
import bodyParser from "body-parser";
import cors from "cors";
import express, {Express} from "express";
// import {rpcHandler} from "typed-rpc/express";
import {ExpressSupport, ISingleEndpointOpts, sendErrorResponse} from "@sphereon/ssi-express-support";
import {EthersHeadlessProvider} from "./ethers-headless-provider";
import {Web3Method} from "./types";


export function createRpcServer(provider: EthersHeadlessProvider, opts?: {
express?: Express,
basePath?: string
}) {
const app = opts?.express ?? express();
app.use(express.json());
app.use(cors())
app.use(bodyParser.urlencoded({extended: true}));
export function createRpcServer(provider: EthersHeadlessProvider, expressSupport: ExpressSupport, opts?: ISingleEndpointOpts) {
const app = expressSupport.express
// app.post(opts?.basePath ?? "/web3/rpc", (req, res, next) => {console.log(`${JSON.stringify(req.body, null,2)}`); next()} , rpcHandler(createService(provider)));
app.post(opts?.basePath ?? "/web3/rpc", (req, res, next) => {
console.log(`REQ ${req.body.method}:\r\n${JSON.stringify(req.body, null, 2)}\r\n===`);
app.post(opts?.path ?? "/web3/rpc", (req, res, next) => {
console.log(`REQ ${req.body?.method}:\r\n${JSON.stringify(req.body, null, 2)}\r\n===`);
next()
}, async (req, res, next) => {
try {
const method = req.body.method
const params = req.body.params
const id = req.body.id

// todo: A Notification is a Request object without an "id" member.
// A Request object that is a Notification signifies the Client's lack of interest in the corresponding Response object,
// and as such no Response object needs to be returned to the client. The Server MUST NOT reply to a Notification, including those that are within a batch request.
if (req.body.jsonrpc !== "2.0") {
console.log("No valid JSON RPC call received", JSON.stringify(req.body))
return sendErrorResponse(res, 200, {
id: req.body.id,
jsonrpc: "2.0",
error: "No valid JSON RPC call received. No jsonrp version supplied",
code: -32600
})
} else if (!id || !method) {
console.log("No valid JSON RPC call received", JSON.stringify(req.body))
return sendErrorResponse(res, 200, {
id: req.body.id,
jsonrpc: "2.0",
error: "No valid JSON RPC call received",
code: -32600
})
}
const result = provider.request({method, params})
provider.authorizeAll()
const respBody = {id, jsonrpc: "2.0", result: await result}
Expand All @@ -33,17 +45,19 @@ export function createRpcServer(provider: EthersHeadlessProvider, opts?: {
let msg = error.message
if (`body` in error) {
msg = error.body
res.json(error.body)
return sendErrorResponse(res, 200, msg)
// res.json(error.body)
} else {
res.json({id: req.body.id, jsonrpc: "2.0", error: msg, code: error.code})
return sendErrorResponse(res, 200, {
id: req.body.id,
jsonrpc: "2.0",
error: msg,
code: error.code ?? -32000
})
}
return next(msg)

}
next()
return next()
});
app.listen(3000);

}

export function createServiceMethod(method: string, service: Record<string, Function>, provider: EthersHeadlessProvider) {
Expand Down
99 changes: 0 additions & 99 deletions packages/web3-provider-headless/src/web3-kms-account.ts

This file was deleted.

7 changes: 6 additions & 1 deletion packages/web3-provider-headless/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,10 @@
"rootDir": "./src",
"outDir": "./dist",
"declarationDir": "./dist"
}
},
"references": [
{
"path": "../ssi-express-support"
}
]
}
Loading

0 comments on commit c69cf9e

Please sign in to comment.