1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-22 11:13:46 +00:00
Files
browser/libs/common/src/vault/models/domain/login.spec.ts
Bernd Schoolmann 395e4f2c05 [PM-27591] Remove orgid in vault decryption code (#17099)
* Remove orgid in vault decryption code

* Remove folder usage without provided key

* Fix folder test

* Fix build

* Fix build

* Fix build

* Fix tests

* Update spec to not use EncString decrypt

* Fix tests

* Fix test

* Fix test

* Remove comment

* Remove org id parameter
2025-12-08 07:09:43 -07:00

302 lines
11 KiB
TypeScript

import { MockProxy, mock } from "jest-mock-extended";
import { mockContainerService, mockEnc, mockFromJson } from "../../../../spec";
import { EncryptedString, EncString } from "../../../key-management/crypto/models/enc-string";
import { UriMatchStrategy } from "../../../models/domain/domain-service";
import { LoginData } from "../../models/data/login.data";
import { Login } from "../../models/domain/login";
import { LoginUri } from "../../models/domain/login-uri";
import { LoginUriView } from "../../models/view/login-uri.view";
import { Fido2CredentialApi } from "../api/fido2-credential.api";
import { Fido2CredentialData } from "../data/fido2-credential.data";
import { Fido2CredentialView } from "../view/fido2-credential.view";
import { Fido2Credential } from "./fido2-credential";
describe("Login DTO", () => {
beforeEach(() => {
mockContainerService();
});
it("Convert from empty LoginData", () => {
const data = new LoginData();
const login = new Login(data);
expect(login).toEqual({
passwordRevisionDate: undefined,
autofillOnPageLoad: undefined,
username: undefined,
password: undefined,
totp: undefined,
});
expect(data.username).toBeUndefined();
expect(data.password).toBeUndefined();
expect(data.passwordRevisionDate).toBeUndefined();
expect(data.totp).toBeUndefined();
expect(data.autofillOnPageLoad).toBeUndefined();
expect(data.uris).toBeUndefined();
expect(data.fido2Credentials).toBeUndefined();
});
it("Convert from full LoginData", () => {
const fido2CredentialData = initializeFido2Credential(new Fido2CredentialData());
const data: LoginData = {
uris: [{ uri: "uri", uriChecksum: "checksum", match: UriMatchStrategy.Domain }],
username: "username",
password: "password",
passwordRevisionDate: "2022-01-31T12:00:00.000Z",
totp: "123",
autofillOnPageLoad: false,
fido2Credentials: [fido2CredentialData],
};
const login = new Login(data);
expect(login).toEqual({
passwordRevisionDate: new Date("2022-01-31T12:00:00.000Z"),
autofillOnPageLoad: false,
username: { encryptedString: "username", encryptionType: 0 },
password: { encryptedString: "password", encryptionType: 0 },
totp: { encryptedString: "123", encryptionType: 0 },
uris: [
{
match: 0,
uri: { encryptedString: "uri", encryptionType: 0 },
uriChecksum: { encryptedString: "checksum", encryptionType: 0 },
},
],
fido2Credentials: [encryptFido2Credential(fido2CredentialData)],
});
});
it("Initialize without LoginData", () => {
const login = new Login();
expect(login).toEqual({});
});
describe("decrypt", () => {
let loginUri: MockProxy<LoginUri>;
const loginUriView = new LoginUriView();
const decryptedFido2Credential = Symbol();
const login = Object.assign(new Login(), {
username: mockEnc("encrypted username"),
password: mockEnc("encrypted password"),
passwordRevisionDate: new Date("2022-01-31T12:00:00.000Z"),
totp: mockEnc("encrypted totp"),
autofillOnPageLoad: true,
fido2Credentials: [{ decrypt: jest.fn().mockReturnValue(decryptedFido2Credential) } as any],
});
const expectedView = {
username: "encrypted username",
password: "encrypted password",
passwordRevisionDate: new Date("2022-01-31T12:00:00.000Z"),
totp: "encrypted totp",
uris: [
{
_uri: "decrypted uri",
},
],
autofillOnPageLoad: true,
fido2Credentials: [decryptedFido2Credential],
};
beforeEach(() => {
loginUri = mock();
loginUriView.uri = "decrypted uri";
});
it("should decrypt to a view", async () => {
loginUri.decrypt.mockResolvedValue(loginUriView);
loginUri.validateChecksum.mockResolvedValue(true);
login.uris = [loginUri];
const loginView = await login.decrypt(true, null);
expect(loginView).toEqual(expectedView);
});
it("should ignore uris that fail checksum", async () => {
loginUri.decrypt.mockResolvedValue(loginUriView);
loginUri.validateChecksum
.mockResolvedValueOnce(false)
.mockResolvedValueOnce(false)
.mockResolvedValueOnce(true);
login.uris = [loginUri, loginUri, loginUri];
const loginView = await login.decrypt(false, null);
expect(loginView).toEqual(expectedView);
});
});
it("Converts from LoginData and back", () => {
const data: LoginData = {
uris: [{ uri: "uri", uriChecksum: "checksum", match: UriMatchStrategy.Domain }],
username: "username",
password: "password",
passwordRevisionDate: "2022-01-31T12:00:00.000Z",
totp: "123",
autofillOnPageLoad: false,
fido2Credentials: [initializeFido2Credential(new Fido2CredentialData())],
};
const login = new Login(data);
const loginData = login.toLoginData();
expect(loginData).toEqual(data);
});
describe("fromJSON", () => {
it("initializes nested objects", () => {
jest.spyOn(EncString, "fromJSON").mockImplementation(mockFromJson);
jest.spyOn(LoginUri, "fromJSON").mockImplementation(mockFromJson);
const passwordRevisionDate = new Date("2022-01-31T12:00:00.000Z");
const fido2CreationDate = new Date("2023-01-01T12:00:00.000Z");
const actual = Login.fromJSON({
uris: ["loginUri1", "loginUri2"] as any,
username: "myUsername" as EncryptedString,
password: "myPassword" as EncryptedString,
passwordRevisionDate: passwordRevisionDate.toISOString(),
totp: "myTotp" as EncryptedString,
// NOTE: `as any` is here until we migrate to Nx: https://bitwarden.atlassian.net/browse/PM-6493
fido2Credentials: [
{
credentialId: "keyId" as EncryptedString,
keyType: "keyType" as EncryptedString,
keyAlgorithm: "keyAlgorithm" as EncryptedString,
keyCurve: "keyCurve" as EncryptedString,
keyValue: "keyValue" as EncryptedString,
rpId: "rpId" as EncryptedString,
userHandle: "userHandle" as EncryptedString,
userName: "userName" as EncryptedString,
counter: "counter" as EncryptedString,
rpName: "rpName" as EncryptedString,
userDisplayName: "userDisplayName" as EncryptedString,
discoverable: "discoverable" as EncryptedString,
creationDate: fido2CreationDate.toISOString(),
},
] as any,
});
expect(actual).toEqual({
uris: ["loginUri1_fromJSON", "loginUri2_fromJSON"] as any,
username: "myUsername_fromJSON",
password: "myPassword_fromJSON",
passwordRevisionDate: passwordRevisionDate,
totp: "myTotp_fromJSON",
fido2Credentials: [
{
credentialId: "keyId_fromJSON",
keyType: "keyType_fromJSON",
keyAlgorithm: "keyAlgorithm_fromJSON",
keyCurve: "keyCurve_fromJSON",
keyValue: "keyValue_fromJSON",
rpId: "rpId_fromJSON",
userHandle: "userHandle_fromJSON",
userName: "userName_fromJSON",
counter: "counter_fromJSON",
rpName: "rpName_fromJSON",
userDisplayName: "userDisplayName_fromJSON",
discoverable: "discoverable_fromJSON",
creationDate: fido2CreationDate,
},
],
});
expect(actual).toBeInstanceOf(Login);
});
it("returns undefined if object is null", () => {
expect(Login.fromJSON(null)).toBeUndefined();
});
});
describe("toSdkLogin", () => {
it("should map to SDK login", () => {
const data: LoginData = {
uris: [{ uri: "uri", uriChecksum: "checksum", match: UriMatchStrategy.Domain }],
username: "username",
password: "password",
passwordRevisionDate: "2022-01-31T12:00:00.000Z",
totp: "123",
autofillOnPageLoad: false,
fido2Credentials: [initializeFido2Credential(new Fido2CredentialData())],
};
const login = new Login(data);
const sdkLogin = login.toSdkLogin();
expect(sdkLogin).toEqual({
username: "username",
password: "password",
passwordRevisionDate: "2022-01-31T12:00:00.000Z",
uris: [
{
match: 0,
uri: "uri",
uriChecksum: "checksum",
},
],
totp: "123",
autofillOnPageLoad: false,
fido2Credentials: [
{
credentialId: "credentialId",
keyType: "public-key",
keyAlgorithm: "ECDSA",
keyCurve: "P-256",
keyValue: "keyValue",
rpId: "rpId",
userHandle: "userHandle",
userName: "userName",
counter: "counter",
rpName: "rpName",
userDisplayName: "userDisplayName",
discoverable: "discoverable",
creationDate: "2023-01-01T12:00:00.000Z",
},
],
});
});
});
});
type Fido2CredentialLike = Fido2CredentialData | Fido2CredentialView | Fido2CredentialApi;
function initializeFido2Credential<T extends Fido2CredentialLike>(key: T): T {
key.credentialId = "credentialId";
key.keyType = "public-key";
key.keyAlgorithm = "ECDSA";
key.keyCurve = "P-256";
key.keyValue = "keyValue";
key.rpId = "rpId";
key.userHandle = "userHandle";
key.userName = "userName";
key.counter = "counter";
key.rpName = "rpName";
key.userDisplayName = "userDisplayName";
key.discoverable = "discoverable";
key.creationDate = "2023-01-01T12:00:00.000Z";
return key;
}
function encryptFido2Credential(key: Fido2CredentialLike): Fido2Credential {
const encrypted = new Fido2Credential();
encrypted.credentialId = { encryptedString: key.credentialId, encryptionType: 0 } as EncString;
encrypted.keyType = { encryptedString: key.keyType, encryptionType: 0 } as EncString;
encrypted.keyAlgorithm = { encryptedString: key.keyAlgorithm, encryptionType: 0 } as EncString;
encrypted.keyCurve = { encryptedString: key.keyCurve, encryptionType: 0 } as EncString;
encrypted.keyValue = { encryptedString: key.keyValue, encryptionType: 0 } as EncString;
encrypted.rpId = { encryptedString: key.rpId, encryptionType: 0 } as EncString;
encrypted.userHandle = { encryptedString: key.userHandle, encryptionType: 0 } as EncString;
encrypted.userName = { encryptedString: key.userName, encryptionType: 0 } as EncString;
encrypted.counter = { encryptedString: key.counter, encryptionType: 0 } as EncString;
encrypted.rpName = { encryptedString: key.rpName, encryptionType: 0 } as EncString;
encrypted.userDisplayName = {
encryptedString: key.userDisplayName,
encryptionType: 0,
} as EncString;
encrypted.discoverable = { encryptedString: key.discoverable, encryptionType: 0 } as EncString;
// not encrypted
encrypted.creationDate = new Date(key.creationDate);
return encrypted;
}