mirror of
https://github.com/bitwarden/browser
synced 2025-12-22 19:23:52 +00:00
[PM-19838] Untrust devices that cannot be rotated (#14165)
* Untrust devices that cannot be rotated * Add tests and only send request on more than 0 failed devices * Address feedback
This commit is contained in:
@@ -204,7 +204,8 @@ export class DeviceTrustService implements DeviceTrustServiceAbstraction {
|
||||
}
|
||||
|
||||
const devices = await this.devicesApiService.getDevices();
|
||||
return await Promise.all(
|
||||
const devicesToUntrust: string[] = [];
|
||||
const rotatedData = await Promise.all(
|
||||
devices.data
|
||||
.filter((device) => device.isTrusted)
|
||||
.map(async (device) => {
|
||||
@@ -213,6 +214,13 @@ export class DeviceTrustService implements DeviceTrustServiceAbstraction {
|
||||
deviceWithKeys.encryptedPublicKey,
|
||||
oldUserKey,
|
||||
);
|
||||
|
||||
if (!publicKey) {
|
||||
// Device was trusted but encryption is broken. This should be untrusted
|
||||
devicesToUntrust.push(device.id);
|
||||
return null;
|
||||
}
|
||||
|
||||
const newEncryptedPublicKey = await this.encryptService.encrypt(publicKey, newUserKey);
|
||||
const newEncryptedUserKey = await this.encryptService.rsaEncrypt(
|
||||
newUserKey.key,
|
||||
@@ -229,8 +237,14 @@ export class DeviceTrustService implements DeviceTrustServiceAbstraction {
|
||||
request.encryptedUserKey = newRotateableKeySet.encryptedUserKey.encryptedString;
|
||||
request.deviceId = device.id;
|
||||
return request;
|
||||
}),
|
||||
})
|
||||
.filter((otherDeviceKeysUpdateRequest) => otherDeviceKeysUpdateRequest != null),
|
||||
);
|
||||
if (rotatedData.length > 0) {
|
||||
this.logService.info("[Device trust rotation] Distrusting devices that failed to decrypt.");
|
||||
await this.devicesApiService.untrustDevices(devicesToUntrust);
|
||||
}
|
||||
return rotatedData;
|
||||
}
|
||||
|
||||
async rotateDevicesTrust(
|
||||
|
||||
@@ -679,6 +679,52 @@ describe("deviceTrustService", () => {
|
||||
).rejects.toThrow("New user key is required. Cannot get rotated data.");
|
||||
});
|
||||
|
||||
it("untrusts devices that failed to decrypt", async () => {
|
||||
const deviceResponse = {
|
||||
id: "id",
|
||||
userId: "",
|
||||
name: "",
|
||||
identifier: "",
|
||||
type: DeviceType.Android,
|
||||
creationDate: "",
|
||||
revisionDate: "",
|
||||
isTrusted: true,
|
||||
};
|
||||
devicesApiService.getDevices.mockResolvedValue(
|
||||
new ListResponse(
|
||||
{
|
||||
data: [deviceResponse],
|
||||
},
|
||||
DeviceResponse,
|
||||
),
|
||||
);
|
||||
encryptService.decryptToBytes.mockResolvedValue(null);
|
||||
encryptService.encrypt.mockResolvedValue(new EncString("test_encrypted_data"));
|
||||
encryptService.rsaEncrypt.mockResolvedValue(new EncString("test_encrypted_data"));
|
||||
|
||||
const protectedDeviceResponse = new ProtectedDeviceResponse({
|
||||
id: "id",
|
||||
creationDate: "",
|
||||
identifier: "test_device_identifier",
|
||||
name: "Firefox",
|
||||
type: DeviceType.FirefoxBrowser,
|
||||
encryptedPublicKey: "",
|
||||
encryptedUserKey: "",
|
||||
});
|
||||
devicesApiService.getDeviceKeys.mockResolvedValue(protectedDeviceResponse);
|
||||
|
||||
const fakeOldUserKeyData = new Uint8Array(64);
|
||||
fakeOldUserKeyData.fill(5, 0, 1);
|
||||
fakeOldUserKey = new SymmetricCryptoKey(fakeOldUserKeyData) as UserKey;
|
||||
const fakeNewUserKeyData = new Uint8Array(64);
|
||||
fakeNewUserKeyData.fill(1, 0, 1);
|
||||
fakeNewUserKey = new SymmetricCryptoKey(fakeNewUserKeyData) as UserKey;
|
||||
|
||||
await deviceTrustService.getRotatedData(fakeOldUserKey, fakeNewUserKey, userId);
|
||||
|
||||
expect(devicesApiService.untrustDevices).toHaveBeenCalledWith(["id"]);
|
||||
});
|
||||
|
||||
it("returns the expected data when all required parameters are provided", async () => {
|
||||
const deviceResponse = {
|
||||
id: "",
|
||||
|
||||
Reference in New Issue
Block a user