Skip to content

Commit 9108677

Browse files
authored
Merge pull request #20072 from mozilla/FXA-13132
fix(oauth): Prevent validation errors from orphaned client tokens
2 parents 9d76edf + 095f134 commit 9108677

2 files changed

Lines changed: 42 additions & 3 deletions

File tree

packages/fxa-shared/connected-services/factories.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ export class ConnectedServicesFactory {
257257
// We fill in a default device name from the OAuth client name,
258258
// but individual clients can override this in their device record registration.
259259
if (!client.name) {
260-
client.name = oauthClient.client_name;
260+
client.name = oauthClient.client_name ?? null;
261261
}
262262
// For now we assume that all oauth clients that register a device record are mobile apps.
263263
// Ref https://github.com/mozilla/fxa/issues/449
@@ -277,7 +277,7 @@ export class ConnectedServicesFactory {
277277
refreshTokenId: null,
278278
deviceId: device.id,
279279
deviceType: device.type,
280-
name: device.name,
280+
name: device.name ?? null,
281281
createdTime: device.createdAt,
282282
lastAccessTime: device.lastAccessTime,
283283
};
@@ -292,6 +292,6 @@ export class ConnectedServicesFactory {
292292
}
293293

294294
protected getDefaultClientFields(): AttachedClient {
295-
return attachedClientsDefaults;
295+
return { ...attachedClientsDefaults };
296296
}
297297
}

packages/fxa-shared/test/connected-services/factories.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,5 +193,44 @@ describe('connected-services/factories', () => {
193193
Sinon.assert.calledOnce(bStubbed.oauthClients);
194194
Sinon.assert.calledOnce(bStubbed.sessions);
195195
});
196+
197+
it('coerces undefined device name to null', async () => {
198+
deviceList = [
199+
{
200+
id: 'test-device',
201+
sessionTokenId: 'test',
202+
name: undefined as any, // Simulate undefined from database
203+
pushEndpointExpired: false,
204+
availableCommands: {},
205+
location: {},
206+
} as AttachedDevice,
207+
];
208+
oauthClients = [];
209+
sessions = [];
210+
211+
const results = await factory.build('1234', 'en');
212+
213+
assert.strictEqual(results[0].name, null);
214+
});
215+
216+
it('coerces undefined client_name to null', async () => {
217+
oauthClients = [
218+
{
219+
refresh_token_id: 'test-oauth',
220+
created_time: Date.now(),
221+
last_access_time: Date.now(),
222+
client_name: undefined as any, // Simulate undefined from database
223+
client_id: null as any,
224+
scope: null as any,
225+
} as AttachedOAuthClient,
226+
];
227+
deviceList = [];
228+
sessions = [];
229+
230+
const results = await factory.build('1234', 'en');
231+
232+
// Verify name is null, not undefined (required for validation)
233+
assert.strictEqual(results[0].name, null);
234+
});
196235
});
197236
});

0 commit comments

Comments
 (0)