From 8f05d5947187969a89dccd49bc8ab242276d6a5f Mon Sep 17 00:00:00 2001 From: Emma Casolin Date: Mon, 14 Feb 2022 15:56:23 +1100 Subject: [PATCH] `identities authenticated` command --- ...mmandTokens.ts => CommandAuthenticated.ts} | 10 +- src/bin/identities/CommandIdentities.ts | 4 +- src/client/GRPCClientClient.ts | 8 + .../service/identitiesAuthenticatedGet.ts | 36 +++- src/client/service/index.ts | 2 + .../js/polykey/v1/client_service_grpc_pb.d.ts | 15 ++ .../js/polykey/v1/client_service_grpc_pb.js | 22 ++ .../polykey/v1/identities/identities_pb.d.ts | 31 +++ .../js/polykey/v1/identities/identities_pb.js | 196 ++++++++++++++++++ .../schemas/polykey/v1/client_service.proto | 1 + .../polykey/v1/identities/identities.proto | 5 + tests/bin/identities/identities.test.ts | 6 +- .../identitiesAuthenticatedGet.test.ts | 58 +++++- 13 files changed, 373 insertions(+), 21 deletions(-) rename src/bin/identities/{CommandTokens.ts => CommandAuthenticated.ts} (91%) diff --git a/src/bin/identities/CommandTokens.ts b/src/bin/identities/CommandAuthenticated.ts similarity index 91% rename from src/bin/identities/CommandTokens.ts rename to src/bin/identities/CommandAuthenticated.ts index 550a61a9f1..a5f9006dea 100644 --- a/src/bin/identities/CommandTokens.ts +++ b/src/bin/identities/CommandAuthenticated.ts @@ -6,10 +6,10 @@ import * as binUtils from '../utils'; import * as parsers from '../utils/parsers'; import * as binProcessors from '../utils/processors'; -class CommandTokens extends CommandPolykey { +class CommandAuthenticated extends CommandPolykey { constructor(...args: ConstructorParameters) { super(...args); - this.name('tokens'); + this.name('authenticated'); this.description('Lists all authenticated identities across all providers'); this.option( '-pi, --provider-id [providerId]', @@ -38,7 +38,7 @@ class CommandTokens extends CommandPolykey { ); let pkClient: PolykeyClient; let genReadable: ReturnType< - typeof pkClient.grpcClient.identitiesTokensGet + typeof pkClient.grpcClient.identitiesAuthenticatedGet >; this.exitHandlers.handlers.push(async () => { if (genReadable != null) genReadable.stream.cancel(); @@ -57,7 +57,7 @@ class CommandTokens extends CommandPolykey { optionalProviderMessage.setProviderId(options.providerId); } await binUtils.retryAuthentication(async (auth) => { - const genReadable = pkClient.grpcClient.identitiesTokensGet( + const genReadable = pkClient.grpcClient.identitiesAuthenticatedGet( optionalProviderMessage, auth, ); @@ -81,4 +81,4 @@ class CommandTokens extends CommandPolykey { } } -export default CommandTokens; +export default CommandAuthenticated; diff --git a/src/bin/identities/CommandIdentities.ts b/src/bin/identities/CommandIdentities.ts index ee21520bd2..db52099de8 100644 --- a/src/bin/identities/CommandIdentities.ts +++ b/src/bin/identities/CommandIdentities.ts @@ -1,5 +1,6 @@ import CommandAllow from './CommandAllow'; import CommandAuthenticate from './CommandAuthenticate'; +import CommandAuthenticated from './CommandAuthenticated'; import CommandClaim from './CommandClaim'; import CommandDisallow from './CommandDisallow'; import CommandDiscover from './CommandDiscover'; @@ -7,7 +8,6 @@ import CommandGet from './CommandGet'; import CommandList from './CommandList'; import CommandPermissions from './CommandPermissions'; import CommandSearch from './CommandSearch'; -import CommandTokens from './CommandTokens'; import CommandTrust from './CommandTrust'; import CommandUntrust from './CommandUntrust'; import CommandPolykey from '../CommandPolykey'; @@ -19,6 +19,7 @@ class CommandIdentities extends CommandPolykey { this.description('Identities Operations'); this.addCommand(new CommandAllow(...args)); this.addCommand(new CommandAuthenticate(...args)); + this.addCommand(new CommandAuthenticated(...args)); this.addCommand(new CommandClaim(...args)); this.addCommand(new CommandDisallow(...args)); this.addCommand(new CommandDiscover(...args)); @@ -26,7 +27,6 @@ class CommandIdentities extends CommandPolykey { this.addCommand(new CommandList(...args)); this.addCommand(new CommandPermissions(...args)); this.addCommand(new CommandSearch(...args)); - this.addCommand(new CommandTokens(...args)); this.addCommand(new CommandTrust(...args)); this.addCommand(new CommandUntrust(...args)); } diff --git a/src/client/GRPCClientClient.ts b/src/client/GRPCClientClient.ts index 819a780302..49640ee102 100644 --- a/src/client/GRPCClientClient.ts +++ b/src/client/GRPCClientClient.ts @@ -599,6 +599,14 @@ class GRPCClientClient extends GRPCClient { )(...args); } + @ready(new clientErrors.ErrorClientClientDestroyed()) + public identitiesAuthenticatedGet(...args) { + return grpcUtils.promisifyReadableStreamCall( + this.client, + this.client.identitiesAuthenticatedGet, + )(...args); + } + @ready(new clientErrors.ErrorClientClientDestroyed()) public notificationsSend(...args) { return grpcUtils.promisifyUnaryCall( diff --git a/src/client/service/identitiesAuthenticatedGet.ts b/src/client/service/identitiesAuthenticatedGet.ts index 1428ef8a1b..1fd4bb9dad 100644 --- a/src/client/service/identitiesAuthenticatedGet.ts +++ b/src/client/service/identitiesAuthenticatedGet.ts @@ -1,8 +1,11 @@ import type * as grpc from '@grpc/grpc-js'; import type { Authenticate } from '../types'; -import type { IdentitiesManager, Provider } from '../../identities'; -import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb'; +import type { IdentitiesManager } from '../../identities'; +import type { ProviderId } from '../../identities/types'; +import { validateSync } from '../../validation'; +import { matchSync } from '../../utils'; import * as grpcUtils from '../../grpc/utils'; +import * as validationUtils from '../../validation/utils'; import * as identitiesPB from '../../proto/js/polykey/v1/identities/identities_pb'; function identitiesAuthenticatedGet({ @@ -14,7 +17,7 @@ function identitiesAuthenticatedGet({ }) { return async ( call: grpc.ServerWritableStream< - utilsPB.EmptyMessage, + identitiesPB.OptionalProvider, identitiesPB.Provider >, ): Promise => { @@ -22,10 +25,29 @@ function identitiesAuthenticatedGet({ try { const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - const providers = Object.values( - identitiesManager.getProviders(), - ) as Array; - for (const provider of providers) { + let providerId: ProviderId | undefined; + if (call.request.hasProviderId()) { + providerId = validateSync( + (keyPath, value) => { + return matchSync(keyPath)( + [['providerId'], () => validationUtils.parseProviderId(value)], + () => value, + ); + }, + { + providerId: call.request.getProviderId(), + }, + ).providerId; + } + const providerIds: Array = + providerId == null + ? (Object.keys(identitiesManager.getProviders()) as Array) + : [providerId]; + for (const providerId of providerIds) { + const provider = identitiesManager.getProvider(providerId); + if (provider == null) { + continue; + } const identities = await provider.getAuthIdentityIds(); const providerMessage = new identitiesPB.Provider(); providerMessage.setProviderId(provider.id); diff --git a/src/client/service/index.ts b/src/client/service/index.ts index 91ced4423f..8e4f25d115 100644 --- a/src/client/service/index.ts +++ b/src/client/service/index.ts @@ -31,6 +31,7 @@ import gestaltsGestaltList from './gestaltsGestaltList'; import gestaltsGestaltTrustByIdentity from './gestaltsGestaltTrustByIdentity'; import gestaltsGestaltTrustByNode from './gestaltsGestaltTrustByNode'; import identitiesAuthenticate from './identitiesAuthenticate'; +import identitiesAuthenticatedGet from './identitiesAuthenticatedGet'; import identitiesClaim from './identitiesClaim'; import identitiesInfoGet from './identitiesInfoGet'; import identitiesInfoConnectedGet from './identitiesInfoConnectedGet'; @@ -131,6 +132,7 @@ function createService({ gestaltsGestaltTrustByIdentity: gestaltsGestaltTrustByIdentity(container), gestaltsGestaltTrustByNode: gestaltsGestaltTrustByNode(container), identitiesAuthenticate: identitiesAuthenticate(container), + identitiesAuthenticatedGet: identitiesAuthenticatedGet(container), identitiesClaim: identitiesClaim(container), identitiesInfoGet: identitiesInfoGet(container), identitiesInfoConnectedGet: identitiesInfoConnectedGet(container), diff --git a/src/proto/js/polykey/v1/client_service_grpc_pb.d.ts b/src/proto/js/polykey/v1/client_service_grpc_pb.d.ts index c24147d643..d558b71408 100644 --- a/src/proto/js/polykey/v1/client_service_grpc_pb.d.ts +++ b/src/proto/js/polykey/v1/client_service_grpc_pb.d.ts @@ -59,6 +59,7 @@ interface IClientServiceService extends grpc.ServiceDefinition; responseDeserialize: grpc.deserialize; } +interface IClientServiceService_IIdentitiesAuthenticatedGet extends grpc.MethodDefinition { + path: "/polykey.v1.ClientService/IdentitiesAuthenticatedGet"; + requestStream: false; + responseStream: true; + requestSerialize: grpc.serialize; + requestDeserialize: grpc.deserialize; + responseSerialize: grpc.serialize; + responseDeserialize: grpc.deserialize; +} interface IClientServiceService_IIdentitiesTokenPut extends grpc.MethodDefinition { path: "/polykey.v1.ClientService/IdentitiesTokenPut"; requestStream: false; @@ -695,6 +705,7 @@ export interface IClientServiceServer extends grpc.UntypedServiceImplementation vaultsVersion: grpc.handleUnaryCall; vaultsLog: grpc.handleServerStreamingCall; identitiesAuthenticate: grpc.handleServerStreamingCall; + identitiesAuthenticatedGet: grpc.handleServerStreamingCall; identitiesTokenPut: grpc.handleUnaryCall; identitiesTokenGet: grpc.handleUnaryCall; identitiesTokenDelete: grpc.handleUnaryCall; @@ -834,6 +845,8 @@ export interface IClientServiceClient { vaultsLog(request: polykey_v1_vaults_vaults_pb.Log, metadata?: grpc.Metadata, options?: Partial): grpc.ClientReadableStream; identitiesAuthenticate(request: polykey_v1_identities_identities_pb.Provider, options?: Partial): grpc.ClientReadableStream; identitiesAuthenticate(request: polykey_v1_identities_identities_pb.Provider, metadata?: grpc.Metadata, options?: Partial): grpc.ClientReadableStream; + identitiesAuthenticatedGet(request: polykey_v1_identities_identities_pb.OptionalProvider, options?: Partial): grpc.ClientReadableStream; + identitiesAuthenticatedGet(request: polykey_v1_identities_identities_pb.OptionalProvider, metadata?: grpc.Metadata, options?: Partial): grpc.ClientReadableStream; identitiesTokenPut(request: polykey_v1_identities_identities_pb.TokenSpecific, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; identitiesTokenPut(request: polykey_v1_identities_identities_pb.TokenSpecific, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; identitiesTokenPut(request: polykey_v1_identities_identities_pb.TokenSpecific, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; @@ -1017,6 +1030,8 @@ export class ClientServiceClient extends grpc.Client implements IClientServiceCl public vaultsLog(request: polykey_v1_vaults_vaults_pb.Log, metadata?: grpc.Metadata, options?: Partial): grpc.ClientReadableStream; public identitiesAuthenticate(request: polykey_v1_identities_identities_pb.Provider, options?: Partial): grpc.ClientReadableStream; public identitiesAuthenticate(request: polykey_v1_identities_identities_pb.Provider, metadata?: grpc.Metadata, options?: Partial): grpc.ClientReadableStream; + public identitiesAuthenticatedGet(request: polykey_v1_identities_identities_pb.OptionalProvider, options?: Partial): grpc.ClientReadableStream; + public identitiesAuthenticatedGet(request: polykey_v1_identities_identities_pb.OptionalProvider, metadata?: grpc.Metadata, options?: Partial): grpc.ClientReadableStream; public identitiesTokenPut(request: polykey_v1_identities_identities_pb.TokenSpecific, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; public identitiesTokenPut(request: polykey_v1_identities_identities_pb.TokenSpecific, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; public identitiesTokenPut(request: polykey_v1_identities_identities_pb.TokenSpecific, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; diff --git a/src/proto/js/polykey/v1/client_service_grpc_pb.js b/src/proto/js/polykey/v1/client_service_grpc_pb.js index fe2b2eae81..59bfc3d728 100644 --- a/src/proto/js/polykey/v1/client_service_grpc_pb.js +++ b/src/proto/js/polykey/v1/client_service_grpc_pb.js @@ -80,6 +80,17 @@ function deserialize_polykey_v1_identities_Info(buffer_arg) { return polykey_v1_identities_identities_pb.Info.deserializeBinary(new Uint8Array(buffer_arg)); } +function serialize_polykey_v1_identities_OptionalProvider(arg) { + if (!(arg instanceof polykey_v1_identities_identities_pb.OptionalProvider)) { + throw new Error('Expected argument of type polykey.v1.identities.OptionalProvider'); + } + return Buffer.from(arg.serializeBinary()); +} + +function deserialize_polykey_v1_identities_OptionalProvider(buffer_arg) { + return polykey_v1_identities_identities_pb.OptionalProvider.deserializeBinary(new Uint8Array(buffer_arg)); +} + function serialize_polykey_v1_identities_Provider(arg) { if (!(arg instanceof polykey_v1_identities_identities_pb.Provider)) { throw new Error('Expected argument of type polykey.v1.identities.Provider'); @@ -934,6 +945,17 @@ identitiesAuthenticate: { responseSerialize: serialize_polykey_v1_identities_AuthenticationProcess, responseDeserialize: deserialize_polykey_v1_identities_AuthenticationProcess, }, + identitiesAuthenticatedGet: { + path: '/polykey.v1.ClientService/IdentitiesAuthenticatedGet', + requestStream: false, + responseStream: true, + requestType: polykey_v1_identities_identities_pb.OptionalProvider, + responseType: polykey_v1_identities_identities_pb.Provider, + requestSerialize: serialize_polykey_v1_identities_OptionalProvider, + requestDeserialize: deserialize_polykey_v1_identities_OptionalProvider, + responseSerialize: serialize_polykey_v1_identities_Provider, + responseDeserialize: deserialize_polykey_v1_identities_Provider, + }, identitiesTokenPut: { path: '/polykey.v1.ClientService/IdentitiesTokenPut', requestStream: false, diff --git a/src/proto/js/polykey/v1/identities/identities_pb.d.ts b/src/proto/js/polykey/v1/identities/identities_pb.d.ts index 22ce0f08d9..c80a027746 100644 --- a/src/proto/js/polykey/v1/identities/identities_pb.d.ts +++ b/src/proto/js/polykey/v1/identities/identities_pb.d.ts @@ -29,6 +29,37 @@ export namespace Provider { } } +export class OptionalProvider extends jspb.Message { + + hasProviderId(): boolean; + clearProviderId(): void; + getProviderId(): string; + setProviderId(value: string): OptionalProvider; + + getOptionalProviderIdCase(): OptionalProvider.OptionalProviderIdCase; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): OptionalProvider.AsObject; + static toObject(includeInstance: boolean, msg: OptionalProvider): OptionalProvider.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: OptionalProvider, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): OptionalProvider; + static deserializeBinaryFromReader(message: OptionalProvider, reader: jspb.BinaryReader): OptionalProvider; +} + +export namespace OptionalProvider { + export type AsObject = { + providerId: string, + } + + export enum OptionalProviderIdCase { + OPTIONAL_PROVIDER_ID_NOT_SET = 0, + PROVIDER_ID = 1, + } + +} + export class Token extends jspb.Message { getToken(): string; setToken(value: string): Token; diff --git a/src/proto/js/polykey/v1/identities/identities_pb.js b/src/proto/js/polykey/v1/identities/identities_pb.js index 011509772b..cbfb21ed9a 100644 --- a/src/proto/js/polykey/v1/identities/identities_pb.js +++ b/src/proto/js/polykey/v1/identities/identities_pb.js @@ -20,6 +20,8 @@ goog.exportSymbol('proto.polykey.v1.identities.AuthenticationRequest', null, glo goog.exportSymbol('proto.polykey.v1.identities.AuthenticationResponse', null, global); goog.exportSymbol('proto.polykey.v1.identities.Claim', null, global); goog.exportSymbol('proto.polykey.v1.identities.Info', null, global); +goog.exportSymbol('proto.polykey.v1.identities.OptionalProvider', null, global); +goog.exportSymbol('proto.polykey.v1.identities.OptionalProvider.OptionalProviderIdCase', null, global); goog.exportSymbol('proto.polykey.v1.identities.Provider', null, global); goog.exportSymbol('proto.polykey.v1.identities.ProviderSearch', null, global); goog.exportSymbol('proto.polykey.v1.identities.ProviderSearch.OptionalAuthIdentityIdCase', null, global); @@ -46,6 +48,27 @@ if (goog.DEBUG && !COMPILED) { */ proto.polykey.v1.identities.Provider.displayName = 'proto.polykey.v1.identities.Provider'; } +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.polykey.v1.identities.OptionalProvider = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.polykey.v1.identities.OptionalProvider.oneofGroups_); +}; +goog.inherits(proto.polykey.v1.identities.OptionalProvider, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.polykey.v1.identities.OptionalProvider.displayName = 'proto.polykey.v1.identities.OptionalProvider'; +} /** * Generated by JsPbCodeGenerator. * @param {Array=} opt_data Optional initial data array, typically from a @@ -375,6 +398,179 @@ proto.polykey.v1.identities.Provider.prototype.setIdentityId = function(value) { +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.polykey.v1.identities.OptionalProvider.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.polykey.v1.identities.OptionalProvider.OptionalProviderIdCase = { + OPTIONAL_PROVIDER_ID_NOT_SET: 0, + PROVIDER_ID: 1 +}; + +/** + * @return {proto.polykey.v1.identities.OptionalProvider.OptionalProviderIdCase} + */ +proto.polykey.v1.identities.OptionalProvider.prototype.getOptionalProviderIdCase = function() { + return /** @type {proto.polykey.v1.identities.OptionalProvider.OptionalProviderIdCase} */(jspb.Message.computeOneofCase(this, proto.polykey.v1.identities.OptionalProvider.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.polykey.v1.identities.OptionalProvider.prototype.toObject = function(opt_includeInstance) { + return proto.polykey.v1.identities.OptionalProvider.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.polykey.v1.identities.OptionalProvider} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.polykey.v1.identities.OptionalProvider.toObject = function(includeInstance, msg) { + var f, obj = { + providerId: jspb.Message.getFieldWithDefault(msg, 1, "") + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.polykey.v1.identities.OptionalProvider} + */ +proto.polykey.v1.identities.OptionalProvider.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.polykey.v1.identities.OptionalProvider; + return proto.polykey.v1.identities.OptionalProvider.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.polykey.v1.identities.OptionalProvider} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.polykey.v1.identities.OptionalProvider} + */ +proto.polykey.v1.identities.OptionalProvider.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readString()); + msg.setProviderId(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.polykey.v1.identities.OptionalProvider.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.polykey.v1.identities.OptionalProvider.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.polykey.v1.identities.OptionalProvider} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.polykey.v1.identities.OptionalProvider.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = /** @type {string} */ (jspb.Message.getField(message, 1)); + if (f != null) { + writer.writeString( + 1, + f + ); + } +}; + + +/** + * optional string provider_id = 1; + * @return {string} + */ +proto.polykey.v1.identities.OptionalProvider.prototype.getProviderId = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); +}; + + +/** + * @param {string} value + * @return {!proto.polykey.v1.identities.OptionalProvider} returns this + */ +proto.polykey.v1.identities.OptionalProvider.prototype.setProviderId = function(value) { + return jspb.Message.setOneofField(this, 1, proto.polykey.v1.identities.OptionalProvider.oneofGroups_[0], value); +}; + + +/** + * Clears the field making it undefined. + * @return {!proto.polykey.v1.identities.OptionalProvider} returns this + */ +proto.polykey.v1.identities.OptionalProvider.prototype.clearProviderId = function() { + return jspb.Message.setOneofField(this, 1, proto.polykey.v1.identities.OptionalProvider.oneofGroups_[0], undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.polykey.v1.identities.OptionalProvider.prototype.hasProviderId = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + if (jspb.Message.GENERATE_TO_OBJECT) { diff --git a/src/proto/schemas/polykey/v1/client_service.proto b/src/proto/schemas/polykey/v1/client_service.proto index f545b376f6..eb5aa9ced3 100644 --- a/src/proto/schemas/polykey/v1/client_service.proto +++ b/src/proto/schemas/polykey/v1/client_service.proto @@ -64,6 +64,7 @@ service ClientService { // Identities rpc IdentitiesAuthenticate(polykey.v1.identities.Provider) returns (stream polykey.v1.identities.AuthenticationProcess); + rpc IdentitiesAuthenticatedGet(polykey.v1.identities.OptionalProvider) returns (stream polykey.v1.identities.Provider); rpc IdentitiesTokenPut(polykey.v1.identities.TokenSpecific) returns (polykey.v1.utils.EmptyMessage); rpc IdentitiesTokenGet(polykey.v1.identities.Provider) returns (polykey.v1.identities.Token); rpc IdentitiesTokenDelete(polykey.v1.identities.Provider) returns (polykey.v1.utils.EmptyMessage); diff --git a/src/proto/schemas/polykey/v1/identities/identities.proto b/src/proto/schemas/polykey/v1/identities/identities.proto index ac76c3feba..a671642dc0 100644 --- a/src/proto/schemas/polykey/v1/identities/identities.proto +++ b/src/proto/schemas/polykey/v1/identities/identities.proto @@ -6,6 +6,11 @@ message Provider { string provider_id = 1; string identity_id = 2; } +message OptionalProvider { + oneof optional_provider_id { + string provider_id = 1; + } +} message Token { string token = 1; diff --git a/tests/bin/identities/identities.test.ts b/tests/bin/identities/identities.test.ts index 5755c5d20e..dc4f408be8 100644 --- a/tests/bin/identities/identities.test.ts +++ b/tests/bin/identities/identities.test.ts @@ -552,7 +552,7 @@ describe('CLI Identities', () => { ); }); }); - describe('commandTokens', () => { + describe('commandAuthenticatedGet', () => { test('Should get authenticated identities', async () => { // Need an authenticated identity. await polykeyAgent.identitiesManager.putToken( @@ -560,7 +560,7 @@ describe('CLI Identities', () => { testToken.identityId, testToken.tokenData, ); - const commands = ['identities', 'tokens', '-np', nodePath]; + const commands = ['identities', 'authenticated', '-np', nodePath]; const result = await testBinUtils.pkStdio(commands, {}, dataDir); expect(result.exitCode).toBe(0); // Succeeds. expect(result.stdout).toContain(testToken.providerId); @@ -580,7 +580,7 @@ describe('CLI Identities', () => { ); const commands = [ 'identities', - 'tokens', + 'authenticated', '--provider-id', testToken.providerId, '-np', diff --git a/tests/client/service/identitiesAuthenticatedGet.test.ts b/tests/client/service/identitiesAuthenticatedGet.test.ts index dd023c8805..8e650ca137 100644 --- a/tests/client/service/identitiesAuthenticatedGet.test.ts +++ b/tests/client/service/identitiesAuthenticatedGet.test.ts @@ -10,7 +10,6 @@ import { GRPCServer } from '@/grpc'; import { IdentitiesManager } from '@/identities'; import { GRPCClientClient, ClientServiceService } from '@/client'; import identitiesAuthenticatedGet from '@/client/service/identitiesAuthenticatedGet'; -import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import * as identitiesPB from '@/proto/js/polykey/v1/identities/identities_pb'; import * as nodesUtils from '@/nodes/utils'; import * as clientUtils from '@/client/utils'; @@ -89,7 +88,7 @@ describe('identitiesAuthenticatedGet', () => { user1.identityId, tokenData, ); - const request = new utilsPB.EmptyMessage(); + const request = new identitiesPB.OptionalProvider(); const response = grpcClient.identitiesAuthenticatedGet( request, clientUtils.encodeAuthFromPassword(password), @@ -118,7 +117,7 @@ describe('identitiesAuthenticatedGet', () => { tokenData, ); await identitiesManager.delToken(user1.providerId, user1.identityId); - const request = new utilsPB.EmptyMessage(); + const request = new identitiesPB.OptionalProvider(); const response = grpcClient.identitiesAuthenticatedGet( request, clientUtils.encodeAuthFromPassword(password), @@ -167,7 +166,7 @@ describe('identitiesAuthenticatedGet', () => { user3.identityId, tokenData, ); - const request = new utilsPB.EmptyMessage(); + const request = new identitiesPB.OptionalProvider(); const response = grpcClient.identitiesAuthenticatedGet( request, clientUtils.encodeAuthFromPassword(password), @@ -183,4 +182,55 @@ describe('identitiesAuthenticatedGet', () => { expect(output[1]).toEqual(user2); expect(output[2]).toEqual(user3); }); + test('gets authenticated identities a specific provider', async () => { + // Setup providers + const provider1 = new TestProvider('provider1' as ProviderId); + const provider2 = new TestProvider('provider2' as ProviderId); + const user1 = { + providerId: provider1.id, + identityId: 'user1' as IdentityId, + }; + const user2 = { + providerId: provider1.id, + identityId: 'user2' as IdentityId, + }; + const user3 = { + providerId: provider2.id, + identityId: 'user3' as IdentityId, + }; + provider1.users['user1'] = user1; + provider1.users['user2'] = user2; + provider2.users['user3'] = user3; + identitiesManager.registerProvider(provider1); + identitiesManager.registerProvider(provider2); + await identitiesManager.putToken( + user1.providerId, + user1.identityId, + tokenData, + ); + await identitiesManager.putToken( + user2.providerId, + user2.identityId, + tokenData, + ); + await identitiesManager.putToken( + user3.providerId, + user3.identityId, + tokenData, + ); + const request = new identitiesPB.OptionalProvider(); + request.setProviderId(provider2.id); + const response = grpcClient.identitiesAuthenticatedGet( + request, + clientUtils.encodeAuthFromPassword(password), + ); + const output = Array(); + for await (const providerMessage of response) { + expect(providerMessage).toBeInstanceOf(identitiesPB.Provider); + const obj = providerMessage.toObject(); + output.push(obj); + } + expect(output).toHaveLength(1); + expect(output[0]).toEqual(user3); + }); });