зеркало из https://github.com/mozilla/fxa.git
recovery code(s) > backup authentication code(s)
Update text on 2fa enter code to confirm screen
This commit is contained in:
Родитель
f28e95071b
Коммит
687fedd36f
|
@ -8,12 +8,12 @@
|
|||
|
||||
Firefox Account originally implemented multi-factor authentication (MFA) support in Q1 of 2018.
|
||||
This feature used TOTP based codes and was based on RFC 6238.
|
||||
Additionally, if users lost their MFA device, they could use one time recovery codes to regain access to the account.
|
||||
Additionally, if users lost their MFA device, they could use one time backup authentication codes to regain access to the account.
|
||||
|
||||
Having MFA support has helped secure our users' accounts and given them more security flexibility.
|
||||
However, over time it has become more obvious that users that lose their MFA device (usually phone) are at risk of getting locked out of their account because they don't save their recovery codes.
|
||||
There are a non-trivial amount of users that don’t save or download their recovery codes, which is currently the only way they can regain access.
|
||||
In 2019 Q4, FxA started requiring that users confirm recovery codes before enabling MFA.
|
||||
However, over time it has become more obvious that users that lose their MFA device (usually phone) are at risk of getting locked out of their account because they don't save their backup authentication codes.
|
||||
There are a non-trivial amount of users that don’t save or download their backup authentication codes, which is currently the only way they can regain access.
|
||||
In 2019 Q4, FxA started requiring that users confirm backup authentication codes before enabling MFA.
|
||||
While this did help reduce lockouts, we still want to reduce it further.
|
||||
|
||||
We believe that adding a new MFA method to Firefox Accounts that has the similar security properties as TOTP would allow users to have another method to recover their account.
|
||||
|
@ -21,7 +21,7 @@ We believe that adding a new MFA method to Firefox Accounts that has the similar
|
|||
## Decision Drivers
|
||||
|
||||
- Improve user's account security
|
||||
- Reduce the risk of account lockout because of lost device/recovery code
|
||||
- Reduce the risk of account lockout because of lost device/backup authentication code
|
||||
- Could be completed in roughly a quarter
|
||||
|
||||
## Considered Options
|
||||
|
@ -54,7 +54,7 @@ There is less security risk to users if this feature is added.
|
|||
### Option B - Implement SMS as opt-in backup method
|
||||
|
||||
- Description
|
||||
- Add the ability to have users send a recovery code to a phone number associated to the account, which could then be used to recover the account.
|
||||
- Add the ability to have users send a backup authentication code to a phone number associated to the account, which could then be used to recover the account.
|
||||
- Pros
|
||||
- Common account recovery pattern used on many sites
|
||||
- Less UX unknowns
|
||||
|
|
|
@ -54,7 +54,7 @@ test.describe('severity-1 #smoke', () => {
|
|||
});
|
||||
|
||||
// https://testrail.stage.mozaws.net/index.php?/cases/view/1293450
|
||||
test('can change recovery codes #1293450', async ({
|
||||
test('can change backup authentication codes #1293450', async ({
|
||||
credentials,
|
||||
page,
|
||||
pages: { settings, totp, login },
|
||||
|
@ -78,7 +78,7 @@ test.describe('severity-1 #smoke', () => {
|
|||
});
|
||||
|
||||
// https://testrail.stage.mozaws.net/index.php?/cases/view/1293460
|
||||
test('can get new recovery codes via email #1293460', async ({
|
||||
test('can get new backup authentication codes via email #1293460', async ({
|
||||
target,
|
||||
credentials,
|
||||
pages: { page, login, settings, totp },
|
||||
|
|
|
@ -1675,18 +1675,18 @@ const conf = convict({
|
|||
},
|
||||
recoveryCodes: {
|
||||
length: {
|
||||
doc: 'The length of a recovery code',
|
||||
doc: 'The length of a backup authentication code',
|
||||
default: 10,
|
||||
format: 'nat',
|
||||
env: 'RECOVERY_CODE_LENGTH',
|
||||
},
|
||||
count: {
|
||||
doc: 'Number of recovery codes to create',
|
||||
doc: 'Number of backup authentication codes to create',
|
||||
default: 8,
|
||||
env: 'RECOVERY_CODE_COUNT',
|
||||
},
|
||||
notifyLowCount: {
|
||||
doc: 'Notify the user when there are less than these many recovery codes',
|
||||
doc: 'Notify the user when there are less than these many backup authentication codes',
|
||||
default: 2,
|
||||
env: 'RECOVERY_CODE_NOTIFY_LOW_COUNT',
|
||||
},
|
||||
|
|
|
@ -37,9 +37,9 @@ as follows:
|
|||
|
||||
- User completes an email confirmation loop to confirm password reset.
|
||||
- This produces an `accountResetToken`, a credential for subsequent requests.
|
||||
- User retrieves recovery code from print out or downloaded file,
|
||||
- User retrieves backup authentication code from print out or downloaded file,
|
||||
and provides it to FxA web-content in the password reset flow.
|
||||
- FxA web-content uses the recovery code to derive the fingerprint
|
||||
- FxA web-content uses the backup authentication code to derive the fingerprint
|
||||
and encryption key (recover-kid and recover-enc as defined above).
|
||||
- FxA web-content requests recover-data from FxA server, providing recover-kid.
|
||||
- `GET /recoveryKey/:recoveryKeyId`, authenticated with `accountResetToken`.
|
||||
|
|
|
@ -65,7 +65,7 @@ export const AUTH_SERVER_API_DESCRIPTION = {
|
|||
| 400 | 102 | Unknown account |
|
||||
| 400 | 103 | Incorrect password |
|
||||
| 400 | 104 | Unverified account |
|
||||
| 400 | 105 | Invalid verification code |
|
||||
| 400 | 105 | Invalid authentication code |
|
||||
| 400 | 106 | Invalid JSON in request body |
|
||||
| 400 | 107 | Invalid parameter in request body |
|
||||
| 400 | 108 | Missing parameter in request body |
|
||||
|
@ -107,16 +107,16 @@ export const AUTH_SERVER_API_DESCRIPTION = {
|
|||
| 400 | 150 | Can not resend email code to an email that does not belong to this account |
|
||||
| 500 | 151 | Failed to send email |
|
||||
| 422 | 151 | Failed to send email |
|
||||
| 400 | 152 | Invalid token verification code |
|
||||
| 400 | 153 | Expired token verification code |
|
||||
| 400 | 152 | Invalid token authentication code |
|
||||
| 400 | 153 | Expired token authentication code |
|
||||
| 400 | 154 | TOTP token already exists for this account. |
|
||||
| 400 | 155 | TOTP token not found. |
|
||||
| 400 | 156 | Recovery code not found. |
|
||||
| 400 | 156 | Backup authentication code not found. |
|
||||
| 400 | 157 | Unavailable device command. |
|
||||
| 400 | 158 | Account recovery key not found. |
|
||||
| 400 | 159 | Account recovery key is not valid. |
|
||||
| 400 | 158 | Account recovery key not found. |
|
||||
| 400 | 159 | Account recovery key is not valid. |
|
||||
| 400 | 160 | This request requires two step authentication enabled on your account. |
|
||||
| 400 | 161 | Account recovery key already exists. |
|
||||
| 400 | 161 | Account recovery key already exists. |
|
||||
| 400 | 162 | Unknown client_id |
|
||||
| 400 | 164 | Stale auth timestamp |
|
||||
| 409 | 165 | Redis WATCH detected a conflicting update |
|
||||
|
|
|
@ -16,7 +16,7 @@ const RECOVERYCODES_GET = {
|
|||
dedent`
|
||||
🔒 Authenticated with session token
|
||||
|
||||
Return new recovery codes while removing old ones.
|
||||
Return new backup authentication codes while removing old ones.
|
||||
`,
|
||||
],
|
||||
};
|
||||
|
@ -33,7 +33,7 @@ const SESSION_VERIFY_RECOVERYCODE_POST = {
|
|||
dedent`
|
||||
🔒 Authenticated with session token
|
||||
|
||||
Verify a session using a recovery code.
|
||||
Verify a session using a backup authentication code.
|
||||
`,
|
||||
],
|
||||
};
|
||||
|
|
|
@ -11,7 +11,7 @@ const TAGS = {
|
|||
OAUTH: ['api', 'Oauth'],
|
||||
OAUTH_SERVER: ['api', 'OAuth Server API Overview'],
|
||||
PASSWORD: ['api', 'Password'],
|
||||
RECOVERY_CODES: ['api', 'Recovery codes'],
|
||||
RECOVERY_CODES: ['api', 'Backup authentication codes'],
|
||||
RECOVERY_KEY: ['api', 'Account recovery key'],
|
||||
SECURITY_EVENTS: ['api', 'Security events'],
|
||||
SESSION: ['api', 'Session'],
|
||||
|
|
|
@ -1047,7 +1047,7 @@ AppError.recoveryCodeNotFound = () => {
|
|||
code: 400,
|
||||
error: 'Bad Request',
|
||||
errno: ERRNO.RECOVERY_CODE_NOT_FOUND,
|
||||
message: 'Recovery code not found.',
|
||||
message: 'Backup authentication code not found.',
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ module.exports = (log, db, config, customs, mailer) => {
|
|||
const codeConfig = config.recoveryCodes;
|
||||
const RECOVERY_CODE_COUNT = (codeConfig && codeConfig.count) || 8;
|
||||
|
||||
// Validate recovery codes
|
||||
// Validate backup authentication codes
|
||||
const recoveryCodesSchema = validators.recoveryCodes(
|
||||
RECOVERY_CODE_COUNT,
|
||||
RECOVERY_CODE_SANE_MAX_LENGTH
|
||||
|
@ -39,8 +39,8 @@ module.exports = (log, db, config, customs, mailer) => {
|
|||
|
||||
const { authenticatorAssuranceLevel, uid } = request.auth.credentials;
|
||||
|
||||
// Since TOTP and recovery codes go hand in hand, you should only be
|
||||
// able to replace recovery codes in a TOTP verified session.
|
||||
// Since TOTP and backup authentication codes go hand in hand, you should only be
|
||||
// able to replace backup authentication codes in a TOTP verified session.
|
||||
if (!authenticatorAssuranceLevel || authenticatorAssuranceLevel <= 1) {
|
||||
throw errors.unverifiedSession();
|
||||
}
|
||||
|
@ -94,8 +94,8 @@ module.exports = (log, db, config, customs, mailer) => {
|
|||
|
||||
const { authenticatorAssuranceLevel, uid } = request.auth.credentials;
|
||||
|
||||
// Since TOTP and recovery codes go hand in hand, you should only be
|
||||
// able to replace recovery codes in a TOTP verified session.
|
||||
// Since TOTP and backup authentication codes go hand in hand, you should only be
|
||||
// able to replace backup authentication codes in a TOTP verified session.
|
||||
if (!authenticatorAssuranceLevel || authenticatorAssuranceLevel <= 1) {
|
||||
throw errors.unverifiedSession();
|
||||
}
|
||||
|
@ -138,7 +138,7 @@ module.exports = (log, db, config, customs, mailer) => {
|
|||
validate: {
|
||||
payload: isA.object({
|
||||
// Validation here is done with BASE_36 superset to be backwards compatible...
|
||||
// Ideally all recovery codes are Crockford Base32.
|
||||
// Ideally all backup authentication codes are Crockford Base32.
|
||||
code: validators.recoveryCode(
|
||||
RECOVERY_CODE_SANE_MAX_LENGTH,
|
||||
validators.BASE_36
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
# The user has a low number of valid recovery codes remaining for use
|
||||
codes-reminder-title = Low recovery codes remaining
|
||||
codes-reminder-description = We noticed that you are running low on recovery codes. Please consider generating new codes to avoid getting locked out of your account.
|
||||
# The user has a low number of valid backup authentication codes remaining for use
|
||||
codes-reminder-title = Low backup authentication codes remaining
|
||||
codes-reminder-description = We noticed that you are running low on backup authentication codes. Please consider generating new codes to avoid getting locked out of your account.
|
||||
codes-generate = Generate codes
|
||||
codes-generate-plaintext = { codes-generate }:
|
||||
lowRecoveryCodes-action = Generate codes
|
||||
lowRecoveryCodes-subject =
|
||||
{ $numberRemaining ->
|
||||
[one] 1 recovery code remaining
|
||||
*[other] { $numberRemaining } recovery codes remaining
|
||||
[one] 1 backup authentication code remaining
|
||||
*[other] { $numberRemaining } backup authentication codes remaining
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@ import { GlobalTemplateValues } from '../../../renderer';
|
|||
|
||||
const getSubject = (numberRemaining: number) =>
|
||||
numberRemaining === 1
|
||||
? '1 recovery code remaining'
|
||||
: '<%= numberRemaining %> recovery codes remaining';
|
||||
? '1 backup authentication code remaining'
|
||||
: '<%= numberRemaining %> backup authentication codes remaining';
|
||||
|
||||
export const getIncludes = (numberRemaining: number): GlobalTemplateValues => ({
|
||||
subject: {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<mj-section>
|
||||
<mj-column>
|
||||
<mj-text css-class="text-header">
|
||||
<span data-l10n-id="codes-reminder-title">Low recovery codes remaining</span>
|
||||
<span data-l10n-id="codes-reminder-title">Low backup authentication codes remaining</span>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
|
@ -13,7 +13,7 @@
|
|||
<mj-section>
|
||||
<mj-column>
|
||||
<mj-text css-class="text-body">
|
||||
<span data-l10n-id="codes-reminder-description">We noticed that you are running low on recovery codes. Please consider generating new codes to avoid getting locked out of your account.</span>
|
||||
<span data-l10n-id="codes-reminder-description">We noticed that you are running low on backup authentication codes. Please consider generating new codes to avoid getting locked out of your account.</span>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
|
|
|
@ -11,7 +11,7 @@ export default {
|
|||
|
||||
const createStory = storyWithProps(
|
||||
'lowRecoveryCodes',
|
||||
'Sent when a user has 2 or less recovery codes remaining.',
|
||||
'Sent when a user has 2 or less backup authentication codes remaining.',
|
||||
{
|
||||
link: 'http://localhost:3030/settings/two_step_authentication/replace_codes?low_recovery_codes=true',
|
||||
numberRemaining: 1,
|
||||
|
@ -22,12 +22,12 @@ export const LowRecoveryCodesOne = createStory(
|
|||
{
|
||||
numberRemaining: 1,
|
||||
},
|
||||
'User has 1 recovery code remaining'
|
||||
'User has 1 backup authentication code remaining'
|
||||
);
|
||||
|
||||
export const LowRecoveryCodesMultiple = createStory(
|
||||
{
|
||||
numberRemaining: 2,
|
||||
},
|
||||
'User has 2 recovery codes remaining'
|
||||
'User has 2 backup authentication codes remaining'
|
||||
);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
codes-reminder-title = "Low recovery codes remaining"
|
||||
codes-reminder-title = "Low backup authentication codes remaining"
|
||||
|
||||
codes-reminder-description = "We noticed that you are running low on recovery codes. Please consider generating new codes to avoid getting locked out of your account."
|
||||
codes-reminder-description = "We noticed that you are running low on backup authentication codes. Please consider generating new codes to avoid getting locked out of your account."
|
||||
|
||||
codes-generate-plaintext = "Generate codes:"
|
||||
<%- link %>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
postConsumeRecoveryCode-subject = Recovery code used
|
||||
postConsumeRecoveryCode-title = Recovery code consumed
|
||||
postConsumeRecoveryCode-description = You have successfully consumed a recovery code from the following device:
|
||||
postConsumeRecoveryCode-subject = Backup authentication code used
|
||||
postConsumeRecoveryCode-title = Backup authentication code consumed
|
||||
postConsumeRecoveryCode-description = You have successfully consumed a backup authentication code from the following device:
|
||||
postConsumeRecoveryCode-action = Manage account
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"subject": {
|
||||
"id": "postConsumeRecoveryCode-subject",
|
||||
"message": "Recovery code used"
|
||||
"message": "Backup authentication code used"
|
||||
},
|
||||
"action": {
|
||||
"id": "postConsumeRecoveryCode-action",
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
<mj-section>
|
||||
<mj-column>
|
||||
<mj-text css-class="text-header">
|
||||
<span data-l10n-id="postConsumeRecoveryCode-title">Recovery code consumed</span>
|
||||
<span data-l10n-id="postConsumeRecoveryCode-title">Backup authentication code consumed</span>
|
||||
</mj-text>
|
||||
|
||||
<mj-text css-class="text-body">
|
||||
<span data-l10n-id="postConsumeRecoveryCode-description">You have successfully consumed a recovery code from the following device:</span>
|
||||
<span data-l10n-id="postConsumeRecoveryCode-description">You have successfully consumed a backup authentication code from the following device:</span>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
|
|
|
@ -12,7 +12,7 @@ export default {
|
|||
|
||||
const createStory = storyWithProps(
|
||||
'postConsumeRecoveryCode',
|
||||
'Sent when user has used a recovery code',
|
||||
'Sent when user has used a backup authentication code',
|
||||
{
|
||||
...MOCK_USER_INFO,
|
||||
link: 'http://localhost:3030/settings',
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
postConsumeRecoveryCode-title = "Recovery code consumed"
|
||||
postConsumeRecoveryCode-title = "Backup authentication code consumed"
|
||||
|
||||
postConsumeRecoveryCode-description = "You have successfully consumed a recovery code from the following device:"
|
||||
postConsumeRecoveryCode-description = "You have successfully consumed a backup authentication code from the following device:"
|
||||
|
||||
<%- include('/partials/userInfo/index.txt') %>
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
postNewRecoveryCodes-subject = New recovery codes generated
|
||||
postNewRecoveryCodes-title = New recovery codes generated
|
||||
postNewRecoveryCodes-description = You have successfully generated new recovery codes from the following device:
|
||||
postNewRecoveryCodes-subject = New backup authentication codes generated
|
||||
postNewRecoveryCodes-title = New backup authentication codes generated
|
||||
postNewRecoveryCodes-description = You have successfully generated new backup authentication codes from the following device:
|
||||
postNewRecoveryCodes-action = Manage account
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"subject": {
|
||||
"id": "postNewRecoveryCodes-subject",
|
||||
"message": "New recovery codes generated"
|
||||
"message": "New backup authentication codes generated"
|
||||
},
|
||||
"action": {
|
||||
"id": "postNewRecoveryCodes-action",
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
<mj-section>
|
||||
<mj-column>
|
||||
<mj-text css-class="text-header">
|
||||
<span data-l10n-id="postNewRecoveryCodes-title">New recovery codes generated</span>
|
||||
<span data-l10n-id="postNewRecoveryCodes-title">New backup authentication codes generated</span>
|
||||
</mj-text>
|
||||
|
||||
<mj-text css-class="text-body">
|
||||
<span data-l10n-id="postNewRecoveryCodes-description">You have successfully generated new recovery codes from the following device:</span>
|
||||
<span data-l10n-id="postNewRecoveryCodes-description">You have successfully generated new backup authentication codes from the following device:</span>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
|
|
|
@ -12,7 +12,7 @@ export default {
|
|||
|
||||
const createStory = storyWithProps(
|
||||
'postNewRecoveryCodes',
|
||||
'Sent when user has created new recovery codes, resetting their existing ones',
|
||||
'Sent when user has created new backup authentication codes, resetting their existing ones',
|
||||
{
|
||||
...MOCK_USER_INFO,
|
||||
link: 'http://localhost:3030/settings',
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
postNewRecoveryCodes-title = "New recovery codes generated"
|
||||
postNewRecoveryCodes-title = "New backup authentication codes generated"
|
||||
|
||||
postNewRecoveryCodes-description = "You have successfully generated new recovery codes from the following device:"
|
||||
postNewRecoveryCodes-description = "You have successfully generated new backup authentication codes from the following device:"
|
||||
|
||||
<%- include('/partials/userInfo/index.txt') %>
|
||||
|
||||
|
|
|
@ -258,7 +258,7 @@ class LoadTest(TestCase):
|
|||
raise
|
||||
pft = self.client.send_reset_code(email)
|
||||
assert "tries" in pft.get_status()
|
||||
# Get the recovery code and redeem it.
|
||||
# Get the backup authentication code and redeem it.
|
||||
code = self._get_code_from_email(emailAcct, "x-recovery-code")
|
||||
assert code is not None, "failed to get code"
|
||||
try:
|
||||
|
|
|
@ -36,7 +36,7 @@ function runTest(routePath, requestOptions, method) {
|
|||
return route.handler(request);
|
||||
}
|
||||
|
||||
describe('recovery codes', () => {
|
||||
describe('backup authentication codes', () => {
|
||||
beforeEach(() => {
|
||||
log = mocks.mockLog();
|
||||
customs = mocks.mockCustoms();
|
||||
|
@ -63,7 +63,7 @@ describe('recovery codes', () => {
|
|||
});
|
||||
|
||||
describe('GET /recoveryCodes', () => {
|
||||
it('should replace recovery codes in TOTP session', () => {
|
||||
it('should replace backup authentication codes in TOTP session', () => {
|
||||
requestOptions.credentials.authenticatorAssuranceLevel = 2;
|
||||
return runTest('/recoveryCodes', requestOptions, 'GET').then((res) => {
|
||||
assert.equal(res.recoveryCodes.length, 2, 'correct default code count');
|
||||
|
@ -71,7 +71,11 @@ describe('recovery codes', () => {
|
|||
assert.equal(db.replaceRecoveryCodes.callCount, 1);
|
||||
const args = db.replaceRecoveryCodes.args[0];
|
||||
assert.equal(args[0], UID, 'called with uid');
|
||||
assert.equal(args[1], 8, 'called with recovery code count');
|
||||
assert.equal(
|
||||
args[1],
|
||||
8,
|
||||
'called with backup authentication code count'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -87,7 +91,7 @@ describe('recovery codes', () => {
|
|||
});
|
||||
|
||||
describe('PUT /recoveryCodes', () => {
|
||||
it('should overwrite recovery codes in TOTP session', () => {
|
||||
it('should overwrite backup authentication codes in TOTP session', () => {
|
||||
requestOptions.credentials.authenticatorAssuranceLevel = 2;
|
||||
requestOptions.payload.recoveryCodes = ['123'];
|
||||
|
||||
|
@ -98,7 +102,11 @@ describe('recovery codes', () => {
|
|||
|
||||
const args = db.updateRecoveryCodes.args[0];
|
||||
assert.equal(args[0], UID, 'called with uid');
|
||||
assert.deepEqual(args[1], ['123'], 'called with recovery codes');
|
||||
assert.deepEqual(
|
||||
args[1],
|
||||
['123'],
|
||||
'called with backup authentication codes'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -115,7 +123,7 @@ describe('recovery codes', () => {
|
|||
});
|
||||
|
||||
describe('/session/verify/recoveryCode', () => {
|
||||
it('sends email if recovery codes are low', async () => {
|
||||
it('sends email if backup authentication codes are low', async () => {
|
||||
db.consumeRecoveryCode = sinon.spy((code) => {
|
||||
return Promise.resolve({ remaining: 1 });
|
||||
});
|
||||
|
@ -126,7 +134,7 @@ describe('recovery codes', () => {
|
|||
assert.equal(args[2].numberRemaining, 1);
|
||||
});
|
||||
|
||||
it('should rate-limit attempts to use a recovery code via customs', () => {
|
||||
it('should rate-limit attempts to use a backup authentication code via customs', () => {
|
||||
requestOptions.payload.code = '1234567890';
|
||||
db.consumeRecoveryCode = sinon.spy((code) => {
|
||||
throw error.recoveryCodeNotFound();
|
||||
|
|
|
@ -1031,7 +1031,7 @@ describe('lib/routes/validators:', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('recovery codes', () => {
|
||||
describe('backup authentication codes', () => {
|
||||
it('allows base32 codes', () => {
|
||||
assert.notExists(
|
||||
validators
|
||||
|
@ -1048,7 +1048,7 @@ describe('lib/routes/validators:', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('detects missing recovery codes', () => {
|
||||
it('detects missing backup authentication codes', () => {
|
||||
assert.exists(
|
||||
validators.recoveryCodes(2, 10).validate({ recoveryCodes: [] }).error
|
||||
);
|
||||
|
@ -1087,14 +1087,14 @@ describe('lib/routes/validators:', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('recovery code', () => {
|
||||
it('validates recovery codes', () => {
|
||||
describe('backup authentication code', () => {
|
||||
it('validates backup authentication codes', () => {
|
||||
assert.notExists(
|
||||
validators.recoveryCode(10).validate('0123456789').error
|
||||
);
|
||||
});
|
||||
|
||||
it('invalidates recovery code', () => {
|
||||
it('invalidates backup authentication code', () => {
|
||||
assert.exists(validators.recoveryCode(10).validate('012345678-').error);
|
||||
});
|
||||
|
||||
|
|
|
@ -323,7 +323,7 @@ const TESTS: [string, any, Record<string, any>?][] = [
|
|||
|
||||
['lowRecoveryCodesEmail', new Map<string, Test | any>([
|
||||
['subject', [
|
||||
{ test: 'include', expected: '2 recovery codes remaining' }
|
||||
{ test: 'include', expected: '2 backup authentication codes remaining' }
|
||||
]],
|
||||
['headers', new Map([
|
||||
['X-Link', { test: 'equal', expected: configUrl('accountRecoveryCodesUrl', 'low-recovery-codes', 'recovery-codes', 'low_recovery_codes=true', 'email', 'uid') }],
|
||||
|
@ -332,7 +332,7 @@ const TESTS: [string, any, Record<string, any>?][] = [
|
|||
['X-Template-Version', { test: 'equal', expected: TEMPLATE_VERSIONS.lowRecoveryCodes }],
|
||||
])],
|
||||
['html', [
|
||||
{ test: 'include', expected: '2 recovery codes remaining' },
|
||||
{ test: 'include', expected: '2 backup authentication codes remaining' },
|
||||
{ test: 'include', expected: decodeUrl(configHref('accountRecoveryCodesUrl', 'low-recovery-codes', 'recovery-codes', 'low_recovery_codes=true', 'email', 'uid')) },
|
||||
{ test: 'include', expected: decodeUrl(configHref('privacyUrl', 'low-recovery-codes', 'privacy')) },
|
||||
{ test: 'include', expected: decodeUrl(configHref('supportUrl', 'low-recovery-codes', 'support')) },
|
||||
|
@ -340,7 +340,7 @@ const TESTS: [string, any, Record<string, any>?][] = [
|
|||
{ test: 'notInclude', expected: 'utm_source=email' },
|
||||
]],
|
||||
['text', [
|
||||
{ test: 'include', expected: 'Low recovery codes remaining' },
|
||||
{ test: 'include', expected: 'Low backup authentication codes remaining' },
|
||||
{ test: 'include', expected: `Generate codes:\n${configUrl('accountRecoveryCodesUrl', 'low-recovery-codes', 'recovery-codes', 'low_recovery_codes=true', 'email', 'uid')}` },
|
||||
{ test: 'include', expected: `Mozilla Privacy Policy\n${configUrl('privacyUrl', 'low-recovery-codes', 'privacy')}` },
|
||||
{ test: 'include', expected: `For more info, visit Mozilla Support: ${configUrl('supportUrl', 'low-recovery-codes', 'support')}` },
|
||||
|
@ -349,7 +349,7 @@ const TESTS: [string, any, Record<string, any>?][] = [
|
|||
])],
|
||||
['lowRecoveryCodesEmail', new Map<string, Test | any>([
|
||||
['subject', [
|
||||
{ test: 'include', expected: '1 recovery code remaining' }
|
||||
{ test: 'include', expected: '1 backup authentication code remaining' }
|
||||
]]]),
|
||||
{updateTemplateValues: values => ({...values, numberRemaining: 1 })}],
|
||||
|
||||
|
@ -1133,7 +1133,7 @@ const TESTS: [string, any, Record<string, any>?][] = [
|
|||
])],
|
||||
|
||||
['postConsumeRecoveryCodeEmail', new Map<string, Test | any>([
|
||||
['subject', { test: 'equal', expected: 'Recovery code used' }],
|
||||
['subject', { test: 'equal', expected: 'Backup authentication code used' }],
|
||||
['headers', new Map([
|
||||
['X-Link', { test: 'equal', expected: configUrl('accountSettingsUrl', 'account-consume-recovery-code', 'manage-account', 'email', 'uid') }],
|
||||
['X-SES-MESSAGE-TAGS', { test: 'equal', expected: sesMessageTagsHeaderValue('postConsumeRecoveryCode') }],
|
||||
|
@ -1141,8 +1141,8 @@ const TESTS: [string, any, Record<string, any>?][] = [
|
|||
['X-Template-Version', { test: 'equal', expected: TEMPLATE_VERSIONS.postConsumeRecoveryCode }],
|
||||
])],
|
||||
['html', [
|
||||
{ test: 'include', expected: 'Recovery code consumed' },
|
||||
{ test: 'include', expected: 'You have successfully consumed a recovery code from the following device:' },
|
||||
{ test: 'include', expected: 'Backup authentication code consumed' },
|
||||
{ test: 'include', expected: 'You have successfully consumed a backup authentication code from the following device:' },
|
||||
{ test: 'include', expected: decodeUrl(configHref('accountSettingsUrl', 'account-consume-recovery-code', 'manage-account', 'email', 'uid')) },
|
||||
{ test: 'include', expected: decodeUrl(configHref('initiatePasswordChangeUrl', 'account-consume-recovery-code', 'change-password', 'email')) },
|
||||
{ test: 'include', expected: decodeUrl(configHref('privacyUrl', 'account-consume-recovery-code', 'privacy')) },
|
||||
|
@ -1155,8 +1155,8 @@ const TESTS: [string, any, Record<string, any>?][] = [
|
|||
{ test: 'notInclude', expected: 'utm_source=email' },
|
||||
]],
|
||||
['text', [
|
||||
{ test: 'include', expected: 'Recovery code consumed' },
|
||||
{ test: 'include', expected: 'You have successfully consumed a recovery code from the following device:' },
|
||||
{ test: 'include', expected: 'Backup authentication code consumed' },
|
||||
{ test: 'include', expected: 'You have successfully consumed a backup authentication code from the following device:' },
|
||||
{ test: 'include', expected: `Manage account:\n${configUrl('accountSettingsUrl', 'account-consume-recovery-code', 'manage-account', 'email', 'uid')}` },
|
||||
{ test: 'include', expected: `please change your password.\n${configUrl('initiatePasswordChangeUrl', 'account-consume-recovery-code', 'change-password', 'email')}` },
|
||||
{ test: 'include', expected: `Mozilla Privacy Policy\n${configUrl('privacyUrl', 'account-consume-recovery-code', 'privacy')}` },
|
||||
|
@ -1171,7 +1171,7 @@ const TESTS: [string, any, Record<string, any>?][] = [
|
|||
])],
|
||||
|
||||
['postNewRecoveryCodesEmail', new Map<string, Test | any>([
|
||||
['subject', { test: 'equal', expected: 'New recovery codes generated' }],
|
||||
['subject', { test: 'equal', expected: 'New backup authentication codes generated' }],
|
||||
['headers', new Map([
|
||||
['X-Link', { test: 'equal', expected: configUrl('accountSettingsUrl', 'account-replace-recovery-codes', 'manage-account', 'email', 'uid') }],
|
||||
['X-SES-MESSAGE-TAGS', { test: 'equal', expected: sesMessageTagsHeaderValue('postNewRecoveryCodes') }],
|
||||
|
@ -1179,8 +1179,8 @@ const TESTS: [string, any, Record<string, any>?][] = [
|
|||
['X-Template-Version', { test: 'equal', expected: TEMPLATE_VERSIONS.postNewRecoveryCodes }],
|
||||
])],
|
||||
['html', [
|
||||
{ test: 'include', expected: 'New recovery codes generated' },
|
||||
{ test: 'include', expected: 'You have successfully generated new recovery codes' },
|
||||
{ test: 'include', expected: 'New backup authentication codes generated' },
|
||||
{ test: 'include', expected: 'You have successfully generated new backup authentication codes' },
|
||||
{ test: 'include', expected: decodeUrl(configHref('accountSettingsUrl', 'account-replace-recovery-codes', 'manage-account', 'email', 'uid')) },
|
||||
{ test: 'include', expected: decodeUrl(configHref('initiatePasswordChangeUrl', 'account-replace-recovery-codes', 'change-password', 'email')) },
|
||||
{ test: 'include', expected: decodeUrl(configHref('privacyUrl', 'account-replace-recovery-codes', 'privacy')) },
|
||||
|
@ -1193,8 +1193,8 @@ const TESTS: [string, any, Record<string, any>?][] = [
|
|||
{ test: 'notInclude', expected: 'utm_source=email' },
|
||||
]],
|
||||
['text', [
|
||||
{ test: 'include', expected: 'New recovery codes generated' },
|
||||
{ test: 'include', expected: 'You have successfully generated new recovery codes' },
|
||||
{ test: 'include', expected: 'New backup authentication codes generated' },
|
||||
{ test: 'include', expected: 'You have successfully generated new backup authentication codes' },
|
||||
{ test: 'include', expected: `Manage account:\n${configUrl('accountSettingsUrl', 'account-replace-recovery-codes', 'manage-account', 'email', 'uid')}` },
|
||||
{ test: 'include', expected: `please change your password.\n${configUrl('initiatePasswordChangeUrl', 'account-replace-recovery-codes', 'change-password', 'email')}` },
|
||||
{ test: 'include', expected: `Mozilla Privacy Policy\n${configUrl('privacyUrl', 'account-replace-recovery-codes', 'privacy')}` },
|
||||
|
|
|
@ -11,7 +11,7 @@ const Client = require('../client')();
|
|||
const otplib = require('otplib');
|
||||
const BASE_36 = require('../../lib/routes/validators').BASE_36;
|
||||
|
||||
describe('remote recovery codes', function () {
|
||||
describe('remote backup authentication codes', function () {
|
||||
let server, client, email, recoveryCodes;
|
||||
const recoveryCodeCount = 9;
|
||||
const password = 'pssssst';
|
||||
|
@ -53,10 +53,10 @@ describe('remote recovery codes', function () {
|
|||
assert.equal(
|
||||
result.recoveryCodes.length,
|
||||
recoveryCodeCount,
|
||||
'recovery codes returned'
|
||||
'backup authentication codes returned'
|
||||
);
|
||||
|
||||
// Verify TOTP token so that initial recovery codes are generated
|
||||
// Verify TOTP token so that initial backup authentication codes are generated
|
||||
const code = otplib.authenticator.generate();
|
||||
return client
|
||||
.verifyTotpCode(code, { metricsContext })
|
||||
|
@ -75,12 +75,12 @@ describe('remote recovery codes', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should create recovery codes', () => {
|
||||
it('should create backup authentication codes', () => {
|
||||
assert.ok(recoveryCodes);
|
||||
assert.equal(
|
||||
recoveryCodes.length,
|
||||
recoveryCodeCount,
|
||||
'recovery codes returned'
|
||||
'backup authentication codes returned'
|
||||
);
|
||||
recoveryCodes.forEach((code) => {
|
||||
assert.equal(code.length > 1, true, 'correct length');
|
||||
|
@ -88,19 +88,19 @@ describe('remote recovery codes', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should replace recovery codes', () => {
|
||||
it('should replace backup authentication codes', () => {
|
||||
return client
|
||||
.replaceRecoveryCodes()
|
||||
.then((result) => {
|
||||
assert.ok(
|
||||
result.recoveryCodes.length,
|
||||
recoveryCodeCount,
|
||||
'recovery codes returned'
|
||||
'backup authentication codes returned'
|
||||
);
|
||||
assert.notDeepEqual(
|
||||
result,
|
||||
recoveryCodes,
|
||||
'recovery codes should not match'
|
||||
'backup authentication codes should not match'
|
||||
);
|
||||
|
||||
return server.mailbox.waitForEmail(email);
|
||||
|
@ -113,9 +113,9 @@ describe('remote recovery codes', function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe('recovery code verification', () => {
|
||||
describe('backup authentication code verification', () => {
|
||||
beforeEach(() => {
|
||||
// Create a new unverified session to test recovery codes
|
||||
// Create a new unverified session to test backup authentication codes
|
||||
return Client.login(config.publicUrl, email, password)
|
||||
.then((response) => {
|
||||
client = response;
|
||||
|
@ -126,7 +126,7 @@ describe('remote recovery codes', function () {
|
|||
);
|
||||
});
|
||||
|
||||
it('should fail to consume unknown recovery code', () => {
|
||||
it('should fail to consume unknown backup authentication code', () => {
|
||||
return client
|
||||
.consumeRecoveryCode('1234abcd', { metricsContext })
|
||||
.then(assert.fail, (err) => {
|
||||
|
@ -135,7 +135,7 @@ describe('remote recovery codes', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should consume recovery code and verify session', () => {
|
||||
it('should consume backup authentication code and verify session', () => {
|
||||
return client
|
||||
.consumeRecoveryCode(recoveryCodes[0], { metricsContext })
|
||||
.then((res) => {
|
||||
|
@ -158,7 +158,7 @@ describe('remote recovery codes', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should consume recovery code and can remove TOTP token', () => {
|
||||
it('should consume backup authentication code and can remove TOTP token', () => {
|
||||
return client
|
||||
.consumeRecoveryCode(recoveryCodes[0], { metricsContext })
|
||||
.then((res) => {
|
||||
|
@ -189,9 +189,9 @@ describe('remote recovery codes', function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe('should notify user when recovery codes are low', () => {
|
||||
describe('should notify user when backup authentication codes are low', () => {
|
||||
beforeEach(() => {
|
||||
// Create a new unverified session to test recovery codes
|
||||
// Create a new unverified session to test backup authentication codes
|
||||
return Client.login(config.publicUrl, email, password)
|
||||
.then((response) => {
|
||||
client = response;
|
||||
|
@ -202,7 +202,7 @@ describe('remote recovery codes', function () {
|
|||
);
|
||||
});
|
||||
|
||||
it('should consume recovery code and verify session', () => {
|
||||
it('should consume backup authentication code and verify session', () => {
|
||||
return client
|
||||
.consumeRecoveryCode(recoveryCodes[0], { metricsContext })
|
||||
.then((res) => {
|
||||
|
|
|
@ -329,7 +329,10 @@ describe('remote emails', function () {
|
|||
})
|
||||
.then((emailData) => {
|
||||
code = emailData.headers['x-recovery-code'];
|
||||
assert.ok(code, 'recovery code was sent the secondary email');
|
||||
assert.ok(
|
||||
code,
|
||||
'backup authentication code was sent the secondary email'
|
||||
);
|
||||
})
|
||||
.then((res) => {
|
||||
return client.deleteEmail(secondEmail);
|
||||
|
@ -344,7 +347,9 @@ describe('remote emails', function () {
|
|||
})
|
||||
.then(
|
||||
() => {
|
||||
assert.fail('password recovery code shoud not have been accepted');
|
||||
assert.fail(
|
||||
'password backup authentication code should not have been accepted'
|
||||
);
|
||||
},
|
||||
(err) => {
|
||||
assert.equal(
|
||||
|
|
|
@ -60,7 +60,7 @@ describe('remote totp', function () {
|
|||
assert.equal(
|
||||
result.recoveryCodes.length > 1,
|
||||
true,
|
||||
'recovery codes returned'
|
||||
'backup authentication codes returned'
|
||||
);
|
||||
|
||||
// Verify TOTP token
|
||||
|
|
|
@ -231,7 +231,7 @@ var ERRORS = {
|
|||
},
|
||||
RECOVERY_CODE_NOT_FOUND: {
|
||||
errno: 156,
|
||||
message: t('Recovery code not found'),
|
||||
message: t('Backup authentication code not found'),
|
||||
},
|
||||
DEVICE_COMMAND_UNAVAILABLE: {
|
||||
errno: 157,
|
||||
|
@ -570,11 +570,11 @@ var ERRORS = {
|
|||
},
|
||||
RECOVERY_CODE_REQUIRED: {
|
||||
errno: 1055,
|
||||
message: t('Recovery code required'),
|
||||
message: t('Backup authentication code required'),
|
||||
},
|
||||
INVALID_RECOVERY_CODE: {
|
||||
errno: 1056,
|
||||
message: t('Invalid recovery code'),
|
||||
message: t('Invalid backup authentication code'),
|
||||
},
|
||||
PASSWORD_SAME_AS_EMAIL: {
|
||||
errno: 1057,
|
||||
|
|
|
@ -1054,16 +1054,16 @@ FxaClientWrapper.prototype = {
|
|||
verifyTotpCode: createClientDelegate('verifyTotpCode'),
|
||||
|
||||
/**
|
||||
* Consume and verifies a session with a recovery code.
|
||||
* Consume and verifies a session with a backup authentication code.
|
||||
*
|
||||
* @param {String} sessionToken SessionToken obtained from signIn
|
||||
* @param {String} code Recovery code
|
||||
* @param {String} code Backup authentication code
|
||||
* @returns {Promise} resolves when complete
|
||||
*/
|
||||
consumeRecoveryCode: createClientDelegate('consumeRecoveryCode'),
|
||||
|
||||
/**
|
||||
* Replace all user recovery codes.
|
||||
* Replace all user backup authentication codes.
|
||||
*
|
||||
* @param {String} sessionToken SessionToken obtained from signIn
|
||||
* @returns {Promise} resolves when complete
|
||||
|
|
|
@ -36,7 +36,7 @@ const unblockCodeRegExp = new RegExp(unblockCodeRegExpStr, 'i');
|
|||
|
||||
// TOTP codes are 6 digits
|
||||
const TOTP_CODE = /^[0-9]{6}$/;
|
||||
// Recovery codes can be 8-10 alpha numeric characters
|
||||
// Backup authentication codes can be 8-10 alpha numeric characters
|
||||
const RECOVERY_CODE = /^([a-zA-Z0-9]{8,10})$/;
|
||||
|
||||
const utmRegex = /^[\w\/.%-]{1,128}$/;
|
||||
|
@ -210,7 +210,7 @@ var Validate = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Check if an recovery code is valid
|
||||
* Check if an backup authentication code is valid
|
||||
*
|
||||
* @param {String} value
|
||||
* @returns {Boolean}
|
||||
|
|
|
@ -1505,7 +1505,7 @@ const Account = Backbone.Model.extend(
|
|||
},
|
||||
|
||||
/**
|
||||
* Consume a recovery code.
|
||||
* Consume a backup authentication code.
|
||||
*
|
||||
* @param {String} code
|
||||
|
||||
|
@ -1524,7 +1524,7 @@ const Account = Backbone.Model.extend(
|
|||
},
|
||||
|
||||
/**
|
||||
* Replaces all current recovery codes.
|
||||
* Replaces all current backup authentication codes.
|
||||
*
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Recovery code model
|
||||
* Backup authentication code model
|
||||
*/
|
||||
|
||||
import Backbone from 'backbone';
|
||||
|
|
|
@ -622,7 +622,7 @@ var User = Backbone.Model.extend({
|
|||
* @param {Object} account - account to sign up
|
||||
* @param {String} password - the user's new password
|
||||
* @param {String} accountResetToken - token used to issue request
|
||||
* @param {String} recoveryKeyId - recoveryKeyId that maps to recovery code
|
||||
* @param {String} recoveryKeyId - recoveryKeyId that maps to backup authentication code
|
||||
* @param {String} kB - original kB
|
||||
* @param {Object} relier - relier being signed in to
|
||||
* @param {String} emailToHashWith - hash password with this email
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<header>
|
||||
<h1 id="fxa-save-recovery-codes">
|
||||
<!-- L10N: For languages structured like English, the second phrase can read "to continue to %(serviceName)s" -->
|
||||
{{#t}}Save recovery codes{{/t}} <span class="service">{{#t}}Continue to %(serviceName)s{{/t}}</span>
|
||||
{{#t}}Save backup authentication codes{{/t}} <span class="service">{{#t}}Continue to %(serviceName)s{{/t}}</span>
|
||||
</h1>
|
||||
</header>
|
||||
<section>
|
||||
|
@ -57,7 +57,7 @@
|
|||
<header>
|
||||
<h1 id="fxa-confirm-recovery-code">
|
||||
<!-- L10N: For languages structured like English, the second phrase can read "to continue to %(serviceName)s" -->
|
||||
{{#t}}Confirm recovery code{{/t}} <span class="service">{{#t}}Continue to %(serviceName)s{{/t}}</span>
|
||||
{{#t}}Confirm backup authentication code{{/t}} <span class="service">{{#t}}Continue to %(serviceName)s{{/t}}</span>
|
||||
</h1>
|
||||
</header>
|
||||
<section>
|
||||
|
@ -67,10 +67,10 @@
|
|||
<div id="recovery-codes">
|
||||
<div class="graphic graphic-recovery-codes"></div>
|
||||
<p>
|
||||
{{#t}}To ensure that you will be able to regain access to your account, in the event of a lost device, please enter one of your saved recovery codes.{{/t}}
|
||||
{{#t}}To ensure that you will be able to regain access to your account, in the event of a lost device, please enter one of your saved backup authentication codes.{{/t}}
|
||||
</p>
|
||||
<div class="input-row">
|
||||
<input type="text" class="tooltip-below recovery-code" placeholder="{{#t}}Recovery code{{/t}}" required autofocus autocomplete="off"/>
|
||||
<input type="text" class="tooltip-below recovery-code" placeholder="{{#t}}Backup authentication code{{/t}}" required autofocus autocomplete="off"/>
|
||||
</div>
|
||||
<div class="button-row">
|
||||
<button type="submit" class="primary-button recovery-confirm-code">{{#t}}Confirm{{/t}}</button>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<html>
|
||||
<head><title>Recovery Codes</title>
|
||||
<head><title>Backup Authentication Codes</title>
|
||||
</head>
|
||||
<body>
|
||||
{{#recoveryCodes}}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<div id="main-content" class="card">
|
||||
<header>
|
||||
<h1 id="fxa-recovery-code-header">{{#t}}Enter recovery code{{/t}}
|
||||
<h1 id="fxa-recovery-code-header">{{#t}}Enter backup authentication code{{/t}}
|
||||
<span class="service">{{#t}}Continue to %(serviceName)s{{/t}}</span>
|
||||
</h1>
|
||||
</header>
|
||||
|
@ -12,12 +12,12 @@
|
|||
<div class="graphic graphic-recovery-codes"></div>
|
||||
|
||||
<p class="verification-recovery-code-message">
|
||||
{{#t}}Please enter a recovery code that was provided to you during setup.{{/t}}
|
||||
{{#t}}Please enter a backup authentication code that was provided to you during two step authentication setup.{{/t}}
|
||||
</p>
|
||||
|
||||
<form novalidate>
|
||||
<div class="input-row otp-code-row">
|
||||
<input type="text" class="tooltip-below recovery-code" placeholder="{{#t}}Enter 10-digit recovery code{{/t}}" required autofocus />
|
||||
<input type="text" class="tooltip-below recovery-code" placeholder="{{#t}}Enter 10-digit backup authentication code{{/t}}" required autofocus />
|
||||
</div>
|
||||
|
||||
<div class="button-row">
|
||||
|
|
|
@ -72,7 +72,7 @@ export default {
|
|||
getFormatedRecoveryCodeFilename() {
|
||||
const account = this.getSignedInAccount();
|
||||
let formattedFilename =
|
||||
account.get('email') + ' ' + t('Firefox Recovery Codes');
|
||||
account.get('email') + ' ' + t('Firefox Backup Authentication Codes');
|
||||
if (formattedFilename.length > 200) {
|
||||
// 200 bytes (close to filesystem max) - 4 for '.txt' extension
|
||||
formattedFilename = formattedFilename.substring(0, 196);
|
||||
|
@ -81,7 +81,7 @@ export default {
|
|||
},
|
||||
|
||||
setupRecoveryCodes(codes, msg) {
|
||||
// Store a readable version of recovery codes so that they can
|
||||
// Store a readable version of backup authentication codes so that they can
|
||||
// be copied, printed and downloaded
|
||||
this.recoveryCodesText = '';
|
||||
if (codes) {
|
||||
|
|
|
@ -90,7 +90,7 @@ describe('views/sign_in_recovery_code', () => {
|
|||
assert.lengthOf(view.$('#fxa-recovery-code-header'), 1);
|
||||
assert.include(
|
||||
view.$('.verification-recovery-code-message').text(),
|
||||
'recovery code'
|
||||
'backup authentication code'
|
||||
);
|
||||
assert.equal(
|
||||
view.$('#use-backup-link').attr('href'),
|
||||
|
@ -189,7 +189,7 @@ describe('views/sign_in_recovery_code', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('invalid recovery code', () => {
|
||||
describe('invalid backup authentication code', () => {
|
||||
beforeEach(() => {
|
||||
sinon
|
||||
.stub(account, 'consumeRecoveryCode')
|
||||
|
|
|
@ -528,13 +528,13 @@ const conf = (module.exports = convict({
|
|||
recovery_codes: {
|
||||
count: {
|
||||
default: 8,
|
||||
doc: 'The default number of recovery codes to create',
|
||||
doc: 'The default number of backup authentication codes to create',
|
||||
env: 'RECOVERY_CODE_COUNT',
|
||||
format: 'nat',
|
||||
},
|
||||
length: {
|
||||
default: 10,
|
||||
doc: 'The default length of a recovery code',
|
||||
doc: 'The default length of a backup authentication code',
|
||||
env: 'RECOVERY_CODE_LENGTH',
|
||||
format: 'nat',
|
||||
},
|
||||
|
|
|
@ -2654,7 +2654,7 @@ const enableTotpInline = thenify(function () {
|
|||
})
|
||||
.then(click(selectors.INLINE_TOTP.READY_BUTTON))
|
||||
|
||||
// on the recovery codes screen, get the codes and advance to the confirm screen
|
||||
// on the backup authentication codes screen, get the codes and advance to the confirm screen
|
||||
.then(testElementExists(selectors.INLINE_RECOVERY_CODES.HEADER))
|
||||
.then(visibleByQSA(selectors.INLINE_RECOVERY_CODES.RECOVERY_CODES))
|
||||
.findByCssSelector(selectors.INLINE_RECOVERY_CODES.RECOVERY_CODES)
|
||||
|
|
|
@ -170,7 +170,7 @@ registerSuite('TOTP', {
|
|||
.then(testElementExists(selectors.ENTER_EMAIL.HEADER));
|
||||
},
|
||||
|
||||
'can change recovery codes': function () {
|
||||
'can change backup authentication codes': function () {
|
||||
return this.remote
|
||||
.then(confirmTotpCode(secret))
|
||||
.then(
|
||||
|
|
|
@ -36,7 +36,7 @@ const {
|
|||
visibleByQSA,
|
||||
} = FunctionalHelpers;
|
||||
|
||||
registerSuite('recovery code', {
|
||||
registerSuite('backup authentication code', {
|
||||
beforeEach: function () {
|
||||
email = createEmail();
|
||||
const self = this;
|
||||
|
@ -81,7 +81,7 @@ registerSuite('recovery code', {
|
|||
)
|
||||
.then(click(selectors.TOTP.CONFIRM_CODE_BUTTON))
|
||||
|
||||
// Store a recovery code
|
||||
// Store a backup authentication code
|
||||
.findByCssSelector(
|
||||
selectors.SETTINGS.SECURITY.TFA.FIRST_RECOVERY_CODE
|
||||
)
|
||||
|
@ -114,7 +114,7 @@ registerSuite('recovery code', {
|
|||
},
|
||||
|
||||
tests: {
|
||||
'can sign-in with recovery code - sync': function () {
|
||||
'can sign-in with backup authentication code - sync': function () {
|
||||
return (
|
||||
this.remote
|
||||
.then(
|
||||
|
@ -153,7 +153,7 @@ registerSuite('recovery code', {
|
|||
);
|
||||
},
|
||||
|
||||
'can regenerate recovery code when low': function () {
|
||||
'can regenerate backup authentication code when low': function () {
|
||||
return (
|
||||
this.remote
|
||||
.then(
|
||||
|
@ -183,8 +183,8 @@ registerSuite('recovery code', {
|
|||
|
||||
.then(testIsBrowserNotified('fxaccounts:login'))
|
||||
|
||||
// Next attempt to use recovery code will redirect to
|
||||
// page where user can generate more recovery codes
|
||||
// Next attempt to use backup authentication code will redirect to
|
||||
// page where user can generate more backup authentication codes
|
||||
.then(clearBrowserState({ force: true }))
|
||||
|
||||
.then(
|
||||
|
@ -203,7 +203,7 @@ registerSuite('recovery code', {
|
|||
.then(testIsBrowserNotified('fxaccounts:login'))
|
||||
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
|
||||
|
||||
// User gets an email notifying them to generate new recovery codes.
|
||||
// User gets an email notifying them to generate new backup authentication codes.
|
||||
// Clicking the link in email opens the security page
|
||||
.then(getEmail(email, 3))
|
||||
.then((emailData) => {
|
||||
|
|
|
@ -112,13 +112,14 @@ export class AccountResolver {
|
|||
}
|
||||
|
||||
@Mutation((returns) => BasicPayload, {
|
||||
description: 'Creates a new password for a user and overrides encryption keys',
|
||||
description:
|
||||
'Creates a new password for a user and overrides encryption keys',
|
||||
})
|
||||
@UseGuards(GqlAuthGuard, GqlCustomsGuard)
|
||||
@CatchGatewayError
|
||||
public async createPassword(
|
||||
@GqlSessionToken() token: string,
|
||||
@Args('input', { type: () => CreatePassword })
|
||||
@GqlSessionToken() token: string,
|
||||
@Args('input', { type: () => CreatePassword })
|
||||
input: CreatePassword
|
||||
): Promise<BasicPayload> {
|
||||
await this.authAPI.createPassword(token, input.email, input.password);
|
||||
|
@ -201,7 +202,8 @@ export class AccountResolver {
|
|||
}
|
||||
|
||||
@Mutation((returns) => ChangeRecoveryCodesPayload, {
|
||||
description: 'Return new recovery codes while removing old ones.',
|
||||
description:
|
||||
'Return new backup authentication codes while removing old ones.',
|
||||
})
|
||||
@UseGuards(GqlAuthGuard, GqlCustomsGuard)
|
||||
@CatchGatewayError
|
||||
|
|
|
@ -133,7 +133,7 @@ No changes.
|
|||
- fxa-settings: update string id on updated string" ([122f2c641](https://github.com/mozilla/fxa/commit/122f2c641))
|
||||
- settings: remove extra white-space before and after "Resend verification code" text Because: ([98a678bca](https://github.com/mozilla/fxa/commit/98a678bca))
|
||||
- 10b272048 PR Followup ([10b272048](https://github.com/mozilla/fxa/commit/10b272048))
|
||||
- settings: Disable 2FA and Recovery Code actions when account has no password ([6c911c6e8](https://github.com/mozilla/fxa/commit/6c911c6e8))
|
||||
- settings: Disable 2FA and Backup Verification Code actions when account has no password ([6c911c6e8](https://github.com/mozilla/fxa/commit/6c911c6e8))
|
||||
|
||||
## 1.231.4
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
# GetDataTrio component, part of Account Recovery Key flow
|
||||
|
||||
get-data-trio-title = Recovery Codes
|
||||
get-data-trio-title = Backup Authentication Codes
|
||||
get-data-trio-title-firefox = Firefox
|
||||
get-data-trio-title-firefox-account-recovery-key = Firefox account recovery key
|
||||
get-data-trio-title-firefox-backup-verification-codes = Firefox backup verification codes
|
||||
get-data-trio-title-firefox-backup-verification-codes = Firefox backup authentication codes
|
||||
get-data-trio-download =
|
||||
.title = Download
|
||||
get-data-trio-copy =
|
||||
|
|
|
@ -12,13 +12,13 @@ import { useAccount } from '../../models';
|
|||
|
||||
export type DownloadContentType =
|
||||
| 'Firefox account recovery key'
|
||||
| 'Firefox backup verification codes'
|
||||
| 'Firefox backup authentication codes'
|
||||
| 'Firefox';
|
||||
|
||||
const DownloadContentTypeL10nMapping: Record<DownloadContentType, string> = {
|
||||
Firefox: 'get-data-trio-title-firefox',
|
||||
'Firefox backup verification codes':
|
||||
'get-data-trio-title-firefox-backup-verification-codes',
|
||||
'Firefox backup authentication codes':
|
||||
'get-data-trio-title-firefox-backup-authentication-codes',
|
||||
'Firefox account recovery key':
|
||||
'get-data-trio-title-firefox-account-recovery-key',
|
||||
};
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
## Two Step Authentication - replace recovery code
|
||||
## Two Step Authentication - replace backup authentication code
|
||||
|
||||
tfa-replace-code-error-2 = There was a problem replacing your recovery codes
|
||||
tfa-replace-code-error-2 = There was a problem replacing your backup authentication codes
|
||||
tfa-replace-code-success = New codes have been created. Save these one-time use
|
||||
codes in a safe place — you’ll need them to access your account if you don’t
|
||||
backup authentication codes in a safe place — you’ll need them to access your account if you don’t
|
||||
have your mobile device.
|
||||
tfa-replace-code-success-alert-2 = Account recovery codes updated
|
||||
tfa-replace-code-success-alert-2 = Account backup authentication codes updated
|
||||
tfa-replace-code-1-2 = Step 1 of 2
|
||||
tfa-replace-code-2-2 = Step 2 of 2
|
||||
|
|
|
@ -61,11 +61,11 @@ it('renders', async () => {
|
|||
|
||||
expect(screen.getByTestId('databutton-download')).toHaveAttribute(
|
||||
'download',
|
||||
expect.stringContaining('Firefox backup verification codes')
|
||||
expect.stringContaining('Firefox backup authentication codes')
|
||||
);
|
||||
});
|
||||
|
||||
it('displays an error when fails to fetch new recovery codes', async () => {
|
||||
it('displays an error when fails to fetch new backup authentication codes', async () => {
|
||||
const account = {
|
||||
replaceRecoveryCodes: jest.fn().mockRejectedValue(new Error('wat')),
|
||||
} as unknown as Account;
|
||||
|
@ -80,7 +80,7 @@ it('displays an error when fails to fetch new recovery codes', async () => {
|
|||
expect(context.alertBarInfo?.error).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it('forces users to validate recovery code', async () => {
|
||||
it('forces users to validate backup authentication code', async () => {
|
||||
await renderPage2faReplaceRecoveryCodes();
|
||||
fireEvent.click(screen.getByTestId('ack-recovery-code'));
|
||||
|
||||
|
@ -89,7 +89,7 @@ it('forces users to validate recovery code', async () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('will not allow bad recovery code', async () => {
|
||||
it('will not allow bad backup authentication code', async () => {
|
||||
await renderPage2faReplaceRecoveryCodes();
|
||||
fireEvent.click(screen.getByTestId('ack-recovery-code'));
|
||||
await typeByTestIdFn('recovery-code-input-field')('xyz');
|
||||
|
|
|
@ -38,7 +38,7 @@ export const Page2faReplaceRecoveryCodes = (_: RouteComponentProps) => {
|
|||
l10n.getString(
|
||||
'tfa-replace-code-success-alert-2',
|
||||
null,
|
||||
'Account recovery codes updated'
|
||||
'Account backup authentication codes updated'
|
||||
)
|
||||
);
|
||||
navigate(HomePath + '#two-step-authentication', { replace: true });
|
||||
|
@ -48,7 +48,8 @@ export const Page2faReplaceRecoveryCodes = (_: RouteComponentProps) => {
|
|||
try {
|
||||
const { success } = await account.updateRecoveryCodes(recoveryCodes);
|
||||
|
||||
if (!success) throw new Error('Update recovery codes not successful.');
|
||||
if (!success)
|
||||
throw new Error('Update backup authentication codes not successful.');
|
||||
|
||||
alertSuccessAndGoHome();
|
||||
} catch (e) {
|
||||
|
@ -56,7 +57,7 @@ export const Page2faReplaceRecoveryCodes = (_: RouteComponentProps) => {
|
|||
l10n.getString(
|
||||
'tfa-replace-code-error-2',
|
||||
null,
|
||||
'There was a problem replacing your recovery codes'
|
||||
'There was a problem replacing your backup authentication codes'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -82,7 +83,7 @@ export const Page2faReplaceRecoveryCodes = (_: RouteComponentProps) => {
|
|||
l10n.getString(
|
||||
'tfa-replace-code-error-2',
|
||||
null,
|
||||
'There was a problem creating your recovery codes'
|
||||
'There was a problem creating your backup authentication codes'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -131,9 +132,9 @@ export const Page2faReplaceRecoveryCodes = (_: RouteComponentProps) => {
|
|||
<>
|
||||
<div className="my-2" data-testid="2fa-recovery-codes">
|
||||
<Localized id="tfa-replace-code-success">
|
||||
New codes have been created. Save these one-time use codes in a
|
||||
safe place — you’ll need them to access your account if you don’t
|
||||
have your mobile device.
|
||||
New codes have been created. Save these one-time use backup
|
||||
authentication codes in a safe place — you’ll need them to access
|
||||
your account if you don’t have your mobile device.
|
||||
</Localized>
|
||||
<div className="mt-6 flex flex-col items-center h-auto justify-between">
|
||||
{recoveryCodes.length > 0 ? (
|
||||
|
@ -141,7 +142,7 @@ export const Page2faReplaceRecoveryCodes = (_: RouteComponentProps) => {
|
|||
value={recoveryCodes}
|
||||
separator=" "
|
||||
onCopy={copyRecoveryCodes}
|
||||
contentType="Firefox backup verification codes"
|
||||
contentType="Firefox backup authentication codes"
|
||||
/>
|
||||
) : (
|
||||
<LoadingSpinner />
|
||||
|
@ -214,7 +215,7 @@ const RecoveryCodeCheck = ({
|
|||
l10n.getString(
|
||||
'tfa-incorrect-recovery-code',
|
||||
null,
|
||||
'Incorrect recovery code'
|
||||
'Incorrect backup authentication code'
|
||||
)
|
||||
);
|
||||
return;
|
||||
|
@ -230,16 +231,16 @@ const RecoveryCodeCheck = ({
|
|||
<form onSubmit={recoveryCodeForm.handleSubmit(onSubmit)}>
|
||||
<Localized id="tfa-enter-code-to-confirm">
|
||||
<p className="mt-4 mb-4">
|
||||
Please enter one of your recovery codes now to confirm you've saved
|
||||
it. You'll need a code if you lose your device and want to access your
|
||||
account.
|
||||
Please enter one of your backup authentication codes now to confirm
|
||||
you've saved it. You’ll need a code to login if you don’t have access
|
||||
to your mobile device.
|
||||
</p>
|
||||
</Localized>
|
||||
<div className="mt-4 mb-6" data-testid="recovery-code-input">
|
||||
<Localized id="tfa-enter-recovery-code" attrs={{ label: true }}>
|
||||
<InputText
|
||||
name="recoveryCode"
|
||||
label="Enter a recovery code"
|
||||
label="Enter a backup authentication code"
|
||||
prefixDataTestId="recovery-code"
|
||||
autoFocus
|
||||
onChange={() => {
|
||||
|
|
|
@ -12,8 +12,8 @@ tfa-button-finish = Finish
|
|||
|
||||
tfa-incorrect-totp = Incorrect two-step authentication code
|
||||
tfa-cannot-retrieve-code = There was a problem retrieving your code.
|
||||
tfa-cannot-verify-code-3 = There was a problem confirming your recovery code
|
||||
tfa-incorrect-recovery-code = Incorrect recovery code
|
||||
tfa-cannot-verify-code-3 = There was a problem confirming your backup authentication code
|
||||
tfa-incorrect-recovery-code = Incorrect backup authentication code
|
||||
tfa-enabled = Two-step authentication enabled
|
||||
|
||||
tfa-scan-this-code = Scan this QR code using one of <linkExternal>these
|
||||
|
@ -34,13 +34,20 @@ tfa-enter-secret-key = Enter this secret key into your authenticator app:
|
|||
tfa-enter-totp = Now enter the security code from the authentication app.
|
||||
tfa-input-enter-totp =
|
||||
.label = Enter security code
|
||||
tfa-save-these-codes = Save these one-time use codes in a safe place for when
|
||||
tfa-save-these-codes = Save these one-time use backup authentication codes in a safe place for when
|
||||
you don’t have your mobile device.
|
||||
|
||||
tfa-enter-code-to-confirm = Please enter one of your recovery codes now to
|
||||
<<<<<<< HEAD
|
||||
tfa-enter-code-to-confirm = Please enter one of your backup authentication codes now to
|
||||
confirm you’ve saved it. You’ll need a code if you lose your device and want
|
||||
to access your account.
|
||||
tfa-enter-recovery-code =
|
||||
.label = Enter a recovery code
|
||||
=======
|
||||
tfa-enter-code-to-confirm-1 = Please enter one of your backup authentication codes now to
|
||||
confirm you’ve saved it. You’ll need a code to login if you don’t have access to your
|
||||
mobile device.
|
||||
tfa-enter-recovery-code-1 =
|
||||
>>>>>>> 782bda91e4 (Update text on 2fa enter code to confirm screen)
|
||||
.label = Enter a backup authentication code
|
||||
|
||||
##
|
||||
|
|
|
@ -135,7 +135,7 @@ describe('step 2', () => {
|
|||
resetCheckcodeMock();
|
||||
});
|
||||
|
||||
it('shows the recovery codes when valid auth code is submitted', async () => {
|
||||
it('shows the backup authentication codes when valid auth code is submitted', async () => {
|
||||
await act(async () => {
|
||||
render();
|
||||
});
|
||||
|
@ -150,7 +150,7 @@ describe('step 2', () => {
|
|||
);
|
||||
expect(screen.getByTestId('databutton-download')).toHaveAttribute(
|
||||
'download',
|
||||
expect.stringContaining('Firefox backup verification codes')
|
||||
expect.stringContaining('Firefox backup authentication codes')
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -182,12 +182,12 @@ describe('step 3', () => {
|
|||
resetCheckcodeMock();
|
||||
});
|
||||
|
||||
it('renders the recovery code form', async () => {
|
||||
it('renders the backup authentication code form', async () => {
|
||||
await getRecoveryCodes();
|
||||
expect(screen.getByTestId('recovery-code-input-field')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows an error when an incorrect recovery code is entered', async () => {
|
||||
it('shows an error when an incorrect backup authentication code is entered', async () => {
|
||||
await getRecoveryCodes();
|
||||
await act(async () => {
|
||||
await fireEvent.input(screen.getByTestId('recovery-code-input-field'), {
|
||||
|
@ -199,7 +199,7 @@ describe('step 3', () => {
|
|||
});
|
||||
expect(screen.getByTestId('tooltip')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('tooltip')).toHaveTextContent(
|
||||
'Incorrect recovery code'
|
||||
'Incorrect backup authentication code'
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ export const PageTwoStepAuthentication = (_: RouteComponentProps) => {
|
|||
l10n.getString(
|
||||
'tfa-cannot-verify-code-3',
|
||||
null,
|
||||
'There was a problem confirming your recovery code'
|
||||
'There was a problem confirming your backup authentication code'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ export const PageTwoStepAuthentication = (_: RouteComponentProps) => {
|
|||
l10n.getString(
|
||||
'tfa-incorrect-recovery-code',
|
||||
null,
|
||||
'Incorrect recovery code'
|
||||
'Incorrect backup authentication code'
|
||||
)
|
||||
);
|
||||
return;
|
||||
|
@ -310,8 +310,8 @@ export const PageTwoStepAuthentication = (_: RouteComponentProps) => {
|
|||
<>
|
||||
<div className="my-2" data-testid="2fa-recovery-codes">
|
||||
<Localized id="tfa-save-these-codes">
|
||||
Save these one-time use codes in a safe place for when you don’t
|
||||
have your mobile device.
|
||||
Save these one-time use backup authentication codes in a safe
|
||||
place for when you don’t have your mobile device.
|
||||
</Localized>
|
||||
<div className="mt-6 flex flex-col items-center justify-between">
|
||||
<DataBlock
|
||||
|
@ -319,7 +319,7 @@ export const PageTwoStepAuthentication = (_: RouteComponentProps) => {
|
|||
separator=" "
|
||||
onAction={logDataTrioActionEvent}
|
||||
onCopy={copyRecoveryCodes}
|
||||
contentType="Firefox backup verification codes"
|
||||
contentType="Firefox backup authentication codes"
|
||||
></DataBlock>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -350,16 +350,16 @@ export const PageTwoStepAuthentication = (_: RouteComponentProps) => {
|
|||
<form onSubmit={recoveryCodeForm.handleSubmit(onRecoveryCodeSubmit)}>
|
||||
<Localized id="tfa-enter-code-to-confirm">
|
||||
<p className="mt-4 mb-4">
|
||||
Please enter one of your recovery codes now to confirm you've
|
||||
saved it. You'll need a code if you lose your device and want to
|
||||
access your account.
|
||||
Please enter one of your backup authentication codes now to
|
||||
confirm you've saved it. You’ll need a code to login if you don’t
|
||||
have access to your mobile device.
|
||||
</p>
|
||||
</Localized>
|
||||
<div className="mt-4 mb-6" data-testid="recovery-code-input">
|
||||
<Localized id="tfa-enter-recovery-code" attrs={{ label: true }}>
|
||||
<InputText
|
||||
name="recoveryCode"
|
||||
label="Enter a recovery code"
|
||||
label="Enter a backup authentication code"
|
||||
prefixDataTestId="recovery-code"
|
||||
autoFocus
|
||||
onChange={() => {
|
||||
|
|
|
@ -18,9 +18,9 @@ tfa-row-cannot-verify-session-4 = Sorry, there was a problem confirming your ses
|
|||
tfa-row-disable-modal-heading = Disable two-step authentication?
|
||||
tfa-row-disable-modal-confirm = Disable
|
||||
tfa-row-disable-modal-explain = You won’t be able to undo this action. You also
|
||||
have the option of <linkExternal>replacing your recovery codes</linkExternal>.
|
||||
have the option of <linkExternal>replacing your backup authentication codes</linkExternal>.
|
||||
tfa-row-cannot-disable-2 = Two-step authentication could not be disabled
|
||||
|
||||
tfa-row-change-modal-heading = Change recovery codes?
|
||||
tfa-row-change-modal-heading = Change backup authentication codes?
|
||||
tfa-row-change-modal-confirm = Change
|
||||
tfa-row-change-modal-explain = You won’t be able to undo this action.
|
||||
|
|
|
@ -145,8 +145,8 @@ export const UnitRowTwoStepAuth = () => {
|
|||
Disable two-step authentication?
|
||||
</h2>
|
||||
</Localized>
|
||||
{/* "replacing recovery codes" link below will actually drop you into
|
||||
recovery codes flow in the future. */}
|
||||
{/* "replacing backup authentication codes" link below will actually drop you into
|
||||
backup authentication codes flow in the future. */}
|
||||
<Localized
|
||||
id="tfa-row-disable-modal-explain"
|
||||
elems={{
|
||||
|
@ -167,7 +167,7 @@ export const UnitRowTwoStepAuth = () => {
|
|||
className="link-blue"
|
||||
href="https://support.mozilla.org/en-US/kb/reset-your-firefox-account-password-recovery-keys"
|
||||
>
|
||||
replacing your recovery codes
|
||||
replacing your backup authentication codes
|
||||
</LinkExternal>
|
||||
.
|
||||
</p>
|
||||
|
@ -207,7 +207,7 @@ export const UnitRowTwoStepAuth = () => {
|
|||
className="font-bold text-xl text-center mb-2"
|
||||
data-testid="change-codes-modal-header"
|
||||
>
|
||||
Change recovery codes?
|
||||
Change backup authentication codes?
|
||||
</h2>
|
||||
</Localized>
|
||||
<Localized id="tfa-row-change-modal-explain">
|
||||
|
|
|
@ -227,7 +227,7 @@ const ERRORS = {
|
|||
},
|
||||
RECOVERY_CODE_NOT_FOUND: {
|
||||
errno: 156,
|
||||
message: 'Recovery code not found',
|
||||
message: 'Backup authentication code not found',
|
||||
},
|
||||
DEVICE_COMMAND_UNAVAILABLE: {
|
||||
errno: 157,
|
||||
|
@ -568,11 +568,11 @@ const ERRORS = {
|
|||
},
|
||||
RECOVERY_CODE_REQUIRED: {
|
||||
errno: 1055,
|
||||
message: 'Recovery code required',
|
||||
message: 'Backup authentication code required',
|
||||
},
|
||||
INVALID_RECOVERY_CODE: {
|
||||
errno: 1056,
|
||||
message: 'Invalid recovery code',
|
||||
message: 'Invalid backup authentication code',
|
||||
},
|
||||
PASSWORD_SAME_AS_EMAIL: {
|
||||
errno: 1057,
|
||||
|
|
Загрузка…
Ссылка в новой задаче