Skip to content

Commit fda0963

Browse files
committed
test: added tests for AuthSignToken handler
1 parent fb874e6 commit fda0963

File tree

4 files changed

+138
-22
lines changed

4 files changed

+138
-22
lines changed

src/client/errors.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,7 @@ class ErrorClientVerificationFailed<T> extends ErrorClientService<T> {
5050
exitCode = sysexits.USAGE;
5151
}
5252

53-
class ErrorAuthentication<T> extends ErrorPolykey<T> {}
54-
55-
class ErrorAuthenticationInvalidToken<T> extends ErrorAuthentication<T> {
53+
class ErrorClientAuthenticationInvalidToken<T> extends ErrorClient<T> {
5654
static description = 'Token is invalid';
5755
exitCode = sysexits.PROTOCOL;
5856
}
@@ -69,6 +67,5 @@ export {
6967
ErrorClientServiceNotRunning,
7068
ErrorClientServiceDestroyed,
7169
ErrorClientVerificationFailed,
72-
ErrorAuthentication,
73-
ErrorAuthenticationInvalidToken,
70+
ErrorClientAuthenticationInvalidToken,
7471
};

src/client/handlers/AuthSignToken.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class AuthSignToken extends UnaryHandler<
2929
const inputToken = { payload: input.payload, signatures: input.signatures };
3030
const incomingToken = Token.fromEncoded<IdentityRequestData>(inputToken);
3131
if (!('publicKey' in incomingToken.payload)) {
32-
throw new clientErrors.ErrorAuthenticationInvalidToken(
32+
throw new clientErrors.ErrorClientAuthenticationInvalidToken(
3333
'Input token does not contain public key',
3434
);
3535
}
@@ -38,7 +38,7 @@ class AuthSignToken extends UnaryHandler<
3838
'base64url',
3939
) as PublicKey;
4040
if (!incomingToken.verifyWithPublicKey(incomingPublicKey)) {
41-
throw new clientErrors.ErrorAuthenticationInvalidToken(
41+
throw new clientErrors.ErrorClientAuthenticationInvalidToken(
4242
'Incoming token does not match its signature',
4343
);
4444
}

tests/client/handlers/auth.test.ts

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import type {
2+
IdentityRequestData,
3+
IdentityResponseData,
4+
} from '#src/client/types.js';
5+
import type { TLSConfig } from '#network/types.js';
6+
import fs from 'node:fs';
7+
import path from 'node:path';
8+
import os from 'node:os';
9+
import Logger, { formatting, LogLevel, StreamHandler } from '@matrixai/logger';
10+
import { RPCClient } from '@matrixai/rpc';
11+
import { WebSocketClient } from '@matrixai/ws';
12+
import * as testsUtils from '../../utils/index.js';
13+
import { AuthSignToken } from '#client/handlers/index.js';
14+
import { authSignToken } from '#client/callers/index.js';
15+
import KeyRing from '#keys/KeyRing.js';
16+
import Token from '#tokens/Token.js';
17+
import ClientService from '#client/ClientService.js';
18+
import * as keysUtils from '#keys/utils/index.js';
19+
import * as networkUtils from '#network/utils.js';
20+
import * as clientErrors from '#client/errors.js';
21+
22+
describe('authSignToken', () => {
23+
const logger = new Logger('authSignToken test', LogLevel.WARN, [
24+
new StreamHandler(
25+
formatting.format`${formatting.level}:${formatting.keys}:${formatting.msg}`,
26+
),
27+
]);
28+
const password = 'password';
29+
const localhost = '127.0.0.1';
30+
let dataDir: string;
31+
let keyRing: KeyRing;
32+
let tlsConfig: TLSConfig;
33+
let clientService: ClientService;
34+
let webSocketClient: WebSocketClient;
35+
let rpcClient: RPCClient<{
36+
authSignToken: typeof authSignToken;
37+
}>;
38+
39+
beforeEach(async () => {
40+
dataDir = await fs.promises.mkdtemp(
41+
path.join(os.tmpdir(), 'polykey-test-'),
42+
);
43+
const keysPath = path.join(dataDir, 'keys');
44+
keyRing = await KeyRing.createKeyRing({
45+
password,
46+
keysPath,
47+
passwordOpsLimit: keysUtils.passwordOpsLimits.min,
48+
passwordMemLimit: keysUtils.passwordMemLimits.min,
49+
strictMemoryLock: false,
50+
logger,
51+
});
52+
tlsConfig = await testsUtils.createTLSConfig(keyRing.keyPair);
53+
clientService = new ClientService({
54+
tlsConfig,
55+
logger: logger.getChild(ClientService.name),
56+
});
57+
await clientService.start({
58+
manifest: {
59+
authSignToken: new AuthSignToken({
60+
keyRing,
61+
}),
62+
},
63+
host: localhost,
64+
});
65+
webSocketClient = await WebSocketClient.createWebSocketClient({
66+
config: {
67+
verifyPeer: false,
68+
},
69+
host: localhost,
70+
logger: logger.getChild(WebSocketClient.name),
71+
port: clientService.port,
72+
});
73+
rpcClient = new RPCClient({
74+
manifest: {
75+
authSignToken,
76+
},
77+
streamFactory: () => webSocketClient.connection.newStream(),
78+
toError: networkUtils.toError,
79+
logger: logger.getChild(RPCClient.name),
80+
});
81+
});
82+
83+
afterEach(async () => {
84+
await keyRing.stop();
85+
await clientService.stop({ force: true });
86+
await webSocketClient.destroy({ force: true });
87+
await keyRing.stop();
88+
await fs.promises.rm(dataDir, {
89+
force: true,
90+
recursive: true,
91+
});
92+
});
93+
94+
test('should sign a valid token', async () => {
95+
// Create token with separate key pair
96+
const keyPair = keysUtils.generateKeyPair();
97+
const token = Token.fromPayload<IdentityRequestData>({
98+
publicKey: keyPair.publicKey.toString('base64url'),
99+
returnURL: 'test',
100+
});
101+
token.signWithPrivateKey(keyPair);
102+
103+
// Get the node to sign the token as well
104+
const encodedToken = token.toEncoded();
105+
const identityToken = await rpcClient.methods.authSignToken(encodedToken);
106+
107+
// Check the signature of both the incoming token and the original sent token
108+
const decodedToken = Token.fromEncoded<IdentityResponseData>(identityToken);
109+
const decodedPublicKey = keysUtils.publicKeyFromNodeId(keyRing.getNodeId());
110+
expect(decodedToken.verifyWithPublicKey(decodedPublicKey)).toBeTrue();
111+
const requestToken = Token.fromEncoded<IdentityRequestData>(
112+
decodedToken.payload.requestToken,
113+
);
114+
expect(requestToken.verifyWithPublicKey(keyPair.publicKey)).toBeTrue();
115+
});
116+
117+
test('should fail if public key does not match signature', async () => {
118+
// Create token with a key pair and sign it with another
119+
const keyPair1 = keysUtils.generateKeyPair();
120+
const keyPair2 = keysUtils.generateKeyPair();
121+
const token = Token.fromPayload<IdentityRequestData>({
122+
publicKey: keyPair1.publicKey.toString('base64url'),
123+
returnURL: 'test',
124+
});
125+
token.signWithPrivateKey(keyPair2);
126+
127+
// The token should fail validation
128+
const encodedToken = token.toEncoded();
129+
await testsUtils.expectRemoteError(
130+
rpcClient.methods.authSignToken(encodedToken),
131+
clientErrors.ErrorClientAuthenticationInvalidToken,
132+
);
133+
});
134+
});

tests/client/handlers/vaults.test.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,7 @@ describe('vaultsClone', () => {
9494
let dataDir: string;
9595
let db: DB;
9696
let keyRing: KeyRing;
97-
let webSocketClient: WebSocketClient;
98-
let clientService: ClientService;
9997
let vaultManager: VaultManager;
100-
let taskManager: TaskManager;
10198
beforeEach(async () => {
10299
dataDir = await fs.promises.mkdtemp(
103100
path.join(os.tmpdir(), 'polykey-test-'),
@@ -130,11 +127,7 @@ describe('vaultsClone', () => {
130127
});
131128
});
132129
afterEach(async () => {
133-
await clientService?.stop({ force: true });
134-
await webSocketClient.destroy({ force: true });
135130
await vaultManager.stop();
136-
await taskManager.stopProcessing();
137-
await taskManager.stopTasks();
138131
await db.stop();
139132
await keyRing.stop();
140133
await fs.promises.rm(dataDir, {
@@ -693,8 +686,6 @@ describe('vaultsPull', () => {
693686
let dataDir: string;
694687
let db: DB;
695688
let keyRing: KeyRing;
696-
let webSocketClient: WebSocketClient;
697-
let clientService: ClientService;
698689
let vaultManager: VaultManager;
699690
let taskManager: TaskManager;
700691
let acl: ACL;
@@ -758,8 +749,6 @@ describe('vaultsPull', () => {
758749
});
759750
});
760751
afterEach(async () => {
761-
await clientService?.stop({ force: true });
762-
await webSocketClient.destroy({ force: true });
763752
await vaultManager.stop();
764753
await notificationsManager.stop();
765754
await gestaltGraph.stop();
@@ -884,8 +873,6 @@ describe('vaultsScan', () => {
884873
let dataDir: string;
885874
let db: DB;
886875
let keyRing: KeyRing;
887-
let webSocketClient: WebSocketClient;
888-
let clientService: ClientService;
889876
let vaultManager: VaultManager;
890877
beforeEach(async () => {
891878
dataDir = await fs.promises.mkdtemp(
@@ -918,8 +905,6 @@ describe('vaultsScan', () => {
918905
});
919906
});
920907
afterEach(async () => {
921-
await clientService?.stop({ force: true });
922-
await webSocketClient.destroy({ force: true });
923908
await vaultManager.stop();
924909
await db.stop();
925910
await keyRing.stop();

0 commit comments

Comments
 (0)