Skip to content

Commit

Permalink
WIP [ci skip]
Browse files Browse the repository at this point in the history
  • Loading branch information
CMCDragonkai committed Oct 21, 2023
1 parent d59d270 commit abaeb82
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 83 deletions.
2 changes: 1 addition & 1 deletion src/PolykeyClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ class PolykeyClient {
this.logger.info(`Stopped ${this.constructor.name}`);
}

public async destroy({ force = true }: { force?: boolean }) {
public async destroy({ force = false }: { force?: boolean }) {
this.logger.info(`Destroying ${this.constructor.name}`);
await this.webSocketClient.destroy({ force });
await this.session.destroy();
Expand Down
221 changes: 139 additions & 82 deletions tests/PolykeyClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ import type { SessionToken } from '@/sessions/types';
import os from 'os';
import path from 'path';
import fs from 'fs';
import net from 'net';
import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
import { utils as webSocketUtils } from '@matrixai/ws';
import {
utils as webSocketUtils,
errors as webSocketErrors,
} from '@matrixai/ws';
import PolykeyAgent from '@/PolykeyAgent';
import PolykeyClient from '@/PolykeyClient';
import Session from '@/sessions/Session';
Expand All @@ -23,104 +27,157 @@ describe(PolykeyClient.name, () => {
const nodeIdGenerator = ids.createNodeIdGenerator();
let dataDir: string;
let nodePath: string;
let pkAgent: PolykeyAgent;
beforeEach(async () => {
dataDir = await fs.promises.mkdtemp(
path.join(os.tmpdir(), 'polykey-test-'),
);
nodePath = path.join(dataDir, 'polykey');
pkAgent = await PolykeyAgent.createPolykeyAgent({
password,
options: {
nodePath,
agentServiceHost: localHost,
clientServiceHost: localHost,
keys: {
passwordOpsLimit: keysUtils.passwordOpsLimits.min,
passwordMemLimit: keysUtils.passwordMemLimits.min,
strictMemoryLock: false,
},
},
logger: logger.getChild(PolykeyAgent.name),
});
});
afterEach(async () => {
await pkAgent.stop();
await fs.promises.rm(dataDir, {
force: true,
recursive: true,
});
});
test('preserving and destroying session state', async () => {
const session = await Session.createSession({
sessionTokenPath: path.join(nodePath, config.paths.tokenBase),
fs,
logger,
test('connect to the nothing', async () => {
await expect(
PolykeyClient.createPolykeyClient({
nodeId: nodeIdGenerator(),
host: '127.0.0.1',
port: 1,
options: {
nodePath: nodePath,
},
fs,
logger: logger.getChild(PolykeyClient.name),
fresh: true,
}),
).rejects.toThrow(webSocketErrors.ErrorWebSocketConnectionLocal);
});
test('connect timeout', async () => {
const sockets: Array<net.Socket> = [];
const server = net.createServer((socket) => {
sockets.push(socket);
});
await session.writeToken('dummy' as SessionToken);
const pkClient = await PolykeyClient.createPolykeyClient({
nodeId: nodeIdGenerator(),
host: pkAgent.clientServiceHost,
port: pkAgent.clientServicePort,
options: {
nodePath,
},
fs,
logger: logger.getChild(PolykeyClient.name),
// Using fresh: true means that any token would be destroyed
fresh: true,
await new Promise<void>((resolve) => {
server.listen(0, () => {
resolve();
});
});
expect(await session.readToken()).toBeUndefined();
await session.writeToken('abc' as SessionToken);
await pkClient.stop();
expect(await session.readToken()).toBeDefined();
await pkClient.destroy({ force: true });
expect(await session.readToken()).toBeUndefined();
const serverPort = (server.address() as net.AddressInfo).port;
await expect(
PolykeyClient.createPolykeyClient(
{
nodeId: nodeIdGenerator(),
host: '127.0.0.1',
port: serverPort,
options: {
nodePath: nodePath,
},
fs,
logger: logger.getChild(PolykeyClient.name),
fresh: true,
},
{ timer: 1000 },
),
).rejects.toThrow(errors.ErrorPolykeyClientCreateTimeout);
server.close();
for (const socket of sockets) {
socket.destroy();
}
});
test('connect to agent client service', async () => {
const pkClient = await PolykeyClient.createPolykeyClient({
nodeId: pkAgent.keyRing.getNodeId(),
port: pkAgent.clientServicePort,
host: pkAgent.clientServiceHost,
options: {
nodePath: nodePath,
},
fs,
logger: logger.getChild(PolykeyClient.name),
fresh: true,
describe('with polykey agent', () => {
let pkAgent: PolykeyAgent;
beforeEach(async () => {
pkAgent = await PolykeyAgent.createPolykeyAgent({
password,
options: {
nodePath,
agentServiceHost: localHost,
clientServiceHost: localHost,
keys: {
passwordOpsLimit: keysUtils.passwordOpsLimits.min,
passwordMemLimit: keysUtils.passwordMemLimits.min,
strictMemoryLock: false,
},
},
logger: logger.getChild(PolykeyAgent.name),
});
});
expect(pkClient.host).toBe(pkAgent.clientServiceHost);
expect(pkClient.port).toBe(pkAgent.clientServicePort);
const connectionMeta = pkClient.webSocketClient.connection.meta();
expect(connectionMeta.remoteCertsChain).toHaveLength(1);
const remoteCert = connectionMeta.remoteCertsChain[0];
const remoteCertPem = webSocketUtils.derToPEM(remoteCert);
const agentCertPem = await pkAgent.certManager.getCurrentCertPEM();
expect(remoteCertPem).toEqual(agentCertPem);
await pkClient.stop();
});
test('authenticated RPC request to agent client service', async () => {
const pkClient = await PolykeyClient.createPolykeyClient({
nodeId: pkAgent.keyRing.getNodeId(),
port: pkAgent.clientServicePort,
host: pkAgent.clientServiceHost,
options: {
nodePath: nodePath,
},
fs,
logger: logger.getChild(PolykeyClient.name),
fresh: true,
afterEach(async () => {
await pkAgent.stop();
});
const callP = pkClient.rpcClient.methods.agentStatus({});
// Authentication error
await expect(callP).rejects.toThrow(errors.ErrorPolykeyRemote);
await testUtils.expectRemoteError(callP, errors.ErrorClientAuthMissing);
// Correct auth runs without error
await pkClient.rpcClient.methods.agentStatus({
metadata: {
authorization: clientUtils.encodeAuthFromPassword(password),
},
test('preserving and destroying session state', async () => {
const session = await Session.createSession({
sessionTokenPath: path.join(nodePath, config.paths.tokenBase),
fs,
logger,
});
await session.writeToken('dummy' as SessionToken);
const pkClient = await PolykeyClient.createPolykeyClient({
nodeId: pkAgent.keyRing.getNodeId(),
host: pkAgent.clientServiceHost,
port: pkAgent.clientServicePort,
options: {
nodePath,
},
fs,
logger: logger.getChild(PolykeyClient.name),
// Using fresh: true means that any token would be destroyed
fresh: true,
});
expect(await session.readToken()).toBeUndefined();
await session.writeToken('abc' as SessionToken);
await pkClient.stop();
expect(await session.readToken()).toBeDefined();
await pkClient.destroy({ force: true });
expect(await session.readToken()).toBeUndefined();
});
test('connect to agent client service', async () => {
const pkClient = await PolykeyClient.createPolykeyClient({
nodeId: pkAgent.keyRing.getNodeId(),
port: pkAgent.clientServicePort,
host: pkAgent.clientServiceHost,
options: {
nodePath: nodePath,
},
fs,
logger: logger.getChild(PolykeyClient.name),
fresh: true,
});
expect(pkClient.host).toBe(pkAgent.clientServiceHost);
expect(pkClient.port).toBe(pkAgent.clientServicePort);
const connectionMeta = pkClient.webSocketClient.connection.meta();
expect(connectionMeta.remoteCertsChain).toHaveLength(1);
const remoteCert = connectionMeta.remoteCertsChain[0];
const remoteCertPem = webSocketUtils.derToPEM(remoteCert);
const agentCertPem = await pkAgent.certManager.getCurrentCertPEM();
expect(remoteCertPem).toEqual(agentCertPem);
await pkClient.stop();
});
test('authenticated RPC request to agent client service', async () => {
const pkClient = await PolykeyClient.createPolykeyClient({
nodeId: pkAgent.keyRing.getNodeId(),
port: pkAgent.clientServicePort,
host: pkAgent.clientServiceHost,
options: {
nodePath: nodePath,
},
fs,
logger: logger.getChild(PolykeyClient.name),
fresh: true,
});
const callP = pkClient.rpcClient.methods.agentStatus({});
// Authentication error
await expect(callP).rejects.toThrow(errors.ErrorPolykeyRemote);
await testUtils.expectRemoteError(callP, errors.ErrorClientAuthMissing);
// Correct auth runs without error
await pkClient.rpcClient.methods.agentStatus({
metadata: {
authorization: clientUtils.encodeAuthFromPassword(password),
},
});
await pkClient.stop();
});
await pkClient.stop();
});
});

0 comments on commit abaeb82

Please sign in to comment.