Skip to content

Commit

Permalink
[native] identityRegisterUsernameAccount function
Browse files Browse the repository at this point in the history
Summary: introduce function that uses useIdentityRegister hook to register user with identity service

Test Plan: successfully registered new user with identity service. also confirmed that all the error cases are handled by displaying the correct alert.

Reviewers: ashoat

Reviewed By: ashoat

Subscribers: kamil

Differential Revision: https://phab.comm.dev/D10581
  • Loading branch information
vdhanan committed Jan 17, 2024
1 parent dd75776 commit 8179b46
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 22 deletions.
2 changes: 2 additions & 0 deletions lib/types/identity-service-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,5 @@ export type IdentityRegisterResult = {
+accessToken: string,
+username: string,
};

export const ONE_TIME_KEYS_NUMBER = 10;
16 changes: 16 additions & 0 deletions lib/types/redux-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import type {
CalendarThreadFilter,
SetCalendarDeletedFilterPayload,
} from './filter-types.js';
import type { IdentityRegisterResult } from './identity-service-types.js';
import type { IntegrityStore } from './integrity-types.js';
import type {
KeyserverStore,
Expand Down Expand Up @@ -374,6 +375,21 @@ export type BaseAction =
+payload: RegisterResult,
+loadingInfo: LoadingInfo,
}
| {
+type: 'IDENTITY_REGISTER_STARTED',
+payload?: void,
+loadingInfo: LoadingInfo,
}
| {
+type: 'IDENTITY_REGISTER_FAILED',
+payload: Error,
+loadingInfo: LoadingInfo,
}
| {
+type: 'IDENTITY_REGISTER_SUCCESS',
+payload: IdentityRegisterResult,
+loadingInfo: LoadingInfo,
}
| {
+type: 'CHANGE_KEYSERVER_USER_PASSWORD_STARTED',
+payload?: void,
Expand Down
15 changes: 9 additions & 6 deletions native/account/register-panel.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@ import SWMansionIcon from '../components/swmansion-icon.react.js';
import { useSelector } from '../redux/redux-utils.js';
import { nativeLogInExtraInfoSelector } from '../selectors/account-selectors.js';
import type { KeyPressEvent } from '../types/react-native.js';
import { AppOutOfDateAlertDetails } from '../utils/alert-messages.js';
import {
AppOutOfDateAlertDetails,
UsernameReservedAlertDetails,
UsernameTakenAlertDetails,
} from '../utils/alert-messages.js';
import Alert from '../utils/alert.js';
import { nativeNotificationsSessionCreator } from '../utils/crypto-utils.js';
import { type StateContainer } from '../utils/state-container.js';
Expand Down Expand Up @@ -365,16 +369,15 @@ class RegisterPanel extends React.PureComponent<Props, State> {
} catch (e) {
if (e.message === 'username_reserved') {
Alert.alert(
'Username reserved',
'This username is currently reserved. Please contact support@' +
'comm.app if you would like to claim this account.',
UsernameReservedAlertDetails.title,
UsernameReservedAlertDetails.message,
[{ text: 'OK', onPress: this.onUsernameAlertAcknowledged }],
{ cancelable: false },
);
} else if (e.message === 'username_taken') {
Alert.alert(
'Username taken',
'An account with that username already exists',
UsernameTakenAlertDetails.title,
UsernameTakenAlertDetails.message,
[{ text: 'OK', onPress: this.onUsernameAlertAcknowledged }],
{ cancelable: false },
);
Expand Down
97 changes: 81 additions & 16 deletions native/account/registration/registration-server-call.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import { setDataLoadedActionType } from 'lib/actions/client-db-store-actions.js'
import {
keyserverRegisterActionTypes,
keyserverRegister,
useIdentityRegister,
identityRegisterActionTypes,
} from 'lib/actions/user-actions.js';
import type { LogInStartingPayload } from 'lib/types/account-types.js';
import { useServerCall } from 'lib/utils/action-utils.js';
import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js';
import { useDispatch } from 'lib/utils/redux-utils.js';
import { usingCommServicesAccessToken } from 'lib/utils/services-utils.js';
import { setURLPrefix } from 'lib/utils/url-utils.js';

import type {
Expand All @@ -24,7 +27,11 @@ import {
} from '../../avatars/avatar-hooks.js';
import { useSelector } from '../../redux/redux-utils.js';
import { nativeLogInExtraInfoSelector } from '../../selectors/account-selectors.js';
import { AppOutOfDateAlertDetails } from '../../utils/alert-messages.js';
import {
AppOutOfDateAlertDetails,
UsernameReservedAlertDetails,
UsernameTakenAlertDetails,
} from '../../utils/alert-messages.js';
import Alert from '../../utils/alert.js';
import { setNativeCredentials } from '../native-credentials.js';
import { useSIWEServerCall } from '../siwe-hooks.js';
Expand Down Expand Up @@ -59,17 +66,62 @@ function useRegistrationServerCall(): RegistrationServerCallInput => Promise<voi
const logInExtraInfo = useSelector(nativeLogInExtraInfoSelector);

const dispatchActionPromise = useDispatchActionPromise();
const callRegister = useServerCall(keyserverRegister);
const callKeyserverRegister = useServerCall(keyserverRegister);
const callIdentityRegister = useIdentityRegister();

const identityRegisterUsernameAccount = React.useCallback(
async (accountSelection: UsernameAccountSelection) => {
const identityRegisterPromise = (async () => {
try {
const result = await callIdentityRegister(
accountSelection.username,
accountSelection.password,
);
await setNativeCredentials({
username: accountSelection.username,
password: accountSelection.password,
});
return result;
} catch (e) {
if (e.message === 'username reserved') {
Alert.alert(
UsernameReservedAlertDetails.title,
UsernameReservedAlertDetails.message,
);
} else if (e.message === 'username already exists') {
Alert.alert(
UsernameTakenAlertDetails.title,
UsernameTakenAlertDetails.message,
);
} else if (e.message === 'Unsupported version') {
Alert.alert(
AppOutOfDateAlertDetails.title,
AppOutOfDateAlertDetails.message,
);
} else {
Alert.alert('Unknown error', 'Uhh... try again?');
}
throw e;
}
})();
void dispatchActionPromise(
identityRegisterActionTypes,
identityRegisterPromise,
);
await identityRegisterPromise;
},
[callIdentityRegister, dispatchActionPromise],
);

const registerUsernameAccount = React.useCallback(
const keyserverRegisterUsernameAccount = React.useCallback(
async (
accountSelection: UsernameAccountSelection,
keyserverURL: string,
) => {
const extraInfo = await logInExtraInfo();
const registerPromise = (async () => {
const keyserverRegisterPromise = (async () => {
try {
const result = await callRegister(
const result = await callKeyserverRegister(
{
...extraInfo,
username: accountSelection.username,
Expand All @@ -87,14 +139,13 @@ function useRegistrationServerCall(): RegistrationServerCallInput => Promise<voi
} catch (e) {
if (e.message === 'username_reserved') {
Alert.alert(
'Username reserved',
'This username is currently reserved. Please contact support@' +
'comm.app if you would like to claim this account.',
UsernameReservedAlertDetails.title,
UsernameReservedAlertDetails.message,
);
} else if (e.message === 'username_taken') {
Alert.alert(
'Username taken',
'An account with that username already exists',
UsernameTakenAlertDetails.title,
UsernameTakenAlertDetails.message,
);
} else if (e.message === 'client_version_unsupported') {
Alert.alert(
Expand All @@ -109,13 +160,13 @@ function useRegistrationServerCall(): RegistrationServerCallInput => Promise<voi
})();
void dispatchActionPromise(
keyserverRegisterActionTypes,
registerPromise,
keyserverRegisterPromise,
undefined,
({ calendarQuery: extraInfo.calendarQuery }: LogInStartingPayload),
);
await registerPromise;
await keyserverRegisterPromise;
},
[logInExtraInfo, callRegister, dispatchActionPromise],
[logInExtraInfo, callKeyserverRegister, dispatchActionPromise],
);

const siweServerCall = useSIWEServerCall();
Expand All @@ -130,8 +181,16 @@ function useRegistrationServerCall(): RegistrationServerCallInput => Promise<voi
return;
}
const { accountSelection, avatarData, keyserverURL } = input;
if (accountSelection.accountType === 'username') {
await registerUsernameAccount(accountSelection, keyserverURL);
if (
accountSelection.accountType === 'username' &&
!usingCommServicesAccessToken
) {
await keyserverRegisterUsernameAccount(
accountSelection,
keyserverURL,
);
} else if (accountSelection.accountType === 'username') {
await identityRegisterUsernameAccount(accountSelection);
} else {
try {
await siweServerCall(accountSelection, {
Expand All @@ -157,7 +216,13 @@ function useRegistrationServerCall(): RegistrationServerCallInput => Promise<voi
}
},
),
[currentStep, registerUsernameAccount, siweServerCall, dispatch],
[
currentStep,
keyserverRegisterUsernameAccount,
identityRegisterUsernameAccount,
siweServerCall,
dispatch,
],
);

// STEP 2: SETTING AVATAR
Expand Down
30 changes: 30 additions & 0 deletions native/identity-service/identity-service-context-provider.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

import * as React from 'react';

import { getOneTimeKeyArray } from 'lib/shared/crypto-utils.js';
import { IdentityClientContext } from 'lib/shared/identity-client-context.js';
import type {
IdentityServiceClient,
OutboundKeyInfoResponse,
UserLoginResponse,
} from 'lib/types/identity-service-types.js';
import { ONE_TIME_KEYS_NUMBER } from 'lib/types/identity-service-types.js';

import { getCommServicesAuthMetadataEmitter } from '../event-emitters/csa-auth-metadata-emitter.js';
import { commCoreModule, commRustModule } from '../native-modules.js';
Expand Down Expand Up @@ -87,6 +89,34 @@ function IdentityServiceContextProvider(props: Props): React.Node {
}
return resultObject;
},
registerUser: async (username: string, password: string) => {
await commCoreModule.initializeCryptoAccount();
const [
{ blobPayload, signature },
notificationsOneTimeKeys,
primaryOneTimeKeys,
prekeys,
] = await Promise.all([
commCoreModule.getUserPublicKey(),
commCoreModule.getNotificationsOneTimeKeys(ONE_TIME_KEYS_NUMBER),
commCoreModule.getPrimaryOneTimeKeys(ONE_TIME_KEYS_NUMBER),
commCoreModule.generateAndGetPrekeys(),
]);
const registrationResult = await commRustModule.registerUser(
username,
password,
blobPayload,
signature,
prekeys.contentPrekey,
prekeys.contentPrekeySignature,
prekeys.notifPrekey,
prekeys.notifPrekeySignature,
getOneTimeKeyArray(primaryOneTimeKeys),
getOneTimeKeyArray(notificationsOneTimeKeys),
);
const { userID, accessToken } = JSON.parse(registrationResult);
return { accessToken, userID, username };
},
};
}, [getAuthMetadata]);

Expand Down
12 changes: 12 additions & 0 deletions native/utils/alert-messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,15 @@ export const AppOutOfDateAlertDetails: AlertDetails = {
'Your app version is pretty old, and the server doesn’t know how ' +
`to speak to it anymore. Please use the ${platformStore} to update!`,
};

export const UsernameReservedAlertDetails: AlertDetails = {
title: 'Username reserved',
message:
'This username is currently reserved. Please contact support@' +
'comm.app if you would like to claim this account.',
};

export const UsernameTakenAlertDetails: AlertDetails = {
title: 'Username taken',
message: 'An account with that username already exists',
};

0 comments on commit 8179b46

Please sign in to comment.