Skip to content

Commit

Permalink
identities claim command
Browse files Browse the repository at this point in the history
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
  • Loading branch information
emmacasolin committed Dec 2, 2021
1 parent 9200b11 commit 0346fc5
Show file tree
Hide file tree
Showing 7 changed files with 196 additions and 41 deletions.
93 changes: 93 additions & 0 deletions src/bin/identities/claim.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { clientPB, utils as clientUtils } from '../../client';
import { createCommand, outputFormatter } from '../utils';
import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
import PolykeyClient from '../../PolykeyClient';
import { errors } from '../../grpc';
import * as utils from '../../utils';

const claim = createCommand('claim', {
description: {
description: 'Claim an identity for this keynode.',
args: {
providerId: 'Provider that identity is linked to',
identityId: 'Identitiy to augment the keynode with',
},
},
verbose: true,
format: true,
nodePath: true,
});
claim.arguments('<providerId> <identityId>');
claim.alias('aug');
claim.action(async (providerId, identitiyId, options) => {
const clientConfig = {};
clientConfig['logger'] = new Logger('CLI Logger', LogLevel.WARN, [
new StreamHandler(),
]);
if (options.verbose) {
clientConfig['logger'].setLevel(LogLevel.DEBUG);
}
clientConfig['nodePath'] = options.nodePath
? options.nodePath
: utils.getDefaultNodePath();

const client = await PolykeyClient.createPolykeyClient(clientConfig);

try {
//Starting client
await client.start({});
const grpcClient = client.grpcClient;

//Constructing message.
const providerMessage = new clientPB.ProviderMessage();
providerMessage.setProviderId(providerId);
providerMessage.setIdentityId(identitiyId);

//Sending message.
const pCall = grpcClient.identitiesClaim(providerMessage);
const { p, resolveP } = utils.promise();
pCall.call.on('metadata', async (meta) => {
await clientUtils.refreshSession(meta, client.session);
resolveP(null);
});
const response = await pCall;
await p;

const output = [`Successfully published identity claim with id: ${response.getClaimId()}
on provider: ${providerId}`];

if (response.getUrl()) {
output.push(`See claim at: ${response.getUrl()}`);
}

process.stdout.write(
outputFormatter({
type: options.format === 'json' ? 'json' : 'list',
data: output,
}),
);

} catch (err) {
if (err instanceof errors.ErrorGRPCClientTimeout) {
process.stderr.write(`${err.message}\n`);
}
if (err instanceof errors.ErrorGRPCServerNotStarted) {
process.stderr.write(`${err.message}\n`);
} else {
process.stdout.write(
outputFormatter({
type: options.format === 'json' ? 'json' : 'list',
data: ['Error:', err.message],
}),
);
}
throw err;
} finally {
await client.stop();
options.nodePath = undefined;
options.verbose = undefined;
options.format = undefined;
}
});

export default claim;
2 changes: 1 addition & 1 deletion src/client/GRPCClientClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,7 @@ class GRPCClientClient extends GRPCClient<ClientServiceClient> {

@ready(new clientErrors.ErrorClientClientDestroyed())
public identitiesClaim(...args) {
return grpcUtils.promisifyUnaryCall<utilsPB.EmptyMessage>(
return grpcUtils.promisifyUnaryCall<clientPB.IdentityClaimMessage>(
this.client,
this.client.identitiesClaim,
)(...args);
Expand Down
4 changes: 4 additions & 0 deletions src/client/clientService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type { NotificationsManager } from '../notifications';
import type { Discovery } from '../discovery';
import type { ForwardProxy, ReverseProxy } from '../network';
import type { GRPCServer } from '../grpc';
import { Sigchain } from '../sigchain';

import type * as grpc from '@grpc/grpc-js';
import type { IClientServiceServer } from '../proto/js/polykey/v1/client_service_grpc_pb';
Expand Down Expand Up @@ -40,6 +41,7 @@ function createClientService({
identitiesManager,
gestaltGraph,
sessionManager,
sigchain,
notificationsManager,
discovery,
fwdProxy,
Expand All @@ -53,6 +55,7 @@ function createClientService({
identitiesManager: IdentitiesManager;
gestaltGraph: GestaltGraph;
sessionManager: SessionManager;
sigchain: Sigchain;
notificationsManager: NotificationsManager;
discovery: Discovery;
fwdProxy: ForwardProxy;
Expand Down Expand Up @@ -84,6 +87,7 @@ function createClientService({
}),
...createIdentitiesRPC({
identitiesManager,
sigchain,
gestaltGraph,
nodeManager,
authenticate,
Expand Down
10 changes: 5 additions & 5 deletions src/client/rpcGestalts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const createGestaltsRPC = ({

const gestalt = await gestaltGraph.getGestaltByIdentity(
call.request.getProviderId() as ProviderId,
call.request.getMessage() as IdentityId,
call.request.getIdentityId() as IdentityId,
);
if (gestalt != null) {
response.setGestaltGraph(JSON.stringify(gestalt));
Expand Down Expand Up @@ -121,7 +121,7 @@ const createGestaltsRPC = ({
// Constructing identity info.
const gen = discovery.discoverGestaltByIdentity(
info.getProviderId() as ProviderId,
info.getMessage() as IdentityId,
info.getIdentityId() as IdentityId,
);
for await (const _ of gen) {
// Empty
Expand Down Expand Up @@ -168,7 +168,7 @@ const createGestaltsRPC = ({
call.sendMetadata(metadata);

const providerId = info.getProviderId() as ProviderId;
const identityId = info.getMessage() as IdentityId;
const identityId = info.getIdentityId() as IdentityId;
const result = await gestaltGraph.getGestaltActionsByIdentity(
providerId,
identityId,
Expand Down Expand Up @@ -242,7 +242,7 @@ const createGestaltsRPC = ({
// Setting the action.
const action = makeGestaltAction(info.getAction());
const providerId = info.getIdentity()?.getProviderId() as ProviderId;
const identityId = info.getIdentity()?.getMessage() as IdentityId;
const identityId = info.getIdentity()?.getIdentityId() as IdentityId;
await gestaltGraph.setGestaltActionByIdentity(
providerId,
identityId,
Expand Down Expand Up @@ -309,7 +309,7 @@ const createGestaltsRPC = ({
// Setting the action.
const action = makeGestaltAction(info.getAction());
const providerId = info.getIdentity()?.getProviderId() as ProviderId;
const identityId = info.getIdentity()?.getMessage() as IdentityId;
const identityId = info.getIdentity()?.getIdentityId() as IdentityId;
await gestaltGraph.unsetGestaltActionByIdentity(
providerId,
identityId,
Expand Down
83 changes: 50 additions & 33 deletions src/client/rpcIdentities.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,31 @@
import type { NodeManager } from '../nodes';
import type { NodeInfo } from '../nodes/types';
import type { GestaltGraph } from '../gestalts';
import type { IdentitiesManager } from '../identities';
import type { ClaimLinkIdentity, ClaimType } from '../claims/types';
import type {
IdentityId,
ProviderId,
TokenData,
IdentityInfo,
} from '../identities/types';

import type * as grpc from '@grpc/grpc-js';
import type * as utils from './utils';
import * as errors from '../errors';
import * as grpc from '@grpc/grpc-js';
import * as claimsUtils from '../claims/utils';
import * as grpcUtils from '../grpc/utils';
import * as utilsPB from '../proto/js/polykey/v1/utils/utils_pb';
import * as identitiesPB from '../proto/js/polykey/v1/identities/identities_pb';

const createIdentitiesRPC = ({
identitiesManager,
sigchain,
nodeManager,
gestaltGraph,
authenticate,
}: {
identitiesManager: IdentitiesManager;
sigchain: Sigchain;
nodeManager: NodeManager;
gestaltGraph: GestaltGraph;
authenticate: utils.Authenticate;
Expand Down Expand Up @@ -50,7 +53,7 @@ const createIdentitiesRPC = ({
'userCode was not a string',
);
}
response.setMessage(userCode);
response.setIdentityId(userCode);
await genWritable.next(response);

// Wait to finish.
Expand All @@ -59,7 +62,7 @@ const createIdentitiesRPC = ({
throw new errors.ErrorProviderAuthentication(
'Failed to authenticate.',
);
response.setMessage(userName);
response.setIdentityId(userName);
await genWritable.next(response);
await genWritable.next(null);
} catch (err) {
Expand All @@ -81,7 +84,7 @@ const createIdentitiesRPC = ({
const provider = call.request.getProvider();
await identitiesManager.putToken(
provider?.getProviderId() as ProviderId,
provider?.getMessage() as IdentityId,
provider?.getIdentityId() as IdentityId,
{ accessToken: call.request.getToken() } as TokenData,
);
} catch (err) {
Expand All @@ -100,7 +103,7 @@ const createIdentitiesRPC = ({

const tokens = await identitiesManager.getToken(
call.request.getProviderId() as ProviderId,
call.request.getMessage() as IdentityId,
call.request.getIdentityId() as IdentityId,
);
response.setToken(JSON.stringify(tokens));
} catch (err) {
Expand All @@ -119,7 +122,7 @@ const createIdentitiesRPC = ({

await identitiesManager.delToken(
call.request.getProviderId() as ProviderId,
call.request.getMessage() as IdentityId,
call.request.getIdentityId() as IdentityId,
);
} catch (err) {
callback(grpcUtils.fromError(err), response);
Expand Down Expand Up @@ -158,7 +161,7 @@ const createIdentitiesRPC = ({
?.getProviderId() as ProviderId;
const identityId = call.request
.getProvider()
?.getMessage() as IdentityId;
?.getIdentityId() as IdentityId;
const provider = identitiesManager.getProvider(providerId);
if (provider == null)
throw Error(
Expand All @@ -174,7 +177,7 @@ const createIdentitiesRPC = ({
const identityInfoMessage = new identitiesPB.Info();
const providerMessage = new identitiesPB.Provider();
providerMessage.setProviderId(identity.providerId);
providerMessage.setMessage(identity.identityId);
providerMessage.setIdentityId(identity.identityId);
identityInfoMessage.setProvider(providerMessage);
identityInfoMessage.setName(identity.name ?? '');
identityInfoMessage.setEmail(identity.email ?? '');
Expand Down Expand Up @@ -204,7 +207,7 @@ const createIdentitiesRPC = ({
const identities = await provider.getAuthIdentityIds();
if (identities.length !== 0) {
providerMessage.setProviderId(providerId);
providerMessage.setMessage(identities[0]);
providerMessage.setIdentityId(identities[0]);
} else throw Error(`No identities found for provider: ${providerId}`);
callback(null, providerMessage);
} catch (err) {
Expand All @@ -215,35 +218,49 @@ const createIdentitiesRPC = ({
* Augments the keynode with a new identity.
*/
identitiesClaim: async (
call: grpc.ServerUnaryCall<identitiesPB.Provider, utilsPB.EmptyMessage>,
callback: grpc.sendUnaryData<utilsPB.EmptyMessage>,
call: grpc.ServerUnaryCall<
clientPB.ProviderMessage,
clientPB.IdentityClaimMessage
>,
callback: grpc.sendUnaryData<clientPB.IdentityClaimMessage>,
): Promise<void> => {
// To augment a keynode we need a provider, generate an oauthkey and then
const info = call.request;
const response = new clientPB.IdentityClaimMessage();
try {
const metadata = await authenticate(call.metadata);
call.sendMetadata(metadata);
await sessionManager.verifyToken(utils.getToken(call.metadata));
const responseMeta = utils.createMetaTokenResponse(
await sessionManager.generateToken(),
);
call.sendMetadata(responseMeta);

// Check provider is authenticated
const providerId = call.request.getProviderId() as ProviderId;
const provider = identitiesManager.getProvider(providerId);
if (provider == null) throw Error(`Invalid provider: ${providerId}`);

const identityId = call.request.getIdentityId() as IdentityId;
const token = await identitiesManager.getToken(providerId, identityId);
if (token == null) {
throw Error(`${identityId} has not been authenticated`);
}

await provider.checkToken(token, identityId);

// Create identity claim on our node
const claim = await nodeManager.claimIdentity(providerId, identityId);

// Publish claim on identity
const claimDecoded = claimsUtils.decodeClaim(claim);
const publishedClaimData = await provider.publishClaim(identityId, claimDecoded);

response.setClaimId(publishedClaimData.id);
if (publishedClaimData.url !== undefined) {
response.setUrl(publishedClaimData.url);
}

const nodeId = nodeManager.getNodeId(); // Getting the local node ID.

// Do the deed...
const nodeInfo: NodeInfo = {
id: nodeId,
chain: {},
};
const identityInfo: IdentityInfo = {
providerId: info.getProviderId() as ProviderId,
identityId: info.getMessage() as IdentityId,
claims: {},
};
await gestaltGraph.linkNodeAndIdentity(nodeInfo, identityInfo); // Need to call this
// it takes NodeInfo and IdentityInfo.
// Getting and creating NodeInfo is blocked by
} catch (err) {
callback(grpcUtils.fromError(err), null);
}
const emptyMessage = new utilsPB.EmptyMessage();
callback(null, emptyMessage);
callback(null, response);
},
};
};
Expand Down
24 changes: 23 additions & 1 deletion src/nodes/NodeManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { KeyManager } from '../keys';
import type { PublicKeyPem } from '../keys/types';
import type { Sigchain } from '../sigchain';
import type { ChainData, ChainDataEncoded } from '../sigchain/types';
import type { ClaimIdString } from '../claims/types';
import type { ClaimEncoded, ClaimId, ClaimIdString } from '../claims/types';
import type {
NodeId,
NodeAddress,
Expand Down Expand Up @@ -354,6 +354,28 @@ class NodeManager {
});
}

/**
* Call this function upon receiving a "claim node request" notification from
* another node.
*/
@ready(new nodesErrors.ErrorNodeManagerNotRunning())
public async claimIdentity(providerId: ProviderId, identityId: IdentityId): Promise<ClaimEncoded> {
return await this.sigchain.transaction(async (sigchain) => {
await sigchain.addClaim({
type: 'identity',
node: this.getNodeId(),
provider: providerId,
identity: identityId,
});
const claimId = await sigchain.getLatestClaimId();
if (claimId === undefined) {
// Should not happen
throw new sigchainErrors.ErrorSigchainClaimUndefined();
}
return sigchain.getClaim(claimId);
});
}

@ready(new nodesErrors.ErrorNodeManagerNotRunning())
public async setNode(
nodeId: NodeId,
Expand Down
Loading

0 comments on commit 0346fc5

Please sign in to comment.