diff --git a/packages/fxa-auth-server/config/dev.json b/packages/fxa-auth-server/config/dev.json index 36ba81caac7..18928197c3f 100644 --- a/packages/fxa-auth-server/config/dev.json +++ b/packages/fxa-auth-server/config/dev.json @@ -195,8 +195,6 @@ "dcdb5ae7add825d2": "123done", "5882386c6d801776": "firefox-desktop", "98e6508e88680e1a": "fxa-settings", - "7377719276ad44ee": "pocket-mobile", - "749818d3f2e7857f": "pocket-web", "8269bacd7bbc7f80": "thunderbird" }, "clients": [ diff --git a/packages/fxa-auth-server/config/index.ts b/packages/fxa-auth-server/config/index.ts index 0b91165fe9c..539e638770e 100644 --- a/packages/fxa-auth-server/config/index.ts +++ b/packages/fxa-auth-server/config/index.ts @@ -504,8 +504,7 @@ const convictConf = convict({ subscriptionSupportUrl: { doc: 'url to Mozilla subscription support page', format: String, - default: - 'https://support.mozilla.org/products', + default: 'https://support.mozilla.org/products', }, redirectDomain: { doc: 'Domain that mail urls are allowed to redirect to', @@ -1212,9 +1211,6 @@ const convictConf = convict({ }, }, clientIdToServiceNames: { - // This is used by oauth/db/index.js to identify pocket client ids so that it - // can store them separately in mysql. - // It's also used for amplitude stats doc: 'Mappings from client id to service name: { "id1": "name-1", "id2": "name-2" }', default: {}, format: 'Object', diff --git a/packages/fxa-auth-server/lib/oauth/db/index.js b/packages/fxa-auth-server/lib/oauth/db/index.js index 1f28ead77f3..d6969b7255e 100644 --- a/packages/fxa-auth-server/lib/oauth/db/index.js +++ b/packages/fxa-auth-server/lib/oauth/db/index.js @@ -24,16 +24,6 @@ const REFRESH_LAST_USED_AT_UPDATE_AFTER_MS = config.get( 'oauthServer.refreshToken.updateAfter' ); -function getPocketIds(idNameMap) { - return Object.entries(idNameMap) - .filter(([_, name]) => name.startsWith('pocket')) - .map(([id, _]) => id); -} - -const POCKET_IDS = getPocketIds( - config.get('oauthServer.clientIdToServiceNames') -); - class OauthDB extends ConnectedServicesDb { get mysql() { return this.db; @@ -92,12 +82,6 @@ class OauthDB extends ConnectedServicesDb { // We avoid revocation concerns with short-lived // tokens, so we do not store them. return token; - } else if (POCKET_IDS.includes(hex(vals.clientId))) { - // Pocket tokens are persisted past their expiration for legacy - // reasons: https://bugzilla.mozilla.org/show_bug.cgi?id=1547902 - // since they are long lived we continue to store them in mysql - // so that redis can be exclusively ephemeral - await this.mysql._generateAccessToken(token); } else { await this.redis.setAccessToken(token); } @@ -217,10 +201,6 @@ class OauthDB extends ConnectedServicesDb { await this.mysql._removeTokensAndCodes(uid); } - getPocketIds() { - return POCKET_IDS; - } - async pruneAuthorizationCodes(ttlInMs) { return await this.mysql._pruneAuthorizationCodes( ttlInMs || config.get('oauthServer.expiration.code') diff --git a/packages/fxa-auth-server/lib/oauth/db/mysql/index.js b/packages/fxa-auth-server/lib/oauth/db/mysql/index.js index dcc5db63324..c79c0fb4704 100644 --- a/packages/fxa-auth-server/lib/oauth/db/mysql/index.js +++ b/packages/fxa-auth-server/lib/oauth/db/mysql/index.js @@ -123,8 +123,7 @@ const QUERY_DEVELOPER_DELETE = 'LEFT JOIN clientDevelopers ON developers.developerId = clientDevelopers.developerId ' + 'WHERE developers.email=?'; // When listing access tokens, we deliberately do not exclude tokens that have expired. -// Such tokens will be cleaned up by a background job, except for those belonging to Pocket, which might -// one day come back to life as refresh tokens. (ref https://bugzilla.mozilla.org/show_bug.cgi?id=1547902). +// Such tokens will be cleaned up by a background job. // There's minimal downside to showing tokens in the brief period between when they expire and when // they get deleted from the db. const QUERY_LIST_ACCESS_TOKENS_BY_UID = @@ -539,14 +538,14 @@ class MysqlStore extends MysqlOAuthShared { } _getRefreshToken(token) { - return this._readOne(QUERY_REFRESH_TOKEN_FIND, [buf(token)]).then(function ( - t - ) { - if (t) { - t.scope = ScopeSet.fromString(t.scope); + return this._readOne(QUERY_REFRESH_TOKEN_FIND, [buf(token)]).then( + function (t) { + if (t) { + t.scope = ScopeSet.fromString(t.scope); + } + return t; } - return t; - }); + ); } _touchRefreshToken(token, now) { diff --git a/packages/fxa-auth-server/lib/oauth/token.js b/packages/fxa-auth-server/lib/oauth/token.js index 7ba07be3db8..774f7782d9e 100644 --- a/packages/fxa-auth-server/lib/oauth/token.js +++ b/packages/fxa-auth-server/lib/oauth/token.js @@ -69,12 +69,7 @@ exports.verify = async function verify(accessToken) { +token.expiresAt >= config.get('oauthServer.expiration.accessTokenExpiryEpoch'); - // Pocket was one of FxA first clients and does not currently support refresh tokens. - // We currently can't expire any pocket tokens. - // Ref: https://bugzilla.mozilla.org/show_bug.cgi?id=1547902 - const isPocket = db.getPocketIds().includes(token.clientId.toString('hex')); - - if (expired && !isPocket) { + if (expired) { throw OauthError.expiredToken(token.expiresAt); } diff --git a/packages/fxa-auth-server/test/oauth/api.js b/packages/fxa-auth-server/test/oauth/api.js index 31e638eb165..298dd576d71 100644 --- a/packages/fxa-auth-server/test/oauth/api.js +++ b/packages/fxa-auth-server/test/oauth/api.js @@ -2847,61 +2847,6 @@ describe('#integration - /v1', function () { assert.equal(res.result.errno, 115); }); - describe('expired tokens from pocket clients', () => { - const clientId = '749818d3f2e7857f'; - let accessTokenExpiryEpoch; - - before(async () => { - await Server.close(); - accessTokenExpiryEpoch = config.get( - 'oauthServer.expiration.accessTokenExpiryEpoch' - ); - config.set('oauthServer.expiration.accessTokenExpiryEpoch', undefined); - Server = await testServer.start(); - assert.isDefined(Server); - }); - - after(async () => { - await Server.close(); - config.set( - 'oauthServer.expiration.accessTokenExpiryEpoch', - accessTokenExpiryEpoch - ); - Server = await testServer.start(); - assert.isDefined(Server); - }); - - it('should not reject expired tokens from pocket clients', async function () { - let res = await newToken( - { - ttl: 1, - }, - { - clientId, - } - ); - - assert.equal(res.statusCode, 200); - assertSecurityHeaders(res); - assert.equal(res.result.expires_in, 1); - - sandbox.useFakeTimers({ - now: Date.now() + 1000 * 60 * 60, // 1 hr in future - shouldAdvanceTime: true, - }); - - res = await Server.api.post({ - url: '/verify', - payload: { - token: res.result.access_token, - }, - }); - - assert.equal(res.statusCode, 200); - assertSecurityHeaders(res); - }); - }); - describe('response', function () { it('should return the correct response', function () { return newToken({ scope: 'profile' }) diff --git a/packages/fxa-auth-server/test/oauth/db/index.js b/packages/fxa-auth-server/test/oauth/db/index.js index d84e9d02495..7fe24d90790 100644 --- a/packages/fxa-auth-server/test/oauth/db/index.js +++ b/packages/fxa-auth-server/test/oauth/db/index.js @@ -683,68 +683,4 @@ describe('#integration - db', function () { assert.notOk(await db.getAccessToken(tokenIdHash)); }); }); - - describe('Access Token storage', () => { - describe('Pocket tokens', () => { - const pocketId = buf('749818d3f2e7857f'); - const userId = buf(randomString(16)); - const tokenData = { - clientId: pocketId, - name: 'pocket', - canGrant: false, - publicClient: true, - userId: userId, - email: 'foo@bar.local', - scope: ScopeSet.fromArray(['no_scope']), - }; - - it('stores them in mysql', async () => { - const t = await db.generateAccessToken(tokenData); - const mysql = await db.mysql; - const tt = await mysql._getAccessToken(t.tokenId); - await db.removeAccessToken(t); - assert.equal(hex(tt.tokenId), hex(t.tokenId)); - }); - - it('retrieves them with getAccessToken', async () => { - const t = await db.generateAccessToken(tokenData); - const tt = await db.getAccessToken(t.tokenId); - await db.removeAccessToken(t); - assert.equal(hex(tt.tokenId), hex(t.tokenId)); - }); - - it('retrieves them with getAccessTokensByUid', async () => { - const t = await db.generateAccessToken(tokenData); - const tokens = await db.getAccessTokensByUid(userId); - await db.removeAccessToken(t); - assert.isArray(tokens); - assert.lengthOf(tokens, 1); - assert.deepEqual(tokens[0].tokenId, t.tokenId); - assert.deepEqual(tokens[0].clientId, t.clientId); - }); - - it('deletes them with removeAccessToken', async () => { - const t = await db.generateAccessToken(tokenData); - const tt = await db.getAccessToken(t.tokenId); - await db.removeAccessToken(t); - assert.isNotNull(tt); - const ttt = await db.getAccessToken(t.tokenId); - assert.isUndefined(ttt); - }); - - it('deletes them with deleteClientAuthorization', async () => { - const t = await db.generateAccessToken(tokenData); - await db.deleteClientAuthorization(t.clientId, t.userId); - const tt = await db.getAccessToken(t.tokenId); - assert.isUndefined(tt); - }); - - it('deletes them with removeTokensAndCodes', async () => { - const t = await db.generateAccessToken(tokenData); - await db.removeTokensAndCodes(t.userId); - const tt = await db.getAccessToken(t.tokenId); - assert.isUndefined(tt); - }); - }); - }); }); diff --git a/packages/fxa-event-broker/src/jwtset/jwtset.service.ts b/packages/fxa-event-broker/src/jwtset/jwtset.service.ts index 40a3f8b32fc..4833a8f6739 100644 --- a/packages/fxa-event-broker/src/jwtset/jwtset.service.ts +++ b/packages/fxa-event-broker/src/jwtset/jwtset.service.ts @@ -123,23 +123,4 @@ export class JwtsetService { uid: delEvent.uid, }); } - - public generateAppleMigrationSET( - appleMigrationEvent: set.appleMigrationEvent - ): Promise { - return this.generateSET({ - uid: appleMigrationEvent.uid, - clientId: appleMigrationEvent.clientId, - events: { - [set.APPLE_USER_MIGRATION_ID]: { - fxaEmail: appleMigrationEvent.fxaEmail, - appleEmail: appleMigrationEvent.appleEmail, - transferSub: appleMigrationEvent.transferSub, - success: appleMigrationEvent.success, - err: appleMigrationEvent.err, - uid: appleMigrationEvent.uid, - }, - }, - }); - } } diff --git a/packages/fxa-event-broker/src/jwtset/set.interface.ts b/packages/fxa-event-broker/src/jwtset/set.interface.ts index bd8bbcfa019..04a0f8929e4 100644 --- a/packages/fxa-event-broker/src/jwtset/set.interface.ts +++ b/packages/fxa-event-broker/src/jwtset/set.interface.ts @@ -11,8 +11,6 @@ export const PROFILE_EVENT_ID = 'https://schemas.accounts.firefox.com/event/profile-change'; export const SUBSCRIPTION_STATE_EVENT_ID = 'https://schemas.accounts.firefox.com/event/subscription-state-change'; -export const APPLE_USER_MIGRATION_ID = - 'https://schemas.accounts.firefox.com/event/apple-user-migration'; export type deleteEvent = { clientId: string; @@ -53,13 +51,3 @@ export type subscriptionEvent = { isActive: boolean; changeTime: number; }; - -export type appleMigrationEvent = { - uid: string; - clientId: string; - fxaEmail: string; - appleEmail: string; - transferSub: string; - success: boolean; - err: string; -}; diff --git a/packages/fxa-event-broker/src/pubsub-proxy/pubsub-proxy.controller.ts b/packages/fxa-event-broker/src/pubsub-proxy/pubsub-proxy.controller.ts index 14a332b6d86..e62151a8655 100644 --- a/packages/fxa-event-broker/src/pubsub-proxy/pubsub-proxy.controller.ts +++ b/packages/fxa-event-broker/src/pubsub-proxy/pubsub-proxy.controller.ts @@ -195,17 +195,6 @@ export class PubsubProxyController { accountLocked: message.accountLocked, }); } - case dto.APPLE_USER_MIGRATION_EVENT: { - return await this.jwtset.generateAppleMigrationSET({ - clientId, - uid: message.uid, - fxaEmail: message.fxaEmail, - appleEmail: message.appleEmail, - transferSub: message.transferSub, - success: message.success, - err: message.error, - }); - } default: throw Error(`Invalid event: ${message.event}`); } diff --git a/packages/fxa-event-broker/src/queueworker/queueworker.service.spec.ts b/packages/fxa-event-broker/src/queueworker/queueworker.service.spec.ts index 67faffb9726..0c5d7f6441e 100644 --- a/packages/fxa-event-broker/src/queueworker/queueworker.service.spec.ts +++ b/packages/fxa-event-broker/src/queueworker/queueworker.service.spec.ts @@ -98,18 +98,6 @@ const profileMessageForTotpEnabledChange = { totpEnabled: true, }; -const appleMigrationMessage = { - event: 'appleUserMigration', - timestamp: now, - ts: now / 1000, - uid: '993d26bac72b471991b197b3d298a5de', - fxaEmail: 'fxa@email.com', - appleEmail: 'apple@email.com', - transferSub: '123', - success: true, - err: '', -}; - const updateStubMessage = (message: any) => { return { Body: JSON.stringify(message), @@ -294,28 +282,6 @@ describe('QueueworkerService', () => { ]); }); - it('handles apple migration event', async () => { - const msg = updateStubMessage(appleMigrationMessage); - await (service as any).handleMessage(msg); - - const topicName = 'rp749818d3f2e7857f'; - expect(pubsub.topic).toBeCalledWith(topicName); - expect(pubsub.topic(topicName).publishMessage).toBeCalledTimes(1); - expect(pubsub.topic(topicName).publishMessage).toBeCalledWith({ - json: { - appleEmail: 'apple@email.com', - err: '', - event: 'appleUserMigration', - fxaEmail: 'fxa@email.com', - success: true, - timestamp: now, - transferSub: '123', - ts: now / 1000, - uid: '993d26bac72b471991b197b3d298a5de', - }, - }); - }); - const fetchOnValidMessage = { 'delete message': baseDeleteMessage, 'legacy subscription message': baseSubscriptionUpdateLegacyMessage, diff --git a/packages/fxa-event-broker/src/queueworker/queueworker.service.ts b/packages/fxa-event-broker/src/queueworker/queueworker.service.ts index 61a474c7c19..453b7cdd1cf 100644 --- a/packages/fxa-event-broker/src/queueworker/queueworker.service.ts +++ b/packages/fxa-event-broker/src/queueworker/queueworker.service.ts @@ -179,11 +179,7 @@ export class QueueworkerService * @param eventType Event type to use for metrics */ private async handleMessageFanout( - message: - | dto.deleteSchema - | dto.profileSchema - | dto.passwordSchema - | dto.appleUserMigrationSchema, + message: dto.deleteSchema | dto.profileSchema | dto.passwordSchema, eventType: string ) { this.metrics.increment('message.type', { eventType }); @@ -294,24 +290,6 @@ export class QueueworkerService await Promise.all(notifyClientPromises); } - /** - * Notify Pocket that a user's Apple account has been migrated. - * - * @param message Incoming SQS Message - */ - private async handleAppleUserMigrationEvent( - message: dto.appleUserMigrationSchema - ) { - // Note the hardcoded Pocket clientId, this value should not change in production - const clientId = '749818d3f2e7857f'; - this.metrics.increment('message.type', { eventType: 'appleMigration' }); - const rpMessage = { - timestamp: Date.now(), - ...message, - }; - await this.publishMessage(clientId, rpMessage); - } - /** * Process a SQS message, dispatch based on message event type. * @@ -357,10 +335,6 @@ export class QueueworkerService await this.handleMessageFanout(message, 'password'); break; } - case dto.APPLE_USER_MIGRATION_EVENT: { - await this.handleAppleUserMigrationEvent(message); - break; - } default: unhandledEventType(message); } diff --git a/packages/fxa-event-broker/src/queueworker/service-notification.interface.ts b/packages/fxa-event-broker/src/queueworker/service-notification.interface.ts index cf8a0cca1c9..47347691e7f 100644 --- a/packages/fxa-event-broker/src/queueworker/service-notification.interface.ts +++ b/packages/fxa-event-broker/src/queueworker/service-notification.interface.ts @@ -13,7 +13,6 @@ export type ServiceNotification = | dto.passwordSchema | dto.profileSchema | dto.subscriptionUpdateSchema - | dto.appleUserMigrationSchema | undefined; interface SchemaTable { @@ -29,7 +28,6 @@ const eventSchemas = { [dto.PRIMARY_EMAIL_EVENT]: dto.PROFILE_CHANGE_SCHEMA, [dto.PASSWORD_CHANGE_EVENT]: dto.PASSWORD_CHANGE_SCHEMA, [dto.PASSWORD_RESET_EVENT]: dto.PASSWORD_CHANGE_SCHEMA, - [dto.APPLE_USER_MIGRATION_EVENT]: dto.APPLE_USER_MIGRATION_SCHEMA, }; /** diff --git a/packages/fxa-event-broker/src/queueworker/sqs.dto.ts b/packages/fxa-event-broker/src/queueworker/sqs.dto.ts index c72951f5476..80d69f50371 100644 --- a/packages/fxa-event-broker/src/queueworker/sqs.dto.ts +++ b/packages/fxa-event-broker/src/queueworker/sqs.dto.ts @@ -11,7 +11,6 @@ export const PASSWORD_RESET_EVENT = 'reset'; export const PRIMARY_EMAIL_EVENT = 'primaryEmailChanged'; export const PROFILE_CHANGE_EVENT = 'profileDataChange'; export const SUBSCRIPTION_UPDATE_EVENT = 'subscription:update'; -export const APPLE_USER_MIGRATION_EVENT = 'appleUserMigration'; // Message schemas const HEX_STRING = /^(?:[0-9a-fA-F]{2})+$/; @@ -98,17 +97,6 @@ export const PROFILE_CHANGE_SCHEMA = joi .unknown(true) .required(); -export const APPLE_USER_MIGRATION_SCHEMA = joi - .object() - .keys({ - event: joi.string().valid(APPLE_USER_MIGRATION_EVENT), - timestamp: joi.number().optional(), - ts: joi.number().required(), - uid: joi.string().required(), - }) - .unknown(true) - .required(); - export type deleteSchema = { event: typeof DELETE_EVENT; timestamp?: number; @@ -159,15 +147,3 @@ export type subscriptionUpdateSchema = { ts: number; uid: string; }; - -export type appleUserMigrationSchema = { - event: typeof APPLE_USER_MIGRATION_EVENT; - timestamp?: number; - ts: number; - uid: string; - fxaEmail: string; - appleEmail: string; - transferSub: string; - success: boolean; - err: string; -};