Skip to content

Commit 188431b

Browse files
authored
Merge pull request #18326 from mozilla/fix-broken-destroy-tests
Fix broken destroy tests
2 parents 6128866 + c06edd5 commit 188431b

12 files changed

Lines changed: 392 additions & 142 deletions

File tree

packages/functional-tests/lib/testAccountTracker.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,18 @@ export class TestAccountTracker {
206206
account.email,
207207
account.password
208208
);
209+
210+
await this.target.authClient.sessionResendVerifyCode(
211+
credentials.sessionToken
212+
);
213+
const code = await this.target.emailClient.getVerifyLoginCode(
214+
account.email
215+
);
216+
await this.target.authClient.sessionVerifyCode(
217+
credentials.sessionToken,
218+
code
219+
);
220+
209221
await this.target.authClient.accountDestroy(
210222
account.email,
211223
account.password,

packages/functional-tests/tests/oauth/oauthPermissionsSignup.spec.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import { expect, test } from '../../lib/fixtures/standard';
77
test.describe('severity-1 #smoke', () => {
88
test.describe('oauth permissions for trusted reliers - sign up', () => {
99
test('signup without `prompt=consent`', async ({
10-
pages: { page, signup, relier },
10+
target,
11+
pages: { page, signup, relier, confirmSignupCode },
1112
testAccountTracker,
1213
}) => {
1314
const { email, password } = testAccountTracker.generateAccountDetails();
@@ -19,12 +20,16 @@ test.describe('severity-1 #smoke', () => {
1920

2021
//no permissions asked for, straight to confirm
2122
await expect(page).toHaveURL(/confirm_signup_code/);
23+
24+
// Provide the code so the account can be cleaned up.
25+
const code = await target.emailClient.getVerifyShortCode(email);
26+
await confirmSignupCode.fillOutCodeForm(code);
2227
});
2328

2429
test('signup with `prompt=consent`', async ({
2530
target,
2631
page,
27-
pages: { configPage, signup, relier },
32+
pages: { configPage, signup, relier, confirmSignupCode },
2833
testAccountTracker,
2934
}) => {
3035
const config = await configPage.getConfig();
@@ -48,6 +53,10 @@ test.describe('severity-1 #smoke', () => {
4853

4954
//Verify sign up code header
5055
await expect(page).toHaveURL(/confirm_signup_code/);
56+
57+
// Provide the code so the account can be cleaned up.
58+
const code = await target.emailClient.getVerifyShortCode(email);
59+
await confirmSignupCode.fillOutCodeForm(code);
5160
});
5261
});
5362
});

packages/functional-tests/tests/oauth/signin.spec.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,9 @@ test.describe('severity-1 #smoke', () => {
138138
});
139139

140140
test('oauth endpoint chooses the right auth flows', async ({
141-
pages: { page, signin, signup, relier },
141+
pages: { page, signin, signup, relier, confirmSignupCode },
142142
testAccountTracker,
143+
target,
143144
}) => {
144145
// Create unverified account
145146
const { email, password } = testAccountTracker.generateAccountDetails();
@@ -155,6 +156,11 @@ test.describe('severity-1 #smoke', () => {
155156
await relier.goto();
156157
await relier.clickChooseFlow();
157158
await expect(signin.cachedSigninHeading).toBeVisible();
159+
160+
await signin.signInButton.click();
161+
await expect(page).toHaveURL(/confirm_signup_code/);
162+
const code = await target.emailClient.getVerifyShortCode(email);
163+
await confirmSignupCode.fillOutCodeForm(code);
158164
});
159165
});
160166
});

packages/functional-tests/tests/react-conversion/oauthSignin.spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,6 @@ test.describe('severity-1 #smoke', () => {
182182

183183
// Verify email and ensure user is redirected to relier
184184
await expect(page).toHaveURL(/confirm_signup_code/);
185-
await expect(page).toHaveURL(/confirm_signup_code/);
186185
const code = await target.emailClient.getVerifyShortCode(email);
187186
await confirmSignupCode.fillOutCodeForm(code);
188187

@@ -227,6 +226,9 @@ test.describe('severity-1 #smoke', () => {
227226

228227
await expect(signin.cachedSigninHeading).toBeVisible();
229228
await expect(page.getByText(email)).toBeVisible();
229+
230+
await signin.signInButton.click();
231+
expect(await relier.isLoggedIn()).toBe(true);
230232
});
231233
});
232234
});

packages/fxa-auth-server/config/index.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1977,6 +1977,20 @@ const convictConf = convict({
19771977
env: 'OTP_SIGNUP_DIGIT',
19781978
},
19791979
},
1980+
accountDestroy: {
1981+
requireVerifiedAccount: {
1982+
doc: 'Whether or not the account must be verified in order to destroy it.',
1983+
default: false,
1984+
format: Boolean,
1985+
env: 'ACCOUNT_DESTROY__REQUIRE_VERIFIED_ACCOUNT',
1986+
},
1987+
requireVerifiedSession: {
1988+
doc: 'Whether or not the account must have a verified session in order to destroy it.',
1989+
default: true,
1990+
format: Boolean,
1991+
env: 'ACCOUNT_DESTROY__REQUIRE_VERIFIED_SESSION',
1992+
},
1993+
},
19801994
passwordForgotOtp: {
19811995
digits: {
19821996
doc: 'Number of digits in token',

packages/fxa-auth-server/lib/routes/account.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1857,6 +1857,29 @@ export class AccountHandler {
18571857
throw error.unverifiedSession();
18581858
}
18591859

1860+
// We can also check that the email was verified. This proves the account is active and
1861+
// related to a valid email. Accounts that aren't activated get deleted automatically
1862+
// by cron jobs anyways...
1863+
if (
1864+
this.config.accountDestroy.requireVerifiedAccount &&
1865+
!accountRecord.emailVerified
1866+
) {
1867+
throw error.unverifiedAccount();
1868+
}
1869+
1870+
// Regardless of whether or not an account has TOTP, we must make sure the user actually
1871+
// owns the account. This means the sessionToken must be verified.
1872+
//
1873+
// The UI will request an OTP code verification before destroying the account in the event
1874+
// the session is currently unverified. The following check will ensure that this OTP code
1875+
// was actually provided by the user.
1876+
if (
1877+
this.config.accountDestroy.requireVerifiedSession &&
1878+
!sessionToken.tokenVerified
1879+
) {
1880+
throw error.unverifiedSession();
1881+
}
1882+
18601883
// In other scenarios, fall back to the default behavior and let the user
18611884
// delete the account. If they have a password set, we verify it here. Users
18621885
// that don't have a password set will be able to delete their account without

packages/fxa-auth-server/lib/routes/session.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,7 @@ module.exports = function (
421421
},
422422
handler: async function (request) {
423423
log.begin('Session.resend_code', request);
424+
console.log('!!! resend code');
424425
const sessionToken = request.auth.credentials;
425426

426427
request.emitMetricsEvent('session.resend_code');
@@ -471,12 +472,14 @@ module.exports = function (
471472
if (account.primaryEmail.isVerified) {
472473
// Unverified emails mean that the user is attempting to resend the code from signup page,
473474
// therefore they get sent a different email template with the code.
475+
console.log('!!! sendVerifyLoginCodeEmail', account.email);
474476
await mailer.sendVerifyLoginCodeEmail(
475477
account.emails,
476478
account,
477479
options
478480
);
479481
} else {
482+
console.log('!!! sendVerifyShortCodeEmail');
480483
await mailer.sendVerifyShortCodeEmail([], account, options);
481484
}
482485

packages/fxa-auth-server/test/client/api.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,6 @@ module.exports = (config) => {
219219
if (!options) {
220220
options = { keys: true };
221221
}
222-
223222
return this.doRequest(
224223
'POST',
225224
`${this.baseURL}/account/login${getQueryString(options)}`,

packages/fxa-auth-server/test/local/routes/account.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3822,6 +3822,7 @@ describe('/account/keys', () => {
38223822

38233823
describe('/account/destroy', () => {
38243824
const email = '[email protected]';
3825+
const tokenVerified = true;
38253826
const uid = uuid.v4({}, Buffer.alloc(16)).toString('hex');
38263827

38273828
let mockDB, mockLog, mockRequest, mockPush, mockPushbox;
@@ -3832,6 +3833,7 @@ describe('/account/destroy', () => {
38323833
};
38333834
mockLog = mocks.mockLog();
38343835
mockRequest = mocks.mockRequest({
3836+
credentials: { uid, email, tokenVerified },
38353837
log: mockLog,
38363838
payload: {
38373839
email: email,
@@ -3856,6 +3858,9 @@ describe('/account/destroy', () => {
38563858
enabled: true,
38573859
},
38583860
},
3861+
accountDestroy: {
3862+
requireVerifiedAccount: false,
3863+
},
38593864
domain: 'wibble',
38603865
},
38613866
db: mockDB,
@@ -3912,6 +3917,7 @@ describe('/account/destroy', () => {
39123917
it('should delete the passwordless account', () => {
39133918
mockDB = { ...mocks.mockDB({ email, uid, verifierSetAt: 0 }) };
39143919
mockRequest = mocks.mockRequest({
3920+
credentials: { uid, email, tokenVerified },
39153921
log: mockLog,
39163922
payload: {
39173923
email: email,

packages/fxa-auth-server/test/remote/account_create_tests.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,12 @@ const {
161161
.then(() => {
162162
return server.mailbox.waitForEmail(email);
163163
})
164-
.then((emailData) => {
164+
.then(async (emailData) => {
165165
assert.include(emailData.text, 'Confirm account', 'en-US');
166166
// TODO: reinstate after translations catch up
167167
//assert.notInclude(emailData.text, 'Ativar agora', 'not pt-BR');
168+
const code = emailData.headers['x-verify-code'];
169+
await client.verifyEmail(code, {});
168170
return client.destroyAccount();
169171
})
170172
.then(() => {
@@ -179,10 +181,12 @@ const {
179181
.then(() => {
180182
return server.mailbox.waitForEmail(email);
181183
})
182-
.then((emailData) => {
184+
.then(async (emailData) => {
183185
assert.notInclude(emailData.text, 'Confirm email', 'not en-US');
184186
// TODO: reinstate after translations catch up
185187
//assert.include(emailData.text, 'Ativar agora', 'is pt-BR');
188+
const code = emailData.headers['x-verify-code'];
189+
await client.verifyEmail(code, {});
186190
return client.destroyAccount();
187191
});
188192
});
@@ -994,8 +998,6 @@ const {
994998
assert.equal(kB2, originalKb);
995999
});
9961000

997-
998-
9991001
async function login(email, password, version = '') {
10001002
return await Client.login(config.publicUrl, email, password, {
10011003
...testOptions,

0 commit comments

Comments
 (0)