1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-06 00:13:28 +00:00

[PM-17577] Inactive two-step login report - check hostname and domain name (#16823)

This commit is contained in:
Vijay Oommen
2025-10-29 10:58:38 -05:00
committed by GitHub
parent d567530e15
commit 687f3d144c
2 changed files with 160 additions and 0 deletions

View File

@@ -121,4 +121,153 @@ describe("InactiveTwoFactorReportComponent", () => {
it("should call fullSync method of syncService", () => {
expect(syncServiceMock.fullSync).toHaveBeenCalledWith(false);
});
describe("isInactive2faCipher", () => {
beforeEach(() => {
// Add both domain and host to services map
component.services.set("example.com", "https://example.com/2fa-doc");
component.services.set("sub.example.com", "https://sub.example.com/2fa-doc");
fixture.detectChanges();
});
it("should return true and documentation for cipher with matching domain", () => {
const cipher = createCipherView({
login: {
uris: [{ uri: "https://example.com/login" }],
},
});
const [doc, isInactive] = (component as any).isInactive2faCipher(cipher);
expect(isInactive).toBe(true);
expect(doc).toBe("https://example.com/2fa-doc");
});
it("should return true and documentation for cipher with matching host", () => {
const cipher = createCipherView({
login: {
uris: [{ uri: "https://sub.example.com/login" }],
},
});
const [doc, isInactive] = (component as any).isInactive2faCipher(cipher);
expect(isInactive).toBe(true);
expect(doc).toBe("https://sub.example.com/2fa-doc");
});
it("should return false for cipher with non-matching domain or host", () => {
const cipher = createCipherView({
login: {
uris: [{ uri: "https://otherdomain.com/login" }],
},
});
const [doc, isInactive] = (component as any).isInactive2faCipher(cipher);
expect(isInactive).toBe(false);
expect(doc).toBe("");
});
it("should return false if cipher type is not Login", () => {
const cipher = createCipherView({
type: 2,
login: {
uris: [{ uri: "https://example.com/login" }],
},
});
const [doc, isInactive] = (component as any).isInactive2faCipher(cipher);
expect(isInactive).toBe(false);
expect(doc).toBe("");
});
it("should return false if cipher has TOTP", () => {
const cipher = createCipherView({
login: {
totp: "some-totp",
uris: [{ uri: "https://example.com/login" }],
},
});
const [doc, isInactive] = (component as any).isInactive2faCipher(cipher);
expect(isInactive).toBe(false);
expect(doc).toBe("");
});
it("should return false if cipher is deleted", () => {
const cipher = createCipherView({
isDeleted: true,
login: {
uris: [{ uri: "https://example.com/login" }],
},
});
const [doc, isInactive] = (component as any).isInactive2faCipher(cipher);
expect(isInactive).toBe(false);
expect(doc).toBe("");
});
it("should return false if cipher does not have edit access and no organization", () => {
component.organization = null;
const cipher = createCipherView({
edit: false,
login: {
uris: [{ uri: "https://example.com/login" }],
},
});
const [doc, isInactive] = (component as any).isInactive2faCipher(cipher);
expect(isInactive).toBe(false);
expect(doc).toBe("");
});
it("should return false if cipher does not have viewPassword", () => {
const cipher = createCipherView({
viewPassword: false,
login: {
uris: [{ uri: "https://example.com/login" }],
},
});
const [doc, isInactive] = (component as any).isInactive2faCipher(cipher);
expect(isInactive).toBe(false);
expect(doc).toBe("");
});
it("should check all uris and return true if any matches domain or host", () => {
const cipher = createCipherView({
login: {
uris: [
{ uri: "https://otherdomain.com/login" },
{ uri: "https://sub.example.com/dashboard" },
],
},
});
const [doc, isInactive] = (component as any).isInactive2faCipher(cipher);
expect(isInactive).toBe(true);
expect(doc).toBe("https://sub.example.com/2fa-doc");
});
it("should return false if uris array is empty", () => {
const cipher = createCipherView({
login: {
uris: [],
},
});
const [doc, isInactive] = (component as any).isInactive2faCipher(cipher);
expect(isInactive).toBe(false);
expect(doc).toBe("");
});
function createCipherView({
type = 1,
login = {},
isDeleted = false,
edit = true,
viewPassword = true,
}: any): any {
return {
id: "test-id",
type,
login: {
totp: null,
hasUris: true,
uris: [],
...login,
},
isDeleted,
edit,
viewPassword,
};
}
});
});

View File

@@ -109,7 +109,18 @@ export class InactiveTwoFactorReportComponent extends CipherReportComponent impl
const u = login.uris[i];
if (u.uri != null && u.uri !== "") {
const uri = u.uri.replace("www.", "");
const host = Utils.getHost(uri);
const domain = Utils.getDomain(uri);
// check host first
if (host != null && this.services.has(host)) {
if (this.services.get(host) != null) {
docFor2fa = this.services.get(host) || "";
}
isInactive2faCipher = true;
break;
}
// then check domain
if (domain != null && this.services.has(domain)) {
if (this.services.get(domain) != null) {
docFor2fa = this.services.get(domain) || "";