Skip to content

Commit 0346fc5

Browse files
committed
identities claim command
creating new branch for #267 changed message to identity_id in provider message updating all commands that use provider message updated everything on the agent side for augment command started tests and debugging augment command identities claim working in client service test wrote test for command in identities
1 parent 9200b11 commit 0346fc5

File tree

7 files changed

+196
-41
lines changed

7 files changed

+196
-41
lines changed

src/bin/identities/claim.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import { clientPB, utils as clientUtils } from '../../client';
2+
import { createCommand, outputFormatter } from '../utils';
3+
import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
4+
import PolykeyClient from '../../PolykeyClient';
5+
import { errors } from '../../grpc';
6+
import * as utils from '../../utils';
7+
8+
const claim = createCommand('claim', {
9+
description: {
10+
description: 'Claim an identity for this keynode.',
11+
args: {
12+
providerId: 'Provider that identity is linked to',
13+
identityId: 'Identitiy to augment the keynode with',
14+
},
15+
},
16+
verbose: true,
17+
format: true,
18+
nodePath: true,
19+
});
20+
claim.arguments('<providerId> <identityId>');
21+
claim.alias('aug');
22+
claim.action(async (providerId, identitiyId, options) => {
23+
const clientConfig = {};
24+
clientConfig['logger'] = new Logger('CLI Logger', LogLevel.WARN, [
25+
new StreamHandler(),
26+
]);
27+
if (options.verbose) {
28+
clientConfig['logger'].setLevel(LogLevel.DEBUG);
29+
}
30+
clientConfig['nodePath'] = options.nodePath
31+
? options.nodePath
32+
: utils.getDefaultNodePath();
33+
34+
const client = await PolykeyClient.createPolykeyClient(clientConfig);
35+
36+
try {
37+
//Starting client
38+
await client.start({});
39+
const grpcClient = client.grpcClient;
40+
41+
//Constructing message.
42+
const providerMessage = new clientPB.ProviderMessage();
43+
providerMessage.setProviderId(providerId);
44+
providerMessage.setIdentityId(identitiyId);
45+
46+
//Sending message.
47+
const pCall = grpcClient.identitiesClaim(providerMessage);
48+
const { p, resolveP } = utils.promise();
49+
pCall.call.on('metadata', async (meta) => {
50+
await clientUtils.refreshSession(meta, client.session);
51+
resolveP(null);
52+
});
53+
const response = await pCall;
54+
await p;
55+
56+
const output = [`Successfully published identity claim with id: ${response.getClaimId()}
57+
on provider: ${providerId}`];
58+
59+
if (response.getUrl()) {
60+
output.push(`See claim at: ${response.getUrl()}`);
61+
}
62+
63+
process.stdout.write(
64+
outputFormatter({
65+
type: options.format === 'json' ? 'json' : 'list',
66+
data: output,
67+
}),
68+
);
69+
70+
} catch (err) {
71+
if (err instanceof errors.ErrorGRPCClientTimeout) {
72+
process.stderr.write(`${err.message}\n`);
73+
}
74+
if (err instanceof errors.ErrorGRPCServerNotStarted) {
75+
process.stderr.write(`${err.message}\n`);
76+
} else {
77+
process.stdout.write(
78+
outputFormatter({
79+
type: options.format === 'json' ? 'json' : 'list',
80+
data: ['Error:', err.message],
81+
}),
82+
);
83+
}
84+
throw err;
85+
} finally {
86+
await client.stop();
87+
options.nodePath = undefined;
88+
options.verbose = undefined;
89+
options.format = undefined;
90+
}
91+
});
92+
93+
export default claim;

src/client/GRPCClientClient.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,7 @@ class GRPCClientClient extends GRPCClient<ClientServiceClient> {
551551

552552
@ready(new clientErrors.ErrorClientClientDestroyed())
553553
public identitiesClaim(...args) {
554-
return grpcUtils.promisifyUnaryCall<utilsPB.EmptyMessage>(
554+
return grpcUtils.promisifyUnaryCall<clientPB.IdentityClaimMessage>(
555555
this.client,
556556
this.client.identitiesClaim,
557557
)(...args);

src/client/clientService.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type { NotificationsManager } from '../notifications';
99
import type { Discovery } from '../discovery';
1010
import type { ForwardProxy, ReverseProxy } from '../network';
1111
import type { GRPCServer } from '../grpc';
12+
import { Sigchain } from '../sigchain';
1213

1314
import type * as grpc from '@grpc/grpc-js';
1415
import type { IClientServiceServer } from '../proto/js/polykey/v1/client_service_grpc_pb';
@@ -40,6 +41,7 @@ function createClientService({
4041
identitiesManager,
4142
gestaltGraph,
4243
sessionManager,
44+
sigchain,
4345
notificationsManager,
4446
discovery,
4547
fwdProxy,
@@ -53,6 +55,7 @@ function createClientService({
5355
identitiesManager: IdentitiesManager;
5456
gestaltGraph: GestaltGraph;
5557
sessionManager: SessionManager;
58+
sigchain: Sigchain;
5659
notificationsManager: NotificationsManager;
5760
discovery: Discovery;
5861
fwdProxy: ForwardProxy;
@@ -84,6 +87,7 @@ function createClientService({
8487
}),
8588
...createIdentitiesRPC({
8689
identitiesManager,
90+
sigchain,
8791
gestaltGraph,
8892
nodeManager,
8993
authenticate,

src/client/rpcGestalts.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const createGestaltsRPC = ({
5858

5959
const gestalt = await gestaltGraph.getGestaltByIdentity(
6060
call.request.getProviderId() as ProviderId,
61-
call.request.getMessage() as IdentityId,
61+
call.request.getIdentityId() as IdentityId,
6262
);
6363
if (gestalt != null) {
6464
response.setGestaltGraph(JSON.stringify(gestalt));
@@ -121,7 +121,7 @@ const createGestaltsRPC = ({
121121
// Constructing identity info.
122122
const gen = discovery.discoverGestaltByIdentity(
123123
info.getProviderId() as ProviderId,
124-
info.getMessage() as IdentityId,
124+
info.getIdentityId() as IdentityId,
125125
);
126126
for await (const _ of gen) {
127127
// Empty
@@ -168,7 +168,7 @@ const createGestaltsRPC = ({
168168
call.sendMetadata(metadata);
169169

170170
const providerId = info.getProviderId() as ProviderId;
171-
const identityId = info.getMessage() as IdentityId;
171+
const identityId = info.getIdentityId() as IdentityId;
172172
const result = await gestaltGraph.getGestaltActionsByIdentity(
173173
providerId,
174174
identityId,
@@ -242,7 +242,7 @@ const createGestaltsRPC = ({
242242
// Setting the action.
243243
const action = makeGestaltAction(info.getAction());
244244
const providerId = info.getIdentity()?.getProviderId() as ProviderId;
245-
const identityId = info.getIdentity()?.getMessage() as IdentityId;
245+
const identityId = info.getIdentity()?.getIdentityId() as IdentityId;
246246
await gestaltGraph.setGestaltActionByIdentity(
247247
providerId,
248248
identityId,
@@ -309,7 +309,7 @@ const createGestaltsRPC = ({
309309
// Setting the action.
310310
const action = makeGestaltAction(info.getAction());
311311
const providerId = info.getIdentity()?.getProviderId() as ProviderId;
312-
const identityId = info.getIdentity()?.getMessage() as IdentityId;
312+
const identityId = info.getIdentity()?.getIdentityId() as IdentityId;
313313
await gestaltGraph.unsetGestaltActionByIdentity(
314314
providerId,
315315
identityId,

src/client/rpcIdentities.ts

Lines changed: 50 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,31 @@
11
import type { NodeManager } from '../nodes';
2-
import type { NodeInfo } from '../nodes/types';
32
import type { GestaltGraph } from '../gestalts';
43
import type { IdentitiesManager } from '../identities';
4+
import type { ClaimLinkIdentity, ClaimType } from '../claims/types';
55
import type {
66
IdentityId,
77
ProviderId,
88
TokenData,
9-
IdentityInfo,
109
} from '../identities/types';
1110

1211
import type * as grpc from '@grpc/grpc-js';
1312
import type * as utils from './utils';
1413
import * as errors from '../errors';
14+
import * as grpc from '@grpc/grpc-js';
15+
import * as claimsUtils from '../claims/utils';
1516
import * as grpcUtils from '../grpc/utils';
1617
import * as utilsPB from '../proto/js/polykey/v1/utils/utils_pb';
1718
import * as identitiesPB from '../proto/js/polykey/v1/identities/identities_pb';
1819

1920
const createIdentitiesRPC = ({
2021
identitiesManager,
22+
sigchain,
2123
nodeManager,
2224
gestaltGraph,
2325
authenticate,
2426
}: {
2527
identitiesManager: IdentitiesManager;
28+
sigchain: Sigchain;
2629
nodeManager: NodeManager;
2730
gestaltGraph: GestaltGraph;
2831
authenticate: utils.Authenticate;
@@ -50,7 +53,7 @@ const createIdentitiesRPC = ({
5053
'userCode was not a string',
5154
);
5255
}
53-
response.setMessage(userCode);
56+
response.setIdentityId(userCode);
5457
await genWritable.next(response);
5558

5659
// Wait to finish.
@@ -59,7 +62,7 @@ const createIdentitiesRPC = ({
5962
throw new errors.ErrorProviderAuthentication(
6063
'Failed to authenticate.',
6164
);
62-
response.setMessage(userName);
65+
response.setIdentityId(userName);
6366
await genWritable.next(response);
6467
await genWritable.next(null);
6568
} catch (err) {
@@ -81,7 +84,7 @@ const createIdentitiesRPC = ({
8184
const provider = call.request.getProvider();
8285
await identitiesManager.putToken(
8386
provider?.getProviderId() as ProviderId,
84-
provider?.getMessage() as IdentityId,
87+
provider?.getIdentityId() as IdentityId,
8588
{ accessToken: call.request.getToken() } as TokenData,
8689
);
8790
} catch (err) {
@@ -100,7 +103,7 @@ const createIdentitiesRPC = ({
100103

101104
const tokens = await identitiesManager.getToken(
102105
call.request.getProviderId() as ProviderId,
103-
call.request.getMessage() as IdentityId,
106+
call.request.getIdentityId() as IdentityId,
104107
);
105108
response.setToken(JSON.stringify(tokens));
106109
} catch (err) {
@@ -119,7 +122,7 @@ const createIdentitiesRPC = ({
119122

120123
await identitiesManager.delToken(
121124
call.request.getProviderId() as ProviderId,
122-
call.request.getMessage() as IdentityId,
125+
call.request.getIdentityId() as IdentityId,
123126
);
124127
} catch (err) {
125128
callback(grpcUtils.fromError(err), response);
@@ -158,7 +161,7 @@ const createIdentitiesRPC = ({
158161
?.getProviderId() as ProviderId;
159162
const identityId = call.request
160163
.getProvider()
161-
?.getMessage() as IdentityId;
164+
?.getIdentityId() as IdentityId;
162165
const provider = identitiesManager.getProvider(providerId);
163166
if (provider == null)
164167
throw Error(
@@ -174,7 +177,7 @@ const createIdentitiesRPC = ({
174177
const identityInfoMessage = new identitiesPB.Info();
175178
const providerMessage = new identitiesPB.Provider();
176179
providerMessage.setProviderId(identity.providerId);
177-
providerMessage.setMessage(identity.identityId);
180+
providerMessage.setIdentityId(identity.identityId);
178181
identityInfoMessage.setProvider(providerMessage);
179182
identityInfoMessage.setName(identity.name ?? '');
180183
identityInfoMessage.setEmail(identity.email ?? '');
@@ -204,7 +207,7 @@ const createIdentitiesRPC = ({
204207
const identities = await provider.getAuthIdentityIds();
205208
if (identities.length !== 0) {
206209
providerMessage.setProviderId(providerId);
207-
providerMessage.setMessage(identities[0]);
210+
providerMessage.setIdentityId(identities[0]);
208211
} else throw Error(`No identities found for provider: ${providerId}`);
209212
callback(null, providerMessage);
210213
} catch (err) {
@@ -215,35 +218,49 @@ const createIdentitiesRPC = ({
215218
* Augments the keynode with a new identity.
216219
*/
217220
identitiesClaim: async (
218-
call: grpc.ServerUnaryCall<identitiesPB.Provider, utilsPB.EmptyMessage>,
219-
callback: grpc.sendUnaryData<utilsPB.EmptyMessage>,
221+
call: grpc.ServerUnaryCall<
222+
clientPB.ProviderMessage,
223+
clientPB.IdentityClaimMessage
224+
>,
225+
callback: grpc.sendUnaryData<clientPB.IdentityClaimMessage>,
220226
): Promise<void> => {
221-
// To augment a keynode we need a provider, generate an oauthkey and then
222-
const info = call.request;
227+
const response = new clientPB.IdentityClaimMessage();
223228
try {
224-
const metadata = await authenticate(call.metadata);
225-
call.sendMetadata(metadata);
229+
await sessionManager.verifyToken(utils.getToken(call.metadata));
230+
const responseMeta = utils.createMetaTokenResponse(
231+
await sessionManager.generateToken(),
232+
);
233+
call.sendMetadata(responseMeta);
234+
235+
// Check provider is authenticated
236+
const providerId = call.request.getProviderId() as ProviderId;
237+
const provider = identitiesManager.getProvider(providerId);
238+
if (provider == null) throw Error(`Invalid provider: ${providerId}`);
239+
240+
const identityId = call.request.getIdentityId() as IdentityId;
241+
const token = await identitiesManager.getToken(providerId, identityId);
242+
if (token == null) {
243+
throw Error(`${identityId} has not been authenticated`);
244+
}
245+
246+
await provider.checkToken(token, identityId);
247+
248+
// Create identity claim on our node
249+
const claim = await nodeManager.claimIdentity(providerId, identityId);
250+
251+
// Publish claim on identity
252+
const claimDecoded = claimsUtils.decodeClaim(claim);
253+
const publishedClaimData = await provider.publishClaim(identityId, claimDecoded);
254+
255+
response.setClaimId(publishedClaimData.id);
256+
if (publishedClaimData.url !== undefined) {
257+
response.setUrl(publishedClaimData.url);
258+
}
226259

227-
const nodeId = nodeManager.getNodeId(); // Getting the local node ID.
228-
229-
// Do the deed...
230-
const nodeInfo: NodeInfo = {
231-
id: nodeId,
232-
chain: {},
233-
};
234-
const identityInfo: IdentityInfo = {
235-
providerId: info.getProviderId() as ProviderId,
236-
identityId: info.getMessage() as IdentityId,
237-
claims: {},
238-
};
239-
await gestaltGraph.linkNodeAndIdentity(nodeInfo, identityInfo); // Need to call this
240-
// it takes NodeInfo and IdentityInfo.
241-
// Getting and creating NodeInfo is blocked by
242260
} catch (err) {
243261
callback(grpcUtils.fromError(err), null);
244262
}
245-
const emptyMessage = new utilsPB.EmptyMessage();
246-
callback(null, emptyMessage);
263+
callback(null, response);
247264
},
248265
};
249266
};

src/nodes/NodeManager.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { KeyManager } from '../keys';
22
import type { PublicKeyPem } from '../keys/types';
33
import type { Sigchain } from '../sigchain';
44
import type { ChainData, ChainDataEncoded } from '../sigchain/types';
5-
import type { ClaimIdString } from '../claims/types';
5+
import type { ClaimEncoded, ClaimId, ClaimIdString } from '../claims/types';
66
import type {
77
NodeId,
88
NodeAddress,
@@ -354,6 +354,28 @@ class NodeManager {
354354
});
355355
}
356356

357+
/**
358+
* Call this function upon receiving a "claim node request" notification from
359+
* another node.
360+
*/
361+
@ready(new nodesErrors.ErrorNodeManagerNotRunning())
362+
public async claimIdentity(providerId: ProviderId, identityId: IdentityId): Promise<ClaimEncoded> {
363+
return await this.sigchain.transaction(async (sigchain) => {
364+
await sigchain.addClaim({
365+
type: 'identity',
366+
node: this.getNodeId(),
367+
provider: providerId,
368+
identity: identityId,
369+
});
370+
const claimId = await sigchain.getLatestClaimId();
371+
if (claimId === undefined) {
372+
// Should not happen
373+
throw new sigchainErrors.ErrorSigchainClaimUndefined();
374+
}
375+
return sigchain.getClaim(claimId);
376+
});
377+
}
378+
357379
@ready(new nodesErrors.ErrorNodeManagerNotRunning())
358380
public async setNode(
359381
nodeId: NodeId,

0 commit comments

Comments
 (0)