2023-06-29 18:26:45 +02:00
|
|
|
import o from "@tutao/otest"
|
2024-07-01 17:56:41 +02:00
|
|
|
import { MailFacade, phishingMarkerValue, validateMimeTypesForAttachments } from "../../../../../src/common/api/worker/facades/lazy/MailFacade.js"
|
2024-05-06 11:08:05 +02:00
|
|
|
import {
|
2025-05-22 14:36:58 +02:00
|
|
|
FileTypeRef,
|
2024-05-06 11:08:05 +02:00
|
|
|
InternalRecipientKeyDataTypeRef,
|
2025-05-02 17:38:27 +02:00
|
|
|
Mail,
|
2024-05-06 11:08:05 +02:00
|
|
|
MailAddressTypeRef,
|
|
|
|
|
MailTypeRef,
|
|
|
|
|
ReportedMailFieldMarkerTypeRef,
|
|
|
|
|
SecureExternalRecipientKeyDataTypeRef,
|
|
|
|
|
SendDraftDataTypeRef,
|
|
|
|
|
SymEncInternalRecipientKeyDataTypeRef,
|
2024-07-01 17:56:41 +02:00
|
|
|
} from "../../../../../src/common/api/entities/tutanota/TypeRefs.js"
|
2025-02-10 15:59:28 +01:00
|
|
|
import {
|
|
|
|
|
CryptoProtocolVersion,
|
|
|
|
|
MailAuthenticationStatus,
|
|
|
|
|
MAX_NBR_MOVE_DELETE_MAIL_SERVICE,
|
|
|
|
|
ReportedMailFieldType,
|
|
|
|
|
} from "../../../../../src/common/api/common/TutanotaConstants.js"
|
2025-05-02 17:38:27 +02:00
|
|
|
import { matchers, object, when } from "testdouble"
|
2024-07-01 17:56:41 +02:00
|
|
|
import { CryptoFacade } from "../../../../../src/common/api/worker/crypto/CryptoFacade.js"
|
|
|
|
|
import { IServiceExecutor } from "../../../../../src/common/api/common/ServiceRequest.js"
|
|
|
|
|
import { EntityClient } from "../../../../../src/common/api/common/EntityClient.js"
|
|
|
|
|
import { BlobFacade } from "../../../../../src/common/api/worker/facades/lazy/BlobFacade.js"
|
|
|
|
|
import { UserFacade } from "../../../../../src/common/api/worker/facades/UserFacade"
|
|
|
|
|
import { NativeFileApp } from "../../../../../src/common/native/common/FileApp.js"
|
|
|
|
|
import { LoginFacade } from "../../../../../src/common/api/worker/facades/LoginFacade.js"
|
|
|
|
|
import { DataFile } from "../../../../../src/common/api/common/DataFile.js"
|
2025-05-22 14:36:58 +02:00
|
|
|
import { downcast, KeyVersion, lazyNumberRange } from "@tutao/tutanota-utils"
|
2024-07-01 17:56:41 +02:00
|
|
|
import { ProgrammingError } from "../../../../../src/common/api/common/error/ProgrammingError.js"
|
2023-11-10 16:59:39 +01:00
|
|
|
import { createTestEntity } from "../../../TestUtils.js"
|
2024-07-01 17:56:41 +02:00
|
|
|
import { KeyLoaderFacade } from "../../../../../src/common/api/worker/facades/KeyLoaderFacade.js"
|
2025-01-20 13:40:57 +01:00
|
|
|
import { PublicKeyProvider } from "../../../../../src/common/api/worker/facades/PublicKeyProvider.js"
|
2025-02-10 15:59:28 +01:00
|
|
|
import { verify } from "@tutao/tutanota-test-utils"
|
|
|
|
|
import { UnreadMailStateService } from "../../../../../src/common/api/entities/tutanota/Services"
|
2025-05-02 17:38:27 +02:00
|
|
|
import { BucketKeyTypeRef, InstanceSessionKey, InstanceSessionKeyTypeRef } from "../../../../../src/common/api/entities/sys/TypeRefs"
|
|
|
|
|
import { OwnerEncSessionKeyProvider } from "../../../../../src/common/api/worker/rest/EntityRestClient"
|
2025-05-22 14:36:58 +02:00
|
|
|
import { elementIdPart, getElementId } from "../../../../../src/common/api/common/utils/EntityUtils"
|
|
|
|
|
import { VersionedEncryptedKey } from "../../../../../src/common/api/worker/crypto/CryptoWrapper"
|
2020-03-16 17:37:50 +01:00
|
|
|
|
|
|
|
|
o.spec("MailFacade test", function () {
|
|
|
|
|
let facade: MailFacade
|
2022-04-12 14:23:38 +02:00
|
|
|
let userFacade: UserFacade
|
2022-03-09 17:43:29 +01:00
|
|
|
let cryptoFacade: CryptoFacade
|
|
|
|
|
let serviceExecutor: IServiceExecutor
|
|
|
|
|
let entity: EntityClient
|
2022-03-16 10:14:53 +01:00
|
|
|
let blobFacade: BlobFacade
|
2022-08-09 15:04:15 +02:00
|
|
|
let fileApp: NativeFileApp
|
2023-07-17 11:42:02 +02:00
|
|
|
let loginFacade: LoginFacade
|
2024-04-17 10:34:33 +02:00
|
|
|
let keyLoaderFacade: KeyLoaderFacade
|
2025-01-20 13:40:57 +01:00
|
|
|
let publicKeyProvider: PublicKeyProvider
|
2022-03-09 17:43:29 +01:00
|
|
|
|
2020-03-16 17:37:50 +01:00
|
|
|
o.beforeEach(function () {
|
2022-04-12 14:23:38 +02:00
|
|
|
userFacade = object()
|
2022-03-16 10:14:53 +01:00
|
|
|
blobFacade = object()
|
2022-03-09 17:43:29 +01:00
|
|
|
entity = object()
|
|
|
|
|
cryptoFacade = object()
|
|
|
|
|
serviceExecutor = object()
|
2022-08-09 15:04:15 +02:00
|
|
|
fileApp = object()
|
2023-07-17 11:42:02 +02:00
|
|
|
loginFacade = object()
|
2024-04-17 10:34:33 +02:00
|
|
|
keyLoaderFacade = object()
|
2025-01-20 13:40:57 +01:00
|
|
|
publicKeyProvider = object()
|
|
|
|
|
facade = new MailFacade(userFacade, entity, cryptoFacade, serviceExecutor, blobFacade, fileApp, loginFacade, keyLoaderFacade, publicKeyProvider)
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
o.spec("checkMailForPhishing", function () {
|
|
|
|
|
o("not phishing if no markers", async function () {
|
2023-11-10 16:59:39 +01:00
|
|
|
const mail = createTestEntity(MailTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
subject: "Test",
|
|
|
|
|
authStatus: MailAuthenticationStatus.AUTHENTICATED,
|
2023-11-10 16:59:39 +01:00
|
|
|
sender: createTestEntity(MailAddressTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
name: "a",
|
|
|
|
|
address: "test@example.com",
|
2022-12-27 15:37:40 +01:00
|
|
|
}),
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
2022-12-27 15:37:40 +01:00
|
|
|
o(await facade.checkMailForPhishing(mail, [{ href: "https://example.com", innerHTML: "link" }])).equals(false)
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
o("not phishing if no matching markers", async function () {
|
2023-11-10 16:59:39 +01:00
|
|
|
const mail = createTestEntity(MailTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
subject: "Test",
|
|
|
|
|
authStatus: MailAuthenticationStatus.AUTHENTICATED,
|
2023-11-10 16:59:39 +01:00
|
|
|
sender: createTestEntity(MailAddressTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
name: "a",
|
2022-12-27 15:37:40 +01:00
|
|
|
address: "test@example.com",
|
|
|
|
|
}),
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
2020-06-02 13:39:22 +02:00
|
|
|
facade.phishingMarkersUpdateReceived([
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2020-06-02 13:39:22 +02:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test 2"),
|
|
|
|
|
}),
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2022-12-27 15:37:40 +01:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.FROM_DOMAIN, "example2.com"),
|
|
|
|
|
}),
|
2020-06-02 13:39:22 +02:00
|
|
|
])
|
2020-03-16 17:37:50 +01:00
|
|
|
|
2022-12-27 15:37:40 +01:00
|
|
|
o(await facade.checkMailForPhishing(mail, [{ href: "https://example.com", innerHTML: "link" }])).equals(false)
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
o("not phishing if only from domain matches", async function () {
|
2023-11-10 16:59:39 +01:00
|
|
|
const mail = createTestEntity(MailTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
subject: "Test",
|
|
|
|
|
authStatus: MailAuthenticationStatus.AUTHENTICATED,
|
2023-11-10 16:59:39 +01:00
|
|
|
sender: createTestEntity(MailAddressTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
name: "a",
|
2022-12-27 15:37:40 +01:00
|
|
|
address: "test@example.com",
|
|
|
|
|
}),
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
2020-06-02 13:39:22 +02:00
|
|
|
facade.phishingMarkersUpdateReceived([
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2020-06-02 13:39:22 +02:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test 2"),
|
|
|
|
|
}),
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2022-12-27 15:37:40 +01:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.FROM_DOMAIN, "example.com"),
|
|
|
|
|
}),
|
2020-06-02 13:39:22 +02:00
|
|
|
])
|
2020-03-16 17:37:50 +01:00
|
|
|
|
2022-12-27 15:37:40 +01:00
|
|
|
o(await facade.checkMailForPhishing(mail, [{ href: "https://example.com", innerHTML: "link" }])).equals(false)
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
o("not phishing if only subject matches", async function () {
|
2023-11-10 16:59:39 +01:00
|
|
|
const mail = createTestEntity(MailTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
subject: "Test",
|
|
|
|
|
authStatus: MailAuthenticationStatus.AUTHENTICATED,
|
2023-11-10 16:59:39 +01:00
|
|
|
sender: createTestEntity(MailAddressTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
name: "a",
|
2022-12-27 15:37:40 +01:00
|
|
|
address: "test@example.com",
|
|
|
|
|
}),
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
2020-06-02 13:39:22 +02:00
|
|
|
facade.phishingMarkersUpdateReceived([
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2020-06-02 13:39:22 +02:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"),
|
|
|
|
|
}),
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2022-12-27 15:37:40 +01:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.FROM_DOMAIN, "example2.com"),
|
|
|
|
|
}),
|
2020-06-02 13:39:22 +02:00
|
|
|
])
|
2020-03-16 17:37:50 +01:00
|
|
|
|
2022-12-27 15:37:40 +01:00
|
|
|
o(await facade.checkMailForPhishing(mail, [{ href: "https://example.com", innerHTML: "link" }])).equals(false)
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
o("is phishing if subject and sender domain matches", async function () {
|
2023-11-10 16:59:39 +01:00
|
|
|
const mail = createTestEntity(MailTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
subject: "Test",
|
|
|
|
|
authStatus: MailAuthenticationStatus.AUTHENTICATED,
|
2023-11-10 16:59:39 +01:00
|
|
|
sender: createTestEntity(MailAddressTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
name: "a",
|
2022-12-27 15:37:40 +01:00
|
|
|
address: "test@example.com",
|
|
|
|
|
}),
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
2020-06-02 13:39:22 +02:00
|
|
|
facade.phishingMarkersUpdateReceived([
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2020-06-02 13:39:22 +02:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"),
|
|
|
|
|
}),
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2022-12-27 15:37:40 +01:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.FROM_DOMAIN, "example.com"),
|
|
|
|
|
}),
|
2020-06-02 13:39:22 +02:00
|
|
|
])
|
2020-03-16 17:37:50 +01:00
|
|
|
|
2022-12-27 15:37:40 +01:00
|
|
|
o(await facade.checkMailForPhishing(mail, [{ href: "https://example.com", innerHTML: "link" }])).equals(true)
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
o("is phishing if subject with whitespaces and sender domain matches", async function () {
|
2023-11-10 16:59:39 +01:00
|
|
|
const mail = createTestEntity(MailTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
subject: "\tTest spaces \n",
|
|
|
|
|
authStatus: MailAuthenticationStatus.AUTHENTICATED,
|
2023-11-10 16:59:39 +01:00
|
|
|
sender: createTestEntity(MailAddressTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
name: "a",
|
2022-12-27 15:37:40 +01:00
|
|
|
address: "test@example.com",
|
|
|
|
|
}),
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
2020-06-02 13:39:22 +02:00
|
|
|
facade.phishingMarkersUpdateReceived([
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2020-06-02 13:39:22 +02:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Testspaces"),
|
|
|
|
|
}),
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2022-12-27 15:37:40 +01:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.FROM_DOMAIN, "example.com"),
|
|
|
|
|
}),
|
2020-06-02 13:39:22 +02:00
|
|
|
])
|
2020-03-16 17:37:50 +01:00
|
|
|
|
2022-12-27 15:37:40 +01:00
|
|
|
o(await facade.checkMailForPhishing(mail, [{ href: "https://example.com", innerHTML: "link" }])).equals(true)
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
o("is not phishing if subject and sender domain matches but not authenticated", async function () {
|
2023-11-10 16:59:39 +01:00
|
|
|
const mail = createTestEntity(MailTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
subject: "Test",
|
|
|
|
|
authStatus: MailAuthenticationStatus.SOFT_FAIL,
|
2023-11-10 16:59:39 +01:00
|
|
|
sender: createTestEntity(MailAddressTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
name: "a",
|
2022-12-27 15:37:40 +01:00
|
|
|
address: "test@example.com",
|
|
|
|
|
}),
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
2020-06-02 13:39:22 +02:00
|
|
|
facade.phishingMarkersUpdateReceived([
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2020-06-02 13:39:22 +02:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"),
|
|
|
|
|
}),
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2022-12-27 15:37:40 +01:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.FROM_DOMAIN, "example.com"),
|
|
|
|
|
}),
|
2020-06-02 13:39:22 +02:00
|
|
|
])
|
2020-03-16 17:37:50 +01:00
|
|
|
|
2022-12-27 15:37:40 +01:00
|
|
|
o(await facade.checkMailForPhishing(mail, [{ href: "https://example.com", innerHTML: "link" }])).equals(false)
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
o("is phishing if subject and sender address matches", async function () {
|
2023-11-10 16:59:39 +01:00
|
|
|
const mail = createTestEntity(MailTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
subject: "Test",
|
|
|
|
|
authStatus: MailAuthenticationStatus.AUTHENTICATED,
|
2023-11-10 16:59:39 +01:00
|
|
|
sender: createTestEntity(MailAddressTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
name: "a",
|
2022-12-27 15:37:40 +01:00
|
|
|
address: "test@example.com",
|
|
|
|
|
}),
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
2020-06-02 13:39:22 +02:00
|
|
|
facade.phishingMarkersUpdateReceived([
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2020-06-02 13:39:22 +02:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"),
|
|
|
|
|
}),
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2022-12-27 15:37:40 +01:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.FROM_ADDRESS, "test@example.com"),
|
|
|
|
|
}),
|
2020-06-02 13:39:22 +02:00
|
|
|
])
|
2020-03-16 17:37:50 +01:00
|
|
|
|
2022-12-27 15:37:40 +01:00
|
|
|
o(await facade.checkMailForPhishing(mail, [{ href: "https://example.com", innerHTML: "link" }])).equals(true)
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
o("is not phishing if subject and sender address matches but not authenticated", async function () {
|
2023-11-10 16:59:39 +01:00
|
|
|
const mail = createTestEntity(MailTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
subject: "Test",
|
|
|
|
|
authStatus: MailAuthenticationStatus.SOFT_FAIL,
|
2023-11-10 16:59:39 +01:00
|
|
|
sender: createTestEntity(MailAddressTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
name: "a",
|
2022-12-27 15:37:40 +01:00
|
|
|
address: "test@example.com",
|
|
|
|
|
}),
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
2020-06-02 13:39:22 +02:00
|
|
|
facade.phishingMarkersUpdateReceived([
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2020-06-02 13:39:22 +02:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"),
|
|
|
|
|
}),
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2022-12-27 15:37:40 +01:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.FROM_ADDRESS, "test@example.com"),
|
|
|
|
|
}),
|
2020-06-02 13:39:22 +02:00
|
|
|
])
|
2020-03-16 17:37:50 +01:00
|
|
|
|
2022-12-27 15:37:40 +01:00
|
|
|
o(await facade.checkMailForPhishing(mail, [{ href: "https://example.com", innerHTML: "link" }])).equals(false)
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
o("is phishing if subject and non auth sender domain matches", async function () {
|
2023-11-10 16:59:39 +01:00
|
|
|
const mail = createTestEntity(MailTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
subject: "Test",
|
|
|
|
|
authStatus: MailAuthenticationStatus.SOFT_FAIL,
|
2023-11-10 16:59:39 +01:00
|
|
|
sender: createTestEntity(MailAddressTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
name: "a",
|
2022-12-27 15:37:40 +01:00
|
|
|
address: "test@example.com",
|
|
|
|
|
}),
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
2020-06-02 13:39:22 +02:00
|
|
|
facade.phishingMarkersUpdateReceived([
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2020-06-02 13:39:22 +02:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"),
|
|
|
|
|
}),
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2022-12-27 15:37:40 +01:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.FROM_DOMAIN_NON_AUTH, "example.com"),
|
|
|
|
|
}),
|
2020-06-02 13:39:22 +02:00
|
|
|
])
|
2020-03-16 17:37:50 +01:00
|
|
|
|
2022-12-27 15:37:40 +01:00
|
|
|
o(await facade.checkMailForPhishing(mail, [{ href: "https://example.com", innerHTML: "link" }])).equals(true)
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
o("is phishing if subject and non auth sender address matches", async function () {
|
2023-11-10 16:59:39 +01:00
|
|
|
const mail = createTestEntity(MailTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
subject: "Test",
|
|
|
|
|
authStatus: MailAuthenticationStatus.SOFT_FAIL,
|
2023-11-10 16:59:39 +01:00
|
|
|
sender: createTestEntity(MailAddressTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
name: "a",
|
2022-12-27 15:37:40 +01:00
|
|
|
address: "test@example.com",
|
|
|
|
|
}),
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
2020-06-02 13:39:22 +02:00
|
|
|
facade.phishingMarkersUpdateReceived([
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2020-06-02 13:39:22 +02:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"),
|
|
|
|
|
}),
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2022-12-27 15:37:40 +01:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.FROM_ADDRESS_NON_AUTH, "test@example.com"),
|
|
|
|
|
}),
|
2020-06-02 13:39:22 +02:00
|
|
|
])
|
2020-03-16 17:37:50 +01:00
|
|
|
|
2022-12-27 15:37:40 +01:00
|
|
|
o(await facade.checkMailForPhishing(mail, [{ href: "https://example.com", innerHTML: "link" }])).equals(true)
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
o("is phishing if subject and link matches", async function () {
|
2023-11-10 16:59:39 +01:00
|
|
|
const mail = createTestEntity(MailTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
subject: "Test",
|
|
|
|
|
authStatus: MailAuthenticationStatus.AUTHENTICATED,
|
2023-11-10 16:59:39 +01:00
|
|
|
sender: createTestEntity(MailAddressTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
name: "a",
|
2022-12-27 15:37:40 +01:00
|
|
|
address: "test@example.com",
|
|
|
|
|
}),
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
2020-06-02 13:39:22 +02:00
|
|
|
facade.phishingMarkersUpdateReceived([
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2020-06-02 13:39:22 +02:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"),
|
|
|
|
|
}),
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2022-12-27 15:37:40 +01:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.LINK, "https://example.com"),
|
|
|
|
|
}),
|
2020-06-02 13:39:22 +02:00
|
|
|
])
|
2020-03-16 17:37:50 +01:00
|
|
|
|
2022-12-27 15:37:40 +01:00
|
|
|
o(await facade.checkMailForPhishing(mail, [{ href: "https://example.com", innerHTML: "link" }])).equals(true)
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
o("is not phishing if just two links match", async function () {
|
2023-11-10 16:59:39 +01:00
|
|
|
const mail = createTestEntity(MailTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
subject: "Test",
|
|
|
|
|
authStatus: MailAuthenticationStatus.AUTHENTICATED,
|
2023-11-10 16:59:39 +01:00
|
|
|
sender: createTestEntity(MailAddressTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
name: "a",
|
2022-12-27 15:37:40 +01:00
|
|
|
address: "test@example.com",
|
|
|
|
|
}),
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
2020-06-02 13:39:22 +02:00
|
|
|
facade.phishingMarkersUpdateReceived([
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2020-06-02 13:39:22 +02:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.LINK, "https://example.com"),
|
|
|
|
|
}),
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2022-12-27 15:37:40 +01:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.LINK, "https://example2.com"),
|
|
|
|
|
}),
|
2020-06-02 13:39:22 +02:00
|
|
|
])
|
2020-03-16 17:37:50 +01:00
|
|
|
|
2022-12-27 15:37:40 +01:00
|
|
|
o(
|
|
|
|
|
await facade.checkMailForPhishing(mail, [
|
|
|
|
|
{ href: "https://example.com", innerHTML: "link1" },
|
|
|
|
|
{ href: "https://example2.com", innerHTML: "link2" },
|
|
|
|
|
]),
|
|
|
|
|
).equals(false)
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
o("is phishing if subject and link domain matches", async function () {
|
2023-11-10 16:59:39 +01:00
|
|
|
const mail = createTestEntity(MailTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
subject: "Test",
|
|
|
|
|
authStatus: MailAuthenticationStatus.AUTHENTICATED,
|
2023-11-10 16:59:39 +01:00
|
|
|
sender: createTestEntity(MailAddressTypeRef, {
|
2020-03-16 17:37:50 +01:00
|
|
|
name: "a",
|
2022-12-27 15:37:40 +01:00
|
|
|
address: "test@example.com",
|
|
|
|
|
}),
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
2020-06-02 13:39:22 +02:00
|
|
|
facade.phishingMarkersUpdateReceived([
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2020-06-02 13:39:22 +02:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"),
|
|
|
|
|
}),
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2022-12-27 15:37:40 +01:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.LINK_DOMAIN, "example.com"),
|
|
|
|
|
}),
|
2020-06-02 13:39:22 +02:00
|
|
|
])
|
2020-03-16 17:37:50 +01:00
|
|
|
|
2022-12-27 15:37:40 +01:00
|
|
|
o(await facade.checkMailForPhishing(mail, [{ href: "https://example.com", innerHTML: "link" }])).equals(true)
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
2020-04-14 15:28:24 +02:00
|
|
|
|
|
|
|
|
o("does not throw on invalid link", async function () {
|
2023-11-10 16:59:39 +01:00
|
|
|
const mail = createTestEntity(MailTypeRef, {
|
2020-04-14 15:28:24 +02:00
|
|
|
subject: "Test",
|
|
|
|
|
authStatus: MailAuthenticationStatus.AUTHENTICATED,
|
2023-11-10 16:59:39 +01:00
|
|
|
sender: createTestEntity(MailAddressTypeRef, {
|
2020-04-14 15:28:24 +02:00
|
|
|
name: "a",
|
2022-12-27 15:37:40 +01:00
|
|
|
address: "test@example.com",
|
|
|
|
|
}),
|
2020-04-14 15:28:24 +02:00
|
|
|
})
|
2020-06-02 13:39:22 +02:00
|
|
|
facade.phishingMarkersUpdateReceived([
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2020-06-02 13:39:22 +02:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"),
|
|
|
|
|
}),
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2022-12-27 15:37:40 +01:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.LINK_DOMAIN, "example.com"),
|
|
|
|
|
}),
|
2020-06-02 13:39:22 +02:00
|
|
|
])
|
2020-04-14 15:28:24 +02:00
|
|
|
|
2022-12-27 15:37:40 +01:00
|
|
|
o(
|
|
|
|
|
await facade.checkMailForPhishing(mail, [
|
|
|
|
|
{ href: "/example1", innerHTML: "link1" },
|
|
|
|
|
{ href: "example2", innerHTML: "link2" },
|
|
|
|
|
{ href: "http:/", innerHTML: "link3" },
|
|
|
|
|
]),
|
|
|
|
|
).equals(false)
|
2021-01-28 12:15:10 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
o("is phishing if subject and suspicious link", async function () {
|
2023-11-10 16:59:39 +01:00
|
|
|
const mail = createTestEntity(MailTypeRef, {
|
2021-01-28 12:15:10 +01:00
|
|
|
subject: "Test",
|
|
|
|
|
authStatus: MailAuthenticationStatus.AUTHENTICATED,
|
2023-11-10 16:59:39 +01:00
|
|
|
sender: createTestEntity(MailAddressTypeRef, {
|
2021-01-28 12:15:10 +01:00
|
|
|
name: "a",
|
2022-12-27 15:37:40 +01:00
|
|
|
address: "test@example.com",
|
|
|
|
|
}),
|
2021-01-28 12:15:10 +01:00
|
|
|
})
|
|
|
|
|
facade.phishingMarkersUpdateReceived([
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2021-01-28 12:15:10 +01:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"),
|
|
|
|
|
}),
|
|
|
|
|
])
|
|
|
|
|
|
2025-02-10 15:59:28 +01:00
|
|
|
o(
|
|
|
|
|
await facade.checkMailForPhishing(mail, [
|
|
|
|
|
{
|
|
|
|
|
href: "https://example.com",
|
|
|
|
|
innerHTML: "https://evil-domain.com",
|
|
|
|
|
},
|
|
|
|
|
]),
|
|
|
|
|
).equals(true)
|
2021-01-28 12:15:10 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
o("link is not suspicious if on the same domain", async function () {
|
2023-11-10 16:59:39 +01:00
|
|
|
const mail = createTestEntity(MailTypeRef, {
|
2021-01-28 12:15:10 +01:00
|
|
|
subject: "Test",
|
|
|
|
|
authStatus: MailAuthenticationStatus.AUTHENTICATED,
|
2023-11-10 16:59:39 +01:00
|
|
|
sender: createTestEntity(MailAddressTypeRef, {
|
2021-01-28 12:15:10 +01:00
|
|
|
name: "a",
|
2022-12-27 15:37:40 +01:00
|
|
|
address: "test@example.com",
|
|
|
|
|
}),
|
2021-01-28 12:15:10 +01:00
|
|
|
})
|
|
|
|
|
facade.phishingMarkersUpdateReceived([
|
2023-11-10 16:59:39 +01:00
|
|
|
createTestEntity(ReportedMailFieldMarkerTypeRef, {
|
2021-01-28 12:15:10 +01:00
|
|
|
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"),
|
|
|
|
|
}),
|
|
|
|
|
])
|
|
|
|
|
|
2025-02-10 15:59:28 +01:00
|
|
|
o(
|
|
|
|
|
await facade.checkMailForPhishing(mail, [
|
|
|
|
|
{
|
|
|
|
|
href: "https://example.com",
|
|
|
|
|
innerHTML: "https://example.com/test",
|
|
|
|
|
},
|
|
|
|
|
]),
|
|
|
|
|
).equals(false)
|
2020-04-14 15:28:24 +02:00
|
|
|
})
|
2020-03-16 17:37:50 +01:00
|
|
|
})
|
2023-09-01 11:03:46 +02:00
|
|
|
|
|
|
|
|
o.spec("verifyMimeTypesForAttachments", () => {
|
|
|
|
|
function attach(mimeType, name): DataFile {
|
|
|
|
|
return downcast({
|
|
|
|
|
mimeType,
|
|
|
|
|
name,
|
|
|
|
|
_type: "DataFile",
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
o("valid mimetypes", () => {
|
|
|
|
|
validateMimeTypesForAttachments([attach("application/json", "something.json")])
|
2023-11-16 14:55:52 +01:00
|
|
|
validateMimeTypesForAttachments([attach("audio/ogg; codec=opus", "something.opus")])
|
|
|
|
|
validateMimeTypesForAttachments([attach('video/webm; codecs="vp8, opus"', "something.webm")])
|
2023-09-01 11:03:46 +02:00
|
|
|
validateMimeTypesForAttachments([attach("something/orrather", "something.somethingorrather")])
|
|
|
|
|
validateMimeTypesForAttachments([attach("thisisvalid/technically+this_is-ok_even-if-YOU-dont-like-it", "something.valid")])
|
2023-11-16 14:55:52 +01:00
|
|
|
validateMimeTypesForAttachments([attach("anotherthing/youcando;ishave=multiple;parameters=in;a=mimetype", "something.technicallyvalidaswell")])
|
2023-09-01 11:03:46 +02:00
|
|
|
})
|
|
|
|
|
|
2023-11-16 14:55:52 +01:00
|
|
|
o("invalid mimetypes", () => {
|
|
|
|
|
o(() => {
|
2023-09-01 11:03:46 +02:00
|
|
|
validateMimeTypesForAttachments([attach("applicationjson", "something.json")])
|
2023-11-16 14:55:52 +01:00
|
|
|
}).throws(ProgrammingError)
|
|
|
|
|
o(() => {
|
2023-09-01 11:03:46 +02:00
|
|
|
validateMimeTypesForAttachments([attach("application/json", "something.json"), attach("applicationjson", "something.json")])
|
2023-11-16 14:55:52 +01:00
|
|
|
}).throws(ProgrammingError)
|
|
|
|
|
o(() => {
|
2023-09-01 11:03:46 +02:00
|
|
|
validateMimeTypesForAttachments([attach("applicationjson", "something.json"), attach("application/json", "something.json")])
|
2023-11-16 14:55:52 +01:00
|
|
|
}).throws(ProgrammingError)
|
|
|
|
|
o(() => {
|
2023-09-01 11:03:46 +02:00
|
|
|
validateMimeTypesForAttachments([attach("", "bad.json")])
|
2023-11-16 14:55:52 +01:00
|
|
|
}).throws(ProgrammingError)
|
|
|
|
|
o(() => {
|
2023-09-01 11:03:46 +02:00
|
|
|
validateMimeTypesForAttachments([attach("a/b/c", "no.json")])
|
2023-11-16 14:55:52 +01:00
|
|
|
}).throws(ProgrammingError)
|
|
|
|
|
o(() => {
|
2023-09-01 11:03:46 +02:00
|
|
|
validateMimeTypesForAttachments([attach("a/b?c", "please stop.json")])
|
2023-11-16 14:55:52 +01:00
|
|
|
}).throws(ProgrammingError)
|
|
|
|
|
o(() => {
|
|
|
|
|
validateMimeTypesForAttachments([attach('video/webm; codecs="vp8, opus oh no i forgot the quote; oops=mybad', "why.webm")])
|
|
|
|
|
}).throws(ProgrammingError)
|
|
|
|
|
o(() => {
|
|
|
|
|
validateMimeTypesForAttachments([attach("video/webm; parameterwithoutavalue", "bad.webm")])
|
|
|
|
|
}).throws(ProgrammingError)
|
2023-09-01 11:03:46 +02:00
|
|
|
})
|
2024-05-06 11:08:05 +02:00
|
|
|
|
|
|
|
|
o("isTutaCryptMail", () => {
|
|
|
|
|
const pqRecipient = createTestEntity(InternalRecipientKeyDataTypeRef, { protocolVersion: CryptoProtocolVersion.TUTA_CRYPT })
|
|
|
|
|
const rsaRecipient = createTestEntity(InternalRecipientKeyDataTypeRef, { protocolVersion: CryptoProtocolVersion.RSA })
|
|
|
|
|
const secureExternalRecipient = createTestEntity(SecureExternalRecipientKeyDataTypeRef, {})
|
|
|
|
|
const symEncInternalRecipient = createTestEntity(SymEncInternalRecipientKeyDataTypeRef, {})
|
|
|
|
|
|
|
|
|
|
o(
|
|
|
|
|
facade.isTutaCryptMail(
|
|
|
|
|
createTestEntity(SendDraftDataTypeRef, {
|
|
|
|
|
internalRecipientKeyData: [pqRecipient],
|
|
|
|
|
secureExternalRecipientKeyData: [],
|
|
|
|
|
symEncInternalRecipientKeyData: [],
|
|
|
|
|
}),
|
|
|
|
|
),
|
|
|
|
|
).equals(true)
|
|
|
|
|
|
|
|
|
|
o(
|
|
|
|
|
facade.isTutaCryptMail(
|
|
|
|
|
createTestEntity(SendDraftDataTypeRef, {
|
|
|
|
|
internalRecipientKeyData: [pqRecipient, pqRecipient],
|
|
|
|
|
secureExternalRecipientKeyData: [],
|
|
|
|
|
symEncInternalRecipientKeyData: [],
|
|
|
|
|
}),
|
|
|
|
|
),
|
|
|
|
|
).equals(true)
|
|
|
|
|
|
|
|
|
|
o(
|
|
|
|
|
facade.isTutaCryptMail(
|
|
|
|
|
createTestEntity(SendDraftDataTypeRef, {
|
|
|
|
|
internalRecipientKeyData: [],
|
|
|
|
|
secureExternalRecipientKeyData: [],
|
|
|
|
|
symEncInternalRecipientKeyData: [],
|
|
|
|
|
}),
|
|
|
|
|
),
|
|
|
|
|
).equals(false)
|
|
|
|
|
|
|
|
|
|
o(
|
|
|
|
|
facade.isTutaCryptMail(
|
|
|
|
|
createTestEntity(SendDraftDataTypeRef, {
|
|
|
|
|
internalRecipientKeyData: [pqRecipient, rsaRecipient],
|
|
|
|
|
secureExternalRecipientKeyData: [],
|
|
|
|
|
symEncInternalRecipientKeyData: [],
|
|
|
|
|
}),
|
|
|
|
|
),
|
|
|
|
|
).equals(false)
|
|
|
|
|
|
|
|
|
|
o(
|
|
|
|
|
facade.isTutaCryptMail(
|
|
|
|
|
createTestEntity(SendDraftDataTypeRef, {
|
|
|
|
|
internalRecipientKeyData: [pqRecipient],
|
|
|
|
|
secureExternalRecipientKeyData: [secureExternalRecipient],
|
|
|
|
|
symEncInternalRecipientKeyData: [],
|
|
|
|
|
}),
|
|
|
|
|
),
|
|
|
|
|
).equals(false)
|
|
|
|
|
|
|
|
|
|
o(
|
|
|
|
|
facade.isTutaCryptMail(
|
|
|
|
|
createTestEntity(SendDraftDataTypeRef, {
|
|
|
|
|
internalRecipientKeyData: [pqRecipient],
|
|
|
|
|
secureExternalRecipientKeyData: [],
|
|
|
|
|
symEncInternalRecipientKeyData: [symEncInternalRecipient],
|
|
|
|
|
}),
|
|
|
|
|
),
|
|
|
|
|
).equals(false)
|
|
|
|
|
})
|
2023-09-01 11:03:46 +02:00
|
|
|
})
|
2025-02-10 15:59:28 +01:00
|
|
|
o.spec("markMails", () => {
|
|
|
|
|
o.test("test with single mail", async () => {
|
|
|
|
|
const testIds: IdTuple[] = [["a", "b"]]
|
|
|
|
|
await facade.markMails(testIds, true)
|
|
|
|
|
verify(
|
|
|
|
|
serviceExecutor.post(
|
|
|
|
|
UnreadMailStateService,
|
|
|
|
|
matchers.contains({
|
|
|
|
|
mails: testIds,
|
|
|
|
|
unread: true,
|
|
|
|
|
}),
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
o.test("test with a few mails", async () => {
|
|
|
|
|
const testIds: IdTuple[] = [
|
|
|
|
|
["a", "b"],
|
|
|
|
|
["c", "d"],
|
|
|
|
|
]
|
|
|
|
|
await facade.markMails(testIds, true)
|
|
|
|
|
verify(
|
|
|
|
|
serviceExecutor.post(
|
|
|
|
|
UnreadMailStateService,
|
|
|
|
|
matchers.contains({
|
|
|
|
|
mails: testIds,
|
|
|
|
|
unread: true,
|
|
|
|
|
}),
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
o.test("batches large amounts of mails", async () => {
|
|
|
|
|
const expectedBatches = 4
|
|
|
|
|
const testIds: IdTuple[] = []
|
|
|
|
|
for (let i = 0; i < MAX_NBR_MOVE_DELETE_MAIL_SERVICE * expectedBatches; i++) {
|
|
|
|
|
testIds.push([`${i}`, `${i}`])
|
|
|
|
|
}
|
|
|
|
|
await facade.markMails(testIds, true)
|
|
|
|
|
for (let i = 0; i < expectedBatches; i++) {
|
|
|
|
|
verify(
|
|
|
|
|
serviceExecutor.post(
|
|
|
|
|
UnreadMailStateService,
|
|
|
|
|
matchers.contains({
|
|
|
|
|
mails: testIds.slice(i * MAX_NBR_MOVE_DELETE_MAIL_SERVICE, (i + 1) * MAX_NBR_MOVE_DELETE_MAIL_SERVICE),
|
|
|
|
|
unread: true,
|
|
|
|
|
}),
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
verify(serviceExecutor.post(UnreadMailStateService, matchers.anything()), { times: expectedBatches })
|
|
|
|
|
})
|
|
|
|
|
})
|
2025-05-02 17:38:27 +02:00
|
|
|
|
|
|
|
|
o.spec("createOwnerEncSessionKeyProviderForAttachments", () => {
|
2025-05-22 14:36:58 +02:00
|
|
|
function sessionKeyId(mailIndex: number, attachmentIndex: number) {
|
|
|
|
|
return `attachmentId_mail_${mailIndex}_attachment_${attachmentIndex}`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function setUpMail(mailIndex: number, attachmentCount: number): Mail {
|
2025-05-02 17:38:27 +02:00
|
|
|
const mail = createTestEntity(MailTypeRef, {
|
|
|
|
|
bucketKey: createTestEntity(BucketKeyTypeRef, {
|
2025-05-22 14:36:58 +02:00
|
|
|
_id: `hey I'm an ID for bucket key #${mailIndex}`,
|
2025-05-02 17:38:27 +02:00
|
|
|
}),
|
|
|
|
|
})
|
|
|
|
|
const instanceSessionKeys: InstanceSessionKey[] = []
|
2025-05-22 14:36:58 +02:00
|
|
|
for (const attachmentIndex of lazyNumberRange(0, attachmentCount)) {
|
|
|
|
|
const attachmentId = sessionKeyId(mailIndex, attachmentIndex)
|
2025-05-02 17:38:27 +02:00
|
|
|
const instanceSessionKey = createTestEntity(InstanceSessionKeyTypeRef, {
|
2025-05-22 14:36:58 +02:00
|
|
|
instanceId: attachmentId,
|
|
|
|
|
symEncSessionKey: new Uint8Array([mailIndex, attachmentIndex, 3, 4]),
|
|
|
|
|
symKeyVersion: `${mailIndex}`,
|
2025-05-02 17:38:27 +02:00
|
|
|
})
|
|
|
|
|
instanceSessionKeys.push(instanceSessionKey)
|
2025-05-22 14:36:58 +02:00
|
|
|
|
|
|
|
|
mail.attachments.push(["someListId", attachmentId])
|
2025-05-02 17:38:27 +02:00
|
|
|
}
|
|
|
|
|
when(cryptoFacade.resolveWithBucketKey(mail)).thenResolve({
|
|
|
|
|
resolvedSessionKeyForInstance: [],
|
|
|
|
|
instanceSessionKeys,
|
|
|
|
|
})
|
|
|
|
|
return mail
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-22 14:36:58 +02:00
|
|
|
async function checkMail(resolver: OwnerEncSessionKeyProvider, fileCount: number, mails: readonly Mail[]) {
|
|
|
|
|
for (const [mailIndex, mail] of mails.entries()) {
|
|
|
|
|
for (const [attachmentIndex, attachmentId] of mail.attachments.entries()) {
|
|
|
|
|
const attachment = createTestEntity(FileTypeRef, {
|
|
|
|
|
_id: attachmentId,
|
|
|
|
|
name: `file_${attachmentIndex}`,
|
|
|
|
|
})
|
|
|
|
|
o.check(await resolver(elementIdPart(attachmentId), attachment)).deepEquals({
|
|
|
|
|
key: new Uint8Array([mailIndex, attachmentIndex, 3, 4]),
|
|
|
|
|
encryptingKeyVersion: mailIndex as KeyVersion,
|
|
|
|
|
})(`hellooooo I'm an ID for some file instance #${attachmentId} for mail #${mailIndex}`)
|
|
|
|
|
}
|
2025-05-02 17:38:27 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
o.test("one mail with no bucket key", async () => {
|
|
|
|
|
const mail = createTestEntity(MailTypeRef)
|
|
|
|
|
await facade.createOwnerEncSessionKeyProviderForAttachments([mail])
|
|
|
|
|
// since our resolver will do nothing, we just need to ensure that cryptoFacade was never called in the first place
|
|
|
|
|
verify(cryptoFacade.resolveWithBucketKey(matchers.anything()), { times: 0 })
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
o.test("one mail with one file instance", async () => {
|
2025-05-22 14:36:58 +02:00
|
|
|
const mails = [setUpMail(0, 1)]
|
|
|
|
|
const resolver = await facade.createOwnerEncSessionKeyProviderForAttachments(mails)
|
|
|
|
|
await checkMail(resolver, 1, mails)
|
2025-05-02 17:38:27 +02:00
|
|
|
})
|
|
|
|
|
o.test("a lot of mails with one file instance", async () => {
|
|
|
|
|
const count = 100
|
|
|
|
|
const instanceCount = 1
|
|
|
|
|
const mails: Mail[] = []
|
|
|
|
|
for (let i = 0; i < count; i++) {
|
|
|
|
|
mails.push(setUpMail(i, instanceCount))
|
|
|
|
|
}
|
|
|
|
|
const resolver = await facade.createOwnerEncSessionKeyProviderForAttachments(mails)
|
2025-05-22 14:36:58 +02:00
|
|
|
await checkMail(resolver, instanceCount, mails)
|
2025-05-02 17:38:27 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
o.test("one mail with many file instances", async () => {
|
|
|
|
|
const instanceCount = 256
|
2025-05-22 14:36:58 +02:00
|
|
|
const mails = [setUpMail(0, instanceCount)]
|
|
|
|
|
const resolver = await facade.createOwnerEncSessionKeyProviderForAttachments(mails)
|
|
|
|
|
await checkMail(resolver, instanceCount, mails)
|
2025-05-02 17:38:27 +02:00
|
|
|
})
|
|
|
|
|
o.test("a lot of mails with many file instances", async () => {
|
|
|
|
|
const count = 100
|
|
|
|
|
const instanceCount = 64
|
|
|
|
|
const mails: Mail[] = []
|
|
|
|
|
for (let i = 0; i < count; i++) {
|
|
|
|
|
mails.push(setUpMail(i, instanceCount))
|
|
|
|
|
}
|
|
|
|
|
const resolver = await facade.createOwnerEncSessionKeyProviderForAttachments(mails)
|
2025-05-22 14:36:58 +02:00
|
|
|
await checkMail(resolver, instanceCount, mails)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
o.test("when already decrypted it just returns the key", async () => {
|
|
|
|
|
const mail = setUpMail(0, 1)
|
|
|
|
|
mail.bucketKey = null
|
|
|
|
|
|
|
|
|
|
const resolver = await facade.createOwnerEncSessionKeyProviderForAttachments([mail])
|
|
|
|
|
const expectedSK: VersionedEncryptedKey = {
|
|
|
|
|
key: new Uint8Array([1, 2, 3, 4]),
|
|
|
|
|
encryptingKeyVersion: 10,
|
2025-05-02 17:38:27 +02:00
|
|
|
}
|
2025-05-22 14:36:58 +02:00
|
|
|
const attachment = createTestEntity(FileTypeRef, {
|
|
|
|
|
_id: mail.attachments[0],
|
|
|
|
|
_ownerEncSessionKey: expectedSK.key,
|
|
|
|
|
_ownerKeyVersion: String(expectedSK.encryptingKeyVersion),
|
|
|
|
|
name: `file_${0}`,
|
|
|
|
|
})
|
|
|
|
|
o.check(await resolver(getElementId(attachment), attachment)).deepEquals(expectedSK)
|
2025-05-02 17:38:27 +02:00
|
|
|
})
|
|
|
|
|
})
|
2022-12-27 15:37:40 +01:00
|
|
|
})
|