Skip to content

Commit

Permalink
feat: keypairs controller
Browse files Browse the repository at this point in the history
  • Loading branch information
mohamed-Dhia committed Dec 19, 2024
1 parent a61bd4a commit f63341c
Show file tree
Hide file tree
Showing 7 changed files with 297 additions and 49 deletions.
27 changes: 27 additions & 0 deletions src/controllers/identity-controllers/keypairs-controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { EdcConnectorClientContext } from "../../context";
import { KeyPair } from "../../entities/keypairs";
import { Inner } from "../../inner";

export class KeyPairsController {
#inner: Inner;
#context?: EdcConnectorClientContext;

constructor(inner: Inner, context?: EdcConnectorClientContext) {
this.#inner = inner;
this.#context = context;
}

async queryAll(
query: { offset?: string; limit?: string } = {},
context?: EdcConnectorClientContext,
) {
const actualContext = context || this.#context!;

return this.#inner.request<KeyPair[]>(actualContext.identity, {
path: "/v1alpha/keypairs",
method: "GET",
apiToken: actualContext.apiToken,
query,
});
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { EdcConnectorClientContext } from "../../context";
import { EdcConnectorClientContext } from "../../../context";
import {
ParticipantInput,
ParticipantRoleResponse,
} from "../../entities/participant";
import { Inner } from "../../inner";
} from "../../../entities/participant";
import { Inner } from "../../../inner";
import { ParticipantKeyPairContoller } from "./participant-keypairs-controller";

export class ParticipantController {
#inner: Inner;
Expand Down Expand Up @@ -82,4 +83,12 @@ export class ParticipantController {
apiToken: actualContext.apiToken,
});
}

get keypairs() {
return new ParticipantKeyPairContoller(
this.#inner,
this.participantId,
this.#context,
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { EdcConnectorClientContext } from "../../../context";
import { KeyDescriptor, KeyPair } from "../../../entities/keypairs";
import { Inner } from "../../../inner";

export class ParticipantKeyPairContoller {
#inner: Inner;
#context?: EdcConnectorClientContext;

constructor(
inner: Inner,
public participantId: string,
context?: EdcConnectorClientContext,
) {
this.#inner = inner;
this.#context = context;
}

getKeyPair(keyPairId: string, context?: EdcConnectorClientContext) {
const actualContext = context || this.#context!;

return this.#inner.request<KeyPair>(actualContext.identity, {
path: `/v1alpha/participants/${this.participantId}/keypairs/${keyPairId}`,
method: "GET",
apiToken: actualContext.apiToken,
});
}

queryAllKeyPairs(context?: EdcConnectorClientContext) {
const actualContext = context || this.#context!;

return this.#inner.request<KeyPair[]>(actualContext.identity, {
path: `/v1alpha/participants/${this.participantId}/keypairs`,
method: "GET",
apiToken: actualContext.apiToken,
});
}

createKeyPair(
keyDescriptor: KeyDescriptor,
makeDefault = false,
context?: EdcConnectorClientContext,
) {
const actualContext = context || this.#context!;

return this.#inner.request<void>(actualContext.identity, {
path: `/v1alpha/participants/${this.participantId}/keypairs`,
method: "PUT",
body: keyDescriptor,
query: {
makeDefault: String(makeDefault),
},
apiToken: actualContext.apiToken,
});
}

activate(keyPairId: string, context?: EdcConnectorClientContext) {
const actualContext = context || this.#context!;

return this.#inner.request<void>(actualContext.identity, {
path: `/v1alpha/participants/${this.participantId}/keypairs/${keyPairId}/activate`,
method: "POST",
apiToken: actualContext.apiToken,
});
}

revoke(
keyPairId: string,
newKeyDescriptor: KeyDescriptor,
context?: EdcConnectorClientContext,
) {
const actualContext = context || this.#context!;

return this.#inner.request<void>(actualContext.identity, {
path: `/v1alpha/participants/${this.participantId}/keypairs/${keyPairId}/revoke`,
method: "POST",
body: newKeyDescriptor,
apiToken: actualContext.apiToken,
});
}

rotate(
keyPairId: string,
duration?: number,
newKeyDescriptor?: KeyDescriptor,
context?: EdcConnectorClientContext,
) {
const actualContext = context || this.#context!;

return this.#inner.request<void>(actualContext.identity, {
path: `/v1alpha/participants/${this.participantId}/keypairs/${keyPairId}/rotate`,
method: "POST",
body: newKeyDescriptor,
query: {
duration: String(duration),
},
apiToken: actualContext.apiToken,
});
}
}
29 changes: 29 additions & 0 deletions src/entities/keypairs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export interface KeyPair {
defaultPair: boolean;
groupName: string;
id: string;
keyContext: string;
keyId: string;
participantId: string;
privateKeyAlias: string;
rotationDuration: number;
serializedPublicKey: string;
state: number;
timestamp: number;
useDuration: number;
}

export interface KeyDescriptor {
active: boolean;
keyGeneratorParams: {
[key: string]: unknown;
};
keyId: string;
privateKeyAlias: string;
publicKeyJwk: {
[key: string]: unknown;
};
publicKeyPem: string;
resourceId: string;
type: string;
}
7 changes: 6 additions & 1 deletion src/facades/identity.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ParticipantController } from "../controllers/identity-controllers/participant-controller";
import { KeyPairsController } from "../controllers/identity-controllers/keypairs-controller";
import { ParticipantController } from "../controllers/identity-controllers/participant-controllers/participant-controller";
import { ParticipantsController } from "../controllers/identity-controllers/participants-controller";
import { EdcController } from "../edc-controller";

Expand All @@ -11,4 +12,8 @@ export class IdentityController extends EdcController {
return (participantId: string) =>
new ParticipantController(this.inner, participantId, this.context);
}

get keyPairs() {
return new KeyPairsController(this.inner, this.context);
}
}
122 changes: 122 additions & 0 deletions tests/controllers/identity-tests/keypairs.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { GenericContainer, StartedTestContainer } from "testcontainers";
import { EdcConnectorClient } from "../../../src";
import { KeyPairsController } from "../../../src/controllers/identity-controllers/keypairs-controller";
import { ParticipantKeyPairContoller } from "../../../src/controllers/identity-controllers/participant-controllers/participant-keypairs-controller";
import { KeyDescriptor } from "../../../src/entities/keypairs";

describe("Key Pairs", () => {
let startedContainer: StartedTestContainer;
let participantKeyPairs: ParticipantKeyPairContoller;
let keyPairs: KeyPairsController;

beforeAll(async () => {
startedContainer = await new GenericContainer("stoplight/prism:5.8.1")
.withCopyFilesToContainer([
{
source: "node_modules/identity-api.yml",
target: "/identity-api.yml",
},
])
.withCommand(["mock", "-h", "0.0.0.0", "/identity-api.yml"])
.withExposedPorts(4010)
.start();

keyPairs = new EdcConnectorClient.Builder()
.identityUrl("http://localhost:" + startedContainer.getFirstMappedPort())
.build().identity.keyPairs;

participantKeyPairs = new EdcConnectorClient.Builder()
.identityUrl("http://localhost:" + startedContainer.getFirstMappedPort())
.build()
.identity.participant("1").keypairs;
});

afterAll(async () => {
await startedContainer.stop();
});

it("should query all key pairs", async () => {
const keyPairs = await participantKeyPairs.queryAllKeyPairs();

expect(keyPairs).not.toBeNull();
expect(keyPairs.length).toBeGreaterThan(0);
expect(keyPairs[0]).toHaveProperty("defaultPair");
expect(keyPairs[0]).toHaveProperty("groupName");
expect(keyPairs[0]).toHaveProperty("id");
expect(keyPairs[0]).toHaveProperty("keyContext");
expect(keyPairs[0]).toHaveProperty("keyId");
expect(keyPairs[0]).toHaveProperty("participantId");
expect(keyPairs[0]).toHaveProperty("privateKeyAlias");
expect(keyPairs[0]).toHaveProperty("rotationDuration");
expect(keyPairs[0]).toHaveProperty("serializedPublicKey");
expect(keyPairs[0]).toHaveProperty("state");
expect(keyPairs[0]).toHaveProperty("timestamp");
expect(keyPairs[0]).toHaveProperty("useDuration");
});

it("should get key pair", async () => {
const keyPair = await participantKeyPairs.getKeyPair("1");

expect(keyPair).not.toBeNull();
expect(keyPair).toHaveProperty("defaultPair");
expect(keyPair).toHaveProperty("groupName");
expect(keyPair).toHaveProperty("id");
expect(keyPair).toHaveProperty("keyContext");
expect(keyPair).toHaveProperty("keyId");
expect(keyPair).toHaveProperty("participantId");
expect(keyPair).toHaveProperty("privateKeyAlias");
expect(keyPair).toHaveProperty("rotationDuration");
expect(keyPair).toHaveProperty("serializedPublicKey");
expect(keyPair).toHaveProperty("state");
expect(keyPair).toHaveProperty("timestamp");
expect(keyPair).toHaveProperty("useDuration");
});

it("should create a key pair", async () => {
const newKeyDescriptor: KeyDescriptor = {
privateKeyAlias: "",
type: "",
keyId: "",
active: true,
resourceId: "",
publicKeyJwk: {},
publicKeyPem: "",
keyGeneratorParams: {},
};

expect(
participantKeyPairs.createKeyPair(newKeyDescriptor),
).resolves.not.toThrow();
});

it("should query All", () => {
const keyPairsList = keyPairs.queryAll();

expect(keyPairsList).not.toBeNull();
});

it("should activate a key pair", () => {
expect(participantKeyPairs.activate("1")).resolves.not.toThrow();
});

it("should revoke a key pair", () => {
const newKeyDescriptor: KeyDescriptor = {
privateKeyAlias: "",
type: "",
keyId: "",
active: true,
resourceId: "",
publicKeyJwk: {},
publicKeyPem: "",
keyGeneratorParams: {},
};

expect(
participantKeyPairs.revoke("1", newKeyDescriptor),
).resolves.not.toThrow();
});

it("should rotate a key pair", () => {
expect(participantKeyPairs.rotate("1")).resolves.not.toThrow();
});
});
47 changes: 2 additions & 45 deletions tests/controllers/identity-tests/participant.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { GenericContainer, StartedTestContainer } from "testcontainers";
import { EdcConnectorClient } from "../../../src";
import { ParticipantController } from "../../../src/controllers/identity-controllers/participant-controllers/participant-controller";
import { ParticipantInput } from "../../../src/entities/participant";
import { ParticipantController } from "../../../src/controllers/identity-controllers/participant-controller";

describe("Paricipant", () => {
let startedContainer: StartedTestContainer;
Expand All @@ -11,7 +11,7 @@ describe("Paricipant", () => {
startedContainer = await new GenericContainer("stoplight/prism:5.8.1")
.withCopyFilesToContainer([
{
source: "node_modules/identity-api.yml",
source: "node_modules/identity.yml",
target: "/identity-api.yml",
},
])
Expand Down Expand Up @@ -79,47 +79,4 @@ describe("Paricipant", () => {

expect(result).not.toBeNull();
});

it("should regenerate token", async () => {
const body: ParticipantInput = {
active: true,
additionalProperties: {
additionalProp1: {},
additionalProp2: {},
additionalProp3: {},
},
did: "string",
key: {
active: true,
keyGeneratorParams: {
additionalProp1: {},
additionalProp2: {},
additionalProp3: {},
},
keyId: "string",
privateKeyAlias: "string",
publicKeyJwk: {
additionalProp1: {},
additionalProp2: {},
additionalProp3: {},
},
publicKeyPem: "string",
resourceId: "string",
type: "string",
},
participantId: "string",
roles: ["string"],
serviceEndpoints: [
{
id: "string",
serviceEndpoint: "string",
type: "string",
},
],
};

const result = participant.regenerateToken(body);

expect(result).not.toBeNull();
});
});

0 comments on commit f63341c

Please sign in to comment.