+
{children}
+ {helperElement}
);
}
diff --git a/ts/state/ducks/standaloneInstaller.preload.ts b/ts/state/ducks/standaloneInstaller.preload.ts
index 06c2829abb..136e5008d1 100644
--- a/ts/state/ducks/standaloneInstaller.preload.ts
+++ b/ts/state/ducks/standaloneInstaller.preload.ts
@@ -795,21 +795,14 @@ export function verifyPIN({
};
dispatch(updateWorkflow(workflow));
} else if (error === 'missing') {
- log.warn(`${logId}: Nothing in SVR for this user!`);
+ log.error(`${logId}: Nothing in SVR for this user!`);
if (dataForReglockAccountCreate) {
// Something has really gone wrong - we're in reglock, but SVR has nothing for us
dispatch(updateWorkflow(workflow, FatalErrorType.UNEXPECTED));
} else {
// No reglock and nothing in SVR - let's allow the user to create a new PIN
- workflow = {
- ...workflow,
- status: {
- type: 'failed',
- error: 'nothing-in-svr',
- },
- };
- dispatch(updateWorkflow(workflow));
+ dispatch(goToCreatePINStage());
}
} else {
const unknownError: never = error;
diff --git a/ts/test-mock/standalone/registration_test.node.ts b/ts/test-mock/standalone/registration_test.node.ts
index 93304e68c4..6a3fb26d20 100644
--- a/ts/test-mock/standalone/registration_test.node.ts
+++ b/ts/test-mock/standalone/registration_test.node.ts
@@ -9,6 +9,7 @@ import { Bootstrap } from '../bootstrap.node.ts';
import { MINUTE } from '../../util/durations/index.std.ts';
import { typeIntoInput } from '../helpers.node.ts';
import { assert } from 'chai';
+import { randomBytes } from 'node:crypto';
export const debug = createDebug('mock:test:registration');
@@ -34,9 +35,7 @@ describe('registration', function (this: Mocha.Suite) {
await bootstrap.teardown();
});
- it('should create totally new account, creating a new PIN with SVR2', async () => {
- this.timeout(10000);
-
+ it('should create new account, creating a new PIN with SVR2', async () => {
const window = await app.getWindow();
{
@@ -71,9 +70,9 @@ describe('registration', function (this: Mocha.Suite) {
{
debug('VERIFICATION_CODE: enter code');
- const code = '111111';
- for (let i = 0; i < code.length; i += 1) {
- const char = code[i];
+ const CODE = '111111';
+ for (let i = 0; i < CODE.length; i += 1) {
+ const char = CODE[i];
if (!char) {
continue;
}
@@ -90,32 +89,151 @@ describe('registration', function (this: Mocha.Suite) {
debug('PROFILE_ENTRY: enter first name');
const firstNameInput = window.getByPlaceholder('First name (required)');
await typeIntoInput(firstNameInput, 'John', '');
- }
- {
- debug('PROFILE_ENTRY: complete');
await window.getByRole('button', { name: 'Continue' }).click();
}
- const pin = '876543';
+ const PIN = '876543';
{
debug('CREATE_PIN: enter pin');
const phoneInput = window.getByPlaceholder('Create your PIN');
- await typeIntoInput(phoneInput, pin, '');
+ await typeIntoInput(phoneInput, PIN, '');
+
await window.getByRole('button', { name: 'Continue' }).click();
}
{
debug('CREATE_PIN_CONFIRM: enter pin again');
const phoneInput = window.getByPlaceholder('Enter your PIN');
- await typeIntoInput(phoneInput, pin, '');
+ await typeIntoInput(phoneInput, PIN, '');
+
await window.getByRole('button', { name: 'Continue' }).click();
}
- const storedData = await app.getSvr2StoreParameters();
- assert.strictEqual(storedData?.pin, pin);
+ {
+ debug('COMPLETE: Verify data was stored in SVR');
+ const storedData = await app.getSvr2StoreParameters();
+ assert.strictEqual(storedData?.pin, PIN);
+ }
- await expect(window.getByText('Welcome to Signal')).toBeVisible();
+ {
+ debug('COMPLETE: verify welcome screen');
+ await expect(window.getByText('Welcome to Signal')).toBeVisible();
+ }
+ });
+
+ it('should reregister account, verifying PIN with SVR2', async () => {
+ const window = await app.getWindow();
+ const { server } = bootstrap;
+
+ {
+ debug('PHONE_NUMBER: Enter phone number');
+ const phoneInput = window.getByPlaceholder('Phone number');
+ await typeIntoInput(phoneInput, '+14155551111', '');
+ await window.getByRole('button', { name: 'Continue' }).click();
+ }
+
+ {
+ debug('PHONE_NUMBER: Confirm phone number');
+ const dialogText = window.getByText(
+ 'Is your phone number above correct?'
+ );
+ await expect(dialogText).toBeVisible();
+
+ await window.getByRole('button', { name: 'Yes' }).click();
+ }
+
+ {
+ debug('CAPTCHA: kick off validation');
+ await window.getByRole('button', { name: 'Verify in Browser' }).click();
+ }
+
+ {
+ debug('CAPTCHA: complete validation');
+ const { seq, reason } = await app.waitForChallenge();
+ assert.strictEqual(reason, 'standalone registration');
+
+ await app.solveChallenge({ seq, data: { captcha: 'unused' } });
+ }
+
+ {
+ debug('VERIFICATION_CODE: enter code');
+ const CODE = '111111';
+ for (let i = 0; i < CODE.length; i += 1) {
+ const char = CODE[i];
+ if (!char) {
+ continue;
+ }
+
+ const codeInput = window.getByLabel(`Character ${i + 1} of 6`);
+ // oxlint-disable-next-line no-await-in-loop
+ await typeIntoInput(codeInput, char, '');
+ }
+
+ // Force server to return storageCapable: true
+ server.setRegisterResponseData({ storageCapable: true });
+
+ await window.getByRole('button', { name: 'Continue' }).click();
+ }
+
+ {
+ debug('PROFILE_ENTRY: enter first name');
+ const firstNameInput = window.getByPlaceholder('First name (required)');
+ await typeIntoInput(firstNameInput, 'John', '');
+
+ await window.getByRole('button', { name: 'Continue' }).click();
+ }
+
+ {
+ debug('VERIFY_PIN: enter incorrect PIN');
+
+ const INCORRECT_PIN = '123456';
+
+ const phoneInput = window.getByPlaceholder('Enter your PIN');
+ await typeIntoInput(phoneInput, INCORRECT_PIN, '');
+
+ await app.saveSVR2RestoreResponse({
+ success: false,
+ error: 'pin-incorrect',
+ triesRemaining: 3,
+ });
+
+ await window.getByRole('button', { name: 'Continue' }).click();
+ }
+
+ {
+ debug('VERIFY_PIN: dismiss dialog');
+ await expect(
+ window.getByText('You have 3 attempts remaining')
+ ).toBeVisible();
+
+ await window.getByRole('button', { name: 'OK' }).click();
+ }
+
+ {
+ debug('VERIFY_PIN: enter correct PIN');
+
+ const CORRECT_PIN = '876543';
+ const DATA = randomBytes(32);
+
+ const phoneInput = window.getByPlaceholder('Enter your PIN');
+
+ await phoneInput.clear();
+ await typeIntoInput(phoneInput, CORRECT_PIN, '');
+
+ await app.saveSVR2RestoreResponse({
+ success: true,
+ data: DATA,
+ triesRemaining: 3,
+ });
+
+ await window.getByRole('button', { name: 'Continue' }).click();
+ }
+
+ {
+ debug('COMPLETE: verify welcome screen');
+ await expect(window.getByText('Welcome to Signal')).toBeVisible();
+ }
});
});
diff --git a/ts/types/StandaloneRegistration.std.ts b/ts/types/StandaloneRegistration.std.ts
index 0542140f0b..598b09579a 100644
--- a/ts/types/StandaloneRegistration.std.ts
+++ b/ts/types/StandaloneRegistration.std.ts
@@ -312,7 +312,7 @@ export type VerifyPINStage = {
| {
type: 'in-progress';
}
- | { type: 'failed'; error: 'nothing-in-svr' };
+ | { type: 'failed'; error: 'incorrect-pin' };
// After VERIFY_PIN:
// - save PIN in local storage