-
Notifications
You must be signed in to change notification settings - Fork 6
Feature/remote key manager #202
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feature/p2pmessaging
Are you sure you want to change the base?
Changes from all commits
e53d002
6ad4672
736638c
2d8519c
706be90
5275f85
7b829d3
6ac6520
f1d0e66
4444029
0fbe28b
7a8a5d0
838d4bb
8155a26
65fea20
0616570
f85b7e3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,7 +3,7 @@ | |
| "BROKER_HOST": "127.0.0.1" | ||
| }, | ||
| "PORTS": { | ||
| "BROKER_PORT": 1883, | ||
| "BROKER_PORT": 8000, | ||
| "TCP_PORT": 4005 | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| import { CruxProtocolMessenger, RemoteKeyManager} from "../../core/domain-services"; | ||
| import { keyManagementProtocol } from "../../infrastructure"; | ||
| import { CruxId, InMemStorage } from "../../packages/"; | ||
| import { CruxWalletClient } from "./crux-wallet-client"; | ||
|
|
||
| export class CruxServiceClient { | ||
| private selfIdClaim: any; | ||
| private cruxProtocolMessenger: any; | ||
|
|
||
| constructor(selfIdClaim: any, secureCruxNetwork: any, protocolSchema: any) { | ||
| this.selfIdClaim = selfIdClaim; | ||
| this.cruxProtocolMessenger = new CruxProtocolMessenger(secureCruxNetwork, protocolSchema); | ||
| } | ||
|
|
||
| public async getWalletClientForUser(remoteUserId: CruxId) { | ||
| await this.cruxProtocolMessenger.initialize(); | ||
| const remoteKeyManager = new RemoteKeyManager(this.cruxProtocolMessenger, remoteUserId); | ||
|
|
||
| await remoteKeyManager.initialize(); | ||
| return new CruxWalletClient({ | ||
| cacheStorage: new InMemStorage(), | ||
| disableCruxMessenger: true, | ||
| // @ts-ignore | ||
| privateKey: remoteKeyManager, | ||
| walletClientName: remoteUserId.components.domain, | ||
| }); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| // Importing packages | ||
| import Logger from "js-logger"; | ||
| import {CruxProtocolMessenger, SecureCruxNetwork} from "../../core/domain-services"; | ||
| import {CruxProtocolMessenger, RemoteKeyHost, SecureCruxNetwork} from "../../core/domain-services"; | ||
| import { | ||
| CruxDomain, | ||
| CruxSpec, | ||
|
|
@@ -26,6 +26,7 @@ import { | |
| CruxNetPubSubClientFactory, cruxPaymentProtocol, | ||
| IBlockstackCruxDomainRepositoryOptions, | ||
| IBlockstackCruxUserRepositoryOptions, | ||
| keyManagementProtocol, | ||
| } from "../../infrastructure/implementations"; | ||
| import {CruxDomainId, CruxId, getLogger, InMemStorage, StorageService} from "../../packages"; | ||
| import {Encryption} from "../../packages/encryption"; | ||
|
|
@@ -79,6 +80,7 @@ export interface ICruxWalletClientOptions { | |
| cacheStorage?: StorageService; | ||
| walletClientName: string; | ||
| debugLogging?: boolean; | ||
| disableCruxMessenger?: boolean; | ||
| } | ||
|
|
||
| export interface ICruxIDState { | ||
|
|
@@ -96,7 +98,7 @@ export const getCruxUserRepository = (options: IBlockstackCruxUserRepositoryOpti | |
|
|
||
| export const getPubsubClientFactory = (): IPubSubClientFactory => { | ||
| return new CruxNetPubSubClientFactory({defaultLinkServer: { | ||
| host: "broker.hivemq.com", | ||
| host: "127.0.0.1", | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't change this in code. In code we should have a globally accessible server.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shall we put it in config??
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should ideally do it in the same way we've done it for Blockstack user repository. It also requires such a default for Blockstack stuff. Look at line 127 of crux-wallet-client.ts
Defaults are defined in |
||
| path: "/mqtt", | ||
| port: 8000, | ||
| }}); | ||
|
|
@@ -107,6 +109,7 @@ export class CruxWalletClient { | |
| public walletClientName: string; | ||
| // TODO: make private | ||
| public paymentProtocolMessenger?: CruxProtocolMessenger; | ||
| public keyManagerProtocolMessenger?: CruxProtocolMessenger; | ||
| public secureCruxNetwork?: SecureCruxNetwork; | ||
| private cruxBlockstackInfrastructure: ICruxBlockstackInfrastructure; | ||
| private initPromise: Promise<void>; | ||
|
|
@@ -119,6 +122,7 @@ export class CruxWalletClient { | |
| private resolvedClientAssetMapping?: IResolvedClientAssetMap; | ||
| private cacheStorage?: StorageService; | ||
| private selfCruxUser?: CruxUser; | ||
| private remoteKeyHost?: RemoteKeyHost; | ||
|
|
||
| constructor(options: ICruxWalletClientOptions) { | ||
| getLogger(cruxWalletClientDebugLoggerName).setLevel(options.debugLogging ? Logger.DEBUG : Logger.OFF); | ||
|
|
@@ -136,7 +140,7 @@ export class CruxWalletClient { | |
| } | ||
| this.cruxDomainRepo = getCruxDomainRepository({cacheStorage: this.cacheStorage, blockstackInfrastructure: this.cruxBlockstackInfrastructure}); | ||
| this.cruxDomainId = new CruxDomainId(this.walletClientName); | ||
| this.initPromise = this.asyncInit(); | ||
| this.initPromise = this.asyncInit(options); | ||
| } | ||
|
|
||
| @throwCruxClientError | ||
|
|
@@ -423,7 +427,7 @@ export class CruxWalletClient { | |
| return this.cruxDomain; | ||
| } | ||
|
|
||
| private asyncInit = async (): Promise<void> => { | ||
| private asyncInit = async (options: ICruxWalletClientOptions): Promise<void> => { | ||
| this.cruxDomain = await this.cruxDomainRepo.get(this.cruxDomainId); | ||
| if (!this.cruxDomain) { | ||
| throw ErrorHelper.getPackageError(null, PackageErrorCode.InvalidWalletClientName); | ||
|
|
@@ -433,9 +437,16 @@ export class CruxWalletClient { | |
| throw ErrorHelper.getPackageError(null, PackageErrorCode.CouldNotFindBlockstackConfigurationServiceClientConfig); | ||
| } | ||
| this.cruxAssetTranslator = new CruxAssetTranslator(this.cruxDomain.config.assetMapping, this.cruxDomain.config.assetList); | ||
| if (options.disableCruxMessenger) { | ||
| return; | ||
| } | ||
| const selfIdClaim = await this.getSelfClaim(); | ||
| if (selfIdClaim) { | ||
| await this.setupCruxMessenger(selfIdClaim); | ||
| try { | ||
| await this.setupCruxMessenger(selfIdClaim); | ||
| } catch (err) { | ||
| console.log(err); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the purpose of this? Remove if it was for your personal debugging only.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. actually it was for catching errors from setupCruxMessenger but now we can remove it(options are being used till here only)
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 'catching error' is not a valid purpose. 'catching error to _________' is a valid purpose
Here you've suppressed it and logged it. Any particular cases/errors you're trying to catch here? If this function is too failure prone then it may block other functionalities of SDK. So then it may be a good idea to suppress error here like youve done |
||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -461,8 +472,12 @@ export class CruxWalletClient { | |
| } | ||
| const pubsubClientFactory = getPubsubClientFactory(); | ||
| this.secureCruxNetwork = new SecureCruxNetwork(this.cruxUserRepository, pubsubClientFactory, selfIdClaim); | ||
| await this.secureCruxNetwork.initialize(); | ||
| this.paymentProtocolMessenger = new CruxProtocolMessenger(this.secureCruxNetwork, cruxPaymentProtocol); | ||
| this.keyManagerProtocolMessenger = new CruxProtocolMessenger(this.secureCruxNetwork, keyManagementProtocol); | ||
| await this.keyManagerProtocolMessenger.initialize(); | ||
| const remoteKeyHost = new RemoteKeyHost(this.keyManagerProtocolMessenger, this.keyManager!); | ||
| this.remoteKeyHost = remoteKeyHost; | ||
| await this.remoteKeyHost.initialize(); | ||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| export * from "./crux-explorer-client"; | ||
| export * from "./crux-wallet-client"; | ||
| export * from "./crux-wallet-onboarding"; | ||
| export * from "./crux-service-client"; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,2 @@ | ||
| export * from "./crux-messenger"; | ||
| export * from "./remote-key-service"; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,153 @@ | ||
| import {makeUUID4} from "blockstack/lib"; | ||
| import { createNanoEvents, DefaultEvents, Emitter } from "nanoevents"; | ||
| import { CruxId } from "../../packages"; | ||
| import { IKeyManager } from "../interfaces"; | ||
| import { CruxProtocolMessenger, SecureCruxNetwork } from "./crux-messenger"; | ||
|
|
||
| const VALID_METHODS = ["signWebToken", "getPubKey", "deriveSharedSecret", "decryptMessage"]; | ||
|
|
||
| export class RemoteKeyClient { | ||
| private cruxProtocolMessenger: CruxProtocolMessenger; | ||
| private remoteUserId: CruxId; | ||
| private emitter: Emitter<DefaultEvents>; | ||
|
|
||
| constructor(cruxProtocolMessenger: CruxProtocolMessenger, remoteUserId: CruxId) { | ||
| this.cruxProtocolMessenger = cruxProtocolMessenger; | ||
| this.remoteUserId = remoteUserId; | ||
| this.emitter = createNanoEvents(); | ||
| } | ||
|
|
||
| public async initialize() { | ||
| this.cruxProtocolMessenger.on("KEY_MANAGER_RESPONSE", async (msg: any, senderId: CruxId | undefined) => { | ||
| console.log("Inside RemoteKeyClient::initialize::Msg, senderId: ", msg, senderId); | ||
| this.emitter.emit(msg.invocationId, msg, senderId); | ||
| }); | ||
| } | ||
|
|
||
| public async invoke(method: string, args: any[]) { | ||
| console.log("RemoteKeyClient::Inside Invoke"); | ||
| if (!this.cruxProtocolMessenger) { | ||
| throw Error("RemoteKeyClient cannot send with no secureCruxNetwork"); | ||
| } | ||
| const methodData = this.generateMethodData(method, args); | ||
| console.log("RemoteKeyClient::Inside Invoke, RemoteUserId, MethodData", this.remoteUserId, methodData); | ||
| // @ts-ignore | ||
| await this.cruxProtocolMessenger.send({ | ||
| content: methodData, | ||
| type: "KEY_MANAGER_REQUEST", | ||
| }, this.remoteUserId); | ||
| return methodData.invocationId; | ||
| } | ||
|
|
||
| public listenToInvocation = (invocationId: string, resultCallback: (msg: any, senderId: CruxId | undefined) => any, errorCallback: (err: any) => any): void => { | ||
| if (!this.cruxProtocolMessenger) { | ||
| throw Error("RemoteKeyClient cannot listen with no secureCruxNetwork"); | ||
| } | ||
| console.log("RemoteKeyClient::ListenToInvocation::invocationId", invocationId); | ||
| this.emitter.on(invocationId, resultCallback); | ||
| this.emitter.on("error", errorCallback); | ||
| } | ||
|
|
||
| private generateMethodData(method: string, args: any[]) { | ||
| return { | ||
| args, | ||
| invocationId: makeUUID4(), | ||
| method, | ||
| }; | ||
| } | ||
| } | ||
|
|
||
| export class RemoteKeyHost { | ||
| private cruxProtocolMessenger: CruxProtocolMessenger; | ||
| private keyManager: IKeyManager; | ||
|
|
||
| constructor(cruxProtocolMessenger: CruxProtocolMessenger, keyManager: IKeyManager) { | ||
| this.keyManager = keyManager; | ||
| this.cruxProtocolMessenger = cruxProtocolMessenger; | ||
| } | ||
|
|
||
| public async initialize() { | ||
| this.cruxProtocolMessenger.on("KEY_MANAGER_REQUEST", async (msg: any, senderId: CruxId | undefined) => { | ||
| console.log("Inside RemoteKeyHost::in::Msg, senderId: ", msg, senderId); | ||
| const data = await this.handleMessage(msg); | ||
| console.log("Inside RemoteKeyHost::initialize::Data(handleMessage): ", data); | ||
| // @ts-ignore | ||
| await this.sendInvocationResult(data, CruxId.fromString(senderId!)); // getting senderId as string | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ID should be coming as object here. If it isn't then it's a bug! Can you fix it?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah seems so. will check it again and fix it. And yes SecureRecieveSocket will be best as it will make sure that it's consistent throughout (CruxID) |
||
| }); | ||
| } | ||
| private async sendInvocationResult(result: any, receiverId: CruxId) { | ||
| if (!this.cruxProtocolMessenger) { | ||
| throw Error("RemoteKeyClient cannot send with no selfMessenger"); | ||
| } | ||
| const resultData = this.generateInvocationResponse(result); | ||
| console.log("RemoteKeyHost::Inside sendInvocationResult::resultData: ", resultData); | ||
| await this.cruxProtocolMessenger.send({ | ||
| content: resultData, | ||
| type: "KEY_MANAGER_RESPONSE", | ||
| }, receiverId); | ||
| } | ||
|
|
||
| private async handleMessage(message: any) { | ||
| if (!this.keyManager) { | ||
| throw new Error("Key Manager not available"); | ||
| } | ||
| let data; | ||
| // @ts-ignore | ||
| data = await this.keyManager[message.method](message.args[0]); | ||
| return { | ||
| data, | ||
| invocationId: message.invocationId, | ||
| }; | ||
| } | ||
|
|
||
| private generateInvocationResponse(result: any) { | ||
| return { | ||
| invocationId: result.invocationId, | ||
| result, | ||
| }; | ||
| } | ||
| } | ||
|
|
||
| export class RemoteKeyManager implements IKeyManager { | ||
| private remoteKeyClient: RemoteKeyClient; | ||
| private remoteUserId: CruxId; | ||
|
|
||
| constructor(cruxProtocolMessenger: CruxProtocolMessenger, remoteUserId: CruxId) { | ||
| this.remoteKeyClient = new RemoteKeyClient(cruxProtocolMessenger, remoteUserId); | ||
| this.remoteUserId = remoteUserId; | ||
| } | ||
|
|
||
| public async initialize() { | ||
| await this.remoteKeyClient.initialize(); | ||
| } | ||
| // @ts-ignore | ||
| public signWebToken = async (args: any) => { | ||
| return this.makeRemoteMessageCall("signWebToken", [args]); | ||
| } | ||
| // @ts-ignore | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove ts ignore and fix errors. Let me know if you're getting confused with 'args' and how to make it generic for arguments. |
||
| public getPubKey = async () => { | ||
| return this.makeRemoteMessageCall("getPubKey"); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can do an optimization here - |
||
| } | ||
| // @ts-ignore | ||
| public deriveSharedSecret = async (args: string) => { | ||
| return this.makeRemoteMessageCall("deriveSharedSecret", [args]); | ||
| } | ||
| // @ts-ignore | ||
| public decryptMessage = async (args: string) => { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wrong naming of parameter in all methods - look at other KeyManager implementation.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry will take care of it |
||
| return this.makeRemoteMessageCall("decryptMessage", [args]); | ||
| } | ||
|
|
||
| private makeRemoteMessageCall = async (method: string, args: any = []) => { | ||
| console.log("makeRemoteMessageCall::", method, args); | ||
| const invocationId = await this.remoteKeyClient.invoke(method, args); | ||
| console.log("RemoteKeyManager::makeRemoteMessageCall::invokationId: ", invocationId); | ||
| return new Promise(async (resolve, reject) => { | ||
| this.remoteKeyClient.listenToInvocation(invocationId, (msg, senderId) => { | ||
| console.log("RemoteKeyManager::deriveSharedSecret::msg: ", msg); | ||
| resolve(msg.result.data); | ||
| }, (err) => { | ||
| reject(err); | ||
| }); | ||
| }); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,3 @@ | ||
| export * from "./entities"; | ||
| export * from "./interfaces"; | ||
| export * from "./domain-services"; |
Uh oh!
There was an error while loading. Please reload this page.