diff --git a/lib/types/identity-service-types.js b/lib/types/identity-service-types.js --- a/lib/types/identity-service-types.js +++ b/lib/types/identity-service-types.js @@ -172,6 +172,7 @@ ) => Promise<$ReadOnlyArray>; +linkFarcasterAccount: (farcasterID: string) => Promise; +unlinkFarcasterAccount: () => Promise; + +findUserIdentities: (userIDs: $ReadOnlyArray) => Promise; } export type IdentityServiceAuthLayer = { @@ -230,6 +231,37 @@ +[userID: string]: RawDeviceList, }; +// User Identity types + +export type EthereumIdentity = { + walletAddress: string, + siweMessage: string, + siweSignature: string, +}; +export type Identity = { + +username: string, + +ethIdentity: ?EthereumIdentity, + +farcasterId: ?string, +}; +export type Identities = { + +[userID: string]: Identity, +}; +export const ethereumIdentityObjectValidator: TInterface = + tShape({ + walletAddress: t.String, + siweMessage: t.String, + siweSignature: t.String, + }); +export const identityValidator: TInterface = tShape({ + username: t.String, + ethIdentity: t.maybe(ethereumIdentityObjectValidator), + farcasterId: t.maybe(t.String), +}); +export const identitiesValidator: TDict = t.dict( + t.String, + identityValidator, +); + export type SignedDeviceList = { // JSON-stringified RawDeviceList +rawDeviceList: string, diff --git a/native/identity-service/identity-service-context-provider.react.js b/native/identity-service/identity-service-context-provider.react.js --- a/native/identity-service/identity-service-context-provider.react.js +++ b/native/identity-service/identity-service-context-provider.react.js @@ -27,6 +27,7 @@ type UserDevicesOlmOutboundKeys, type UsersSignedDeviceLists, usersSignedDeviceListsValidator, + identitiesValidator, } from 'lib/types/identity-service-types.js'; import { getContentSigningKey } from 'lib/utils/crypto-utils.js'; import { assertWithValidator } from 'lib/utils/validation-utils.js'; @@ -615,6 +616,21 @@ } = await getAuthMetadata(); return commRustModule.unlinkFarcasterAccount(userID, deviceID, token); }, + findUserIdentities: async (userIDs: $ReadOnlyArray) => { + const { + deviceID, + userID, + accessToken: token, + } = await getAuthMetadata(); + const result = await commRustModule.findUserIdentities( + userID, + deviceID, + token, + userIDs, + ); + const identities = JSON.parse(result); + return assertWithValidator(identities, identitiesValidator); + }, }), [getAuthMetadata], ); diff --git a/web/grpc/identity-service-client-wrapper.js b/web/grpc/identity-service-client-wrapper.js --- a/web/grpc/identity-service-client-wrapper.js +++ b/web/grpc/identity-service-client-wrapper.js @@ -30,6 +30,8 @@ farcasterUsersValidator, type UsersSignedDeviceLists, usersSignedDeviceListsValidator, + type Identities, + identitiesValidator, } from 'lib/types/identity-service-types.js'; import { getMessageForException } from 'lib/utils/errors.js'; import { assertWithValidator } from 'lib/utils/validation-utils.js'; @@ -615,6 +617,28 @@ } await client.unlinkFarcasterAccount(new Empty()); }; + + findUserIdentities: (userIDs: $ReadOnlyArray) => Promise = + async userIDs => { + const client = this.authClient; + if (!client) { + throw new Error('Identity service client is not initialized'); + } + const request = new IdentityAuthStructs.UserIdentitiesRequest(); + request.setUserIdsList([...userIDs]); + const response = await client.findUserIdentities(request); + const identityObjects = response.toObject()?.identitiesMap; + + let identities: Identities = {}; + identityObjects.forEach(([userID, identityObject]) => { + identities = { + ...identities, + [userID]: identityObject, + }; + }); + + return assertWithValidator(identities, identitiesValidator); + }; } function authNewDeviceKeyUpload( diff --git a/web/grpc/identity-service-context-provider.react.js b/web/grpc/identity-service-context-provider.react.js --- a/web/grpc/identity-service-context-provider.react.js +++ b/web/grpc/identity-service-context-provider.react.js @@ -138,6 +138,7 @@ getFarcasterUsers: proxyMethodToWorker('getFarcasterUsers'), linkFarcasterAccount: proxyMethodToWorker('linkFarcasterAccount'), unlinkFarcasterAccount: proxyMethodToWorker('unlinkFarcasterAccount'), + findUserIdentities: proxyMethodToWorker('findUserIdentities'), }; }, [proxyMethodToWorker]);