Skip to content

Commit

Permalink
feat(core-api): 🎸 add IKeychainPlugin#getKeychainId()
Browse files Browse the repository at this point in the history
New method on the generic interface for keychain plugins that enables
the handling of multiple different keychain backends on the same API
server.

This is useful if you want to have different instances of keychain
plugins deployed because for example your consortium member operates
multiple keychain backends such as one provided by the cloud provider
of their choice and another one that could be a self-hosted, open
source software deployment.
Cactus aims not to limit the deployment architecture where possible
and this feature is aimed at maintaining that design principle.

The idea is that API requests can specify which keychain they want
to use when looking up the signing key for a transaction.
The implementation that serves the request then reaches to the
PluginRegistry and retrieves a list of keychain plugins, then
proceeds to filter that list down to just the one instance based
on the keychain ID that has to match up to what was specified in
the API request being served.

Signed-off-by: Peter Somogyvari <peter.somogyvari@accenture.com>
  • Loading branch information
petermetz committed Dec 1, 2020
1 parent 590a299 commit 34656b0
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
import { IPluginKVStorage } from "../storage/key-value/i-plugin-kv-storage";

/**
* Common interface to be implemented by classes that act as plugins behind
* keychains.
*/
export interface IPluginKeychain extends IPluginKVStorage {
rotateEncryptionKeys(): Promise<void>;
getEncryptionAlgorithm(): string;
/**
* Returns the unique identifier of the keychain pointed to (or backed) by
* this `IPluginKeychain` instance.
* This therefore does not uniqely identify the plugin instance itself, but
* its backend instead.
* Useful for being able to reference keychains by their IDs in deployment
* scenarios when there are multiple keychain backends for different sets of
* secrets.
*/
getKeychainId(): string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@ import { v4 as uuidv4 } from "uuid";

import { PluginFactory } from "@hyperledger/cactus-core-api";
import {
IPluginKeychainOptions,
IPluginKeychainMemoryOptions,
PluginKeychainMemory,
} from "./plugin-keychain-memory";

export class PluginFactoryKeychain extends PluginFactory<
PluginKeychainMemory,
IPluginKeychainOptions
IPluginKeychainMemoryOptions
> {
async create(
options: IPluginKeychainOptions = {
options: IPluginKeychainMemoryOptions = {
backend: new Map(),
instanceId: uuidv4(),
keychainId: uuidv4(),
logLevel: "TRACE",
}
): Promise<PluginKeychainMemory> {
return new PluginKeychainMemory(options);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,62 @@
import {
ICactusPlugin,
Logger,
Checks,
LogLevelDesc,
LoggerProvider,
} from "@hyperledger/cactus-common";
import {
ICactusPluginOptions,
IPluginKeychain,
PluginAspect,
} from "@hyperledger/cactus-core-api";

import { Checks } from "@hyperledger/cactus-common";

export interface IPluginKeychainOptions extends ICactusPluginOptions {
backend: Map<string, any>;
export interface IPluginKeychainMemoryOptions extends ICactusPluginOptions {
logLevel?: LogLevelDesc;
backend?: Map<string, any>;
keychainId: string;
}

export class PluginKeychainMemory implements ICactusPlugin, IPluginKeychain {
export class PluginKeychainMemory {
public static readonly CLASS_NAME = "PluginKeychainMemory";

private readonly backend: Map<string, any>;
private readonly log: Logger;
private readonly instanceId: string;

constructor(public readonly options: IPluginKeychainOptions) {
const fnTag = `PluginKeychainMemory#constructor()`;
if (!options) {
throw new Error(`${fnTag} options falsy.`);
}
Checks.truthy(options.instanceId, `${fnTag} options.instanceId`);
if (!options.backend) {
options.backend = new Map();
}
this.instanceId = this.options.instanceId;
public get className() {
return PluginKeychainMemory.CLASS_NAME;
}

constructor(public readonly opts: IPluginKeychainMemoryOptions) {
const fnTag = `${this.className}#constructor()`;
Checks.truthy(opts, `${fnTag} arg options`);
Checks.truthy(opts.keychainId, `${fnTag} arg options.keychainId`);
Checks.truthy(opts.instanceId, `${fnTag} options.instanceId`);
Checks.nonBlankString(opts.keychainId, `${fnTag} options.keychainId`);

this.backend = opts.backend || new Map();
Checks.truthy(this.backend, `${fnTag} arg options.backend`);

const level = this.opts.logLevel || "INFO";
const label = this.className;
this.log = LoggerProvider.getOrCreate({ level, label });

this.instanceId = this.opts.instanceId;

this.log.info(`Created ${this.className}. KeychainID=${opts.keychainId}`);
this.log.warn(
`Never use ${this.className} in production. ` +
`It does not support encryption. It stores everything in plain text.`
);
}

public getInstanceId(): string {
return this.instanceId;
}

public getKeychainId(): string {
return this.opts.keychainId;
}

public getPackageName(): string {
return `@hyperledger/cactus-plugin-keychain-memory`;
}
Expand All @@ -47,18 +74,18 @@ export class PluginKeychainMemory implements ICactusPlugin, IPluginKeychain {
}

async get<T>(key: string): Promise<T> {
return this.options.backend.get(key);
return this.backend.get(key);
}

async has(key: string): Promise<boolean> {
return this.options.backend.has(key);
return this.backend.has(key);
}

async set<T>(key: string, value: T): Promise<void> {
this.options.backend.set(key, value);
this.backend.set(key, value);
}

async delete<T>(key: string): Promise<void> {
this.options.backend.delete(key);
this.backend.delete(key);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
export { PluginKeychainMemory } from "./plugin-keychain-memory";
export {
PluginKeychainMemory,
IPluginKeychainMemoryOptions,
} from "./plugin-keychain-memory";
export { PluginFactoryKeychain } from "./plugin-factory-keychain";

import { PluginFactoryKeychain } from "./plugin-factory-keychain";
Expand Down

0 comments on commit 34656b0

Please sign in to comment.