2023-06-29 18:26:45 +02:00
import o from "@tutao/otest"
2025-11-13 17:35:16 +01:00
import { arrayEquals , assertNotNull , hexToUint8Array , KeyVersion , neverNull , noOp , utf8Uint8ArrayToString , Versioned } from "@tutao/tutanota-utils"
2024-07-01 17:56:41 +02:00
import { CryptoFacade } from "../../../../../src/common/api/worker/crypto/CryptoFacade.js"
2024-04-17 10:34:33 +02:00
import {
2024-09-05 13:11:59 +02:00
asCryptoProtoocolVersion ,
2024-04-17 10:34:33 +02:00
BucketPermissionType ,
CryptoProtocolVersion ,
EncryptionAuthStatus ,
2025-05-23 16:45:41 +02:00
EncryptionKeyVerificationState ,
2025-06-05 17:07:31 +02:00
GroupType ,
2024-04-17 10:34:33 +02:00
PermissionType ,
2025-07-09 17:17:35 +02:00
PresentableKeyVerificationState ,
2025-10-14 12:11:22 +02:00
ProcessingState ,
2024-09-02 19:57:57 +02:00
PublicKeyIdentifierType ,
2024-07-01 17:56:41 +02:00
} from "../../../../../src/common/api/common/TutanotaConstants.js"
2022-04-19 16:51:08 +02:00
import {
2025-03-10 16:19:11 +01:00
createMail ,
createMailAddress ,
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
FileTypeRef ,
2023-12-18 11:36:38 +01:00
InternalRecipientKeyData ,
2023-01-17 15:42:18 +01:00
Mail ,
2025-03-10 16:19:11 +01:00
MailAddressTypeRef ,
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
MailDetailsBlobTypeRef ,
2023-01-12 16:48:28 +01:00
MailTypeRef ,
2024-07-01 17:56:41 +02:00
} from "../../../../../src/common/api/entities/tutanota/TypeRefs.js"
2022-04-19 16:51:08 +02:00
import {
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
BucketKey ,
BucketKeyTypeRef ,
2022-04-19 16:51:08 +02:00
BucketPermissionTypeRef ,
2023-11-10 16:59:39 +01:00
BucketTypeRef ,
2023-12-18 11:36:38 +01:00
createBucket ,
createBucketKey ,
createBucketPermission ,
createGroup ,
createInstanceSessionKey ,
createKeyPair ,
createPermission ,
createTypeInfo ,
2024-04-17 10:34:33 +02:00
CustomerAccountTerminationRequestTypeRef ,
2023-12-18 11:36:38 +01:00
Group ,
2025-04-10 13:44:34 +02:00
GroupKeysRefTypeRef ,
2023-11-10 16:59:39 +01:00
GroupMembershipTypeRef ,
2022-04-19 16:51:08 +02:00
GroupTypeRef ,
2023-12-18 11:36:38 +01:00
InstanceSessionKey ,
2023-11-10 16:59:39 +01:00
InstanceSessionKeyTypeRef ,
2025-02-10 13:15:28 +01:00
KeyPair ,
2023-11-10 16:59:39 +01:00
KeyPairTypeRef ,
2022-04-19 16:51:08 +02:00
PermissionTypeRef ,
2023-11-10 16:59:39 +01:00
TypeInfoTypeRef ,
2022-04-19 16:51:08 +02:00
UpdatePermissionKeyData ,
2023-12-18 11:36:38 +01:00
User ,
2023-11-10 16:59:39 +01:00
UserTypeRef ,
2024-07-01 17:56:41 +02:00
} from "../../../../../src/common/api/entities/sys/TypeRefs.js"
2024-04-17 10:34:33 +02:00
import { spy } from "@tutao/tutanota-test-utils"
2024-07-01 17:56:41 +02:00
import { RestClient } from "../../../../../src/common/api/worker/rest/RestClient.js"
import { EntityClient } from "../../../../../src/common/api/common/EntityClient.js"
2022-01-07 15:58:30 +01:00
import {
2023-12-18 11:36:38 +01:00
Aes256Key ,
aes256RandomKey ,
2023-09-26 18:03:30 +02:00
aesDecrypt ,
2023-09-13 11:42:57 +02:00
aesEncrypt ,
2024-04-17 10:34:33 +02:00
AesKey ,
2022-01-07 15:58:30 +01:00
bitArrayToUint8Array ,
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
decryptKey ,
2022-01-07 15:58:30 +01:00
encryptKey ,
encryptRsaKey ,
2025-04-02 13:46:11 +02:00
generateX25519KeyPair ,
2025-01-28 18:46:02 +01:00
KeyPairType ,
2023-12-18 11:36:38 +01:00
kyberPrivateKeyToBytes ,
kyberPublicKeyToBytes ,
2024-01-30 18:18:19 +01:00
pqKeyPairsToPublicKeys ,
2025-02-10 13:15:28 +01:00
PQPublicKeys ,
RsaPublicKey ,
2023-12-18 11:36:38 +01:00
rsaPublicKeyToHex ,
2025-04-02 13:46:11 +02:00
X25519KeyPair ,
X25519PublicKey ,
2022-01-07 15:58:30 +01:00
} from "@tutao/tutanota-crypto"
2025-03-10 16:19:11 +01:00
import { ServerModelUntypedInstance , TypeModel , UntypedInstance } from "../../../../../src/common/api/common/EntityTypes.js"
2024-07-01 17:56:41 +02:00
import { IServiceExecutor } from "../../../../../src/common/api/common/ServiceRequest.js"
2024-09-05 13:11:59 +02:00
import { matchers , object , verify , when } from "testdouble"
2025-01-22 15:19:22 +01:00
import { UpdatePermissionKeyService } from "../../../../../src/common/api/entities/sys/Services.js"
2025-03-10 16:19:11 +01:00
import { elementIdPart , getListId , isSameId , listIdPart } from "../../../../../src/common/api/common/utils/EntityUtils.js"
2025-05-19 16:11:26 +02:00
import { HttpMethod , TypeModelResolver } from "../../../../../src/common/api/common/EntityFunctions.js"
2024-07-01 17:56:41 +02:00
import { UserFacade } from "../../../../../src/common/api/worker/facades/UserFacade.js"
import { SessionKeyNotFoundError } from "../../../../../src/common/api/common/error/SessionKeyNotFoundError.js"
import { OwnerEncSessionKeysUpdateQueue } from "../../../../../src/common/api/worker/crypto/OwnerEncSessionKeysUpdateQueue.js"
import { WASMKyberFacade } from "../../../../../src/common/api/worker/facades/KyberFacade.js"
import { PQFacade } from "../../../../../src/common/api/worker/facades/PQFacade.js"
2024-09-05 13:11:59 +02:00
import { encodePQMessage , PQBucketKeyEncapsulation } from "../../../../../src/common/api/worker/facades/PQMessage.js"
2025-05-19 16:11:26 +02:00
import { clientInitializedTypeModelResolver , createTestEntity , instancePipelineFromTypeModelResolver } from "../../../TestUtils.js"
2023-12-18 17:30:21 +01:00
import { RSA_TEST_KEYPAIR } from "../facades/RsaPqPerformanceTest.js"
2024-07-01 17:56:41 +02:00
import { DefaultEntityRestCache } from "../../../../../src/common/api/worker/rest/DefaultEntityRestCache.js"
2024-04-23 11:06:40 +02:00
import { loadLibOQSWASM } from "../WASMTestUtils.js"
2025-01-20 13:40:57 +01:00
import { AsymmetricCryptoFacade } from "../../../../../src/common/api/worker/crypto/AsymmetricCryptoFacade.js"
2025-06-05 17:07:31 +02:00
import { VerifiedPublicEncryptionKey } from "../../../../../src/common/api/worker/facades/lazy/KeyVerificationFacade"
2025-02-10 13:15:28 +01:00
import { KeyLoaderFacade , parseKeyVersion } from "../../../../../src/common/api/worker/facades/KeyLoaderFacade.js"
2025-06-05 17:07:31 +02:00
import { PublicEncryptionKeyProvider } from "../../../../../src/common/api/worker/facades/PublicEncryptionKeyProvider.js"
2025-01-28 18:46:02 +01:00
import { KeyRotationFacade } from "../../../../../src/common/api/worker/facades/KeyRotationFacade.js"
2025-03-25 15:35:51 +01:00
import { NotFoundError } from "../../../../../src/common/api/common/error/RestError"
2025-03-10 16:19:11 +01:00
import { AttributeModel } from "../../../../../src/common/api/common/AttributeModel"
import { EntityAdapter } from "../../../../../src/common/api/worker/crypto/EntityAdapter"
2025-05-23 16:45:41 +02:00
import { KeyVerificationMismatchError } from "../../../../../src/common/api/common/error/KeyVerificationMismatchError"
2023-01-12 16:48:28 +01:00
2023-12-18 11:36:38 +01:00
const { captor , anything , argThat } = matchers
2017-08-15 13:54:22 +02:00
2023-12-18 11:36:38 +01:00
const kyberFacade = new WASMKyberFacade ( await loadLibOQSWASM ( ) )
const pqFacade : PQFacade = new PQFacade ( kyberFacade )
2025-06-05 17:07:31 +02:00
let publicEncryptionKeyProvider : PublicEncryptionKeyProvider
2023-12-18 11:36:38 +01:00
/ * *
* Helper to have all the mocked items available in the test case .
* /
type TestUser = {
user : User
name : string
userGroup : Group
mailGroup : Group
2024-04-17 10:34:33 +02:00
userGroupKey : AesKey
mailGroupKey : AesKey
}
2024-09-16 11:21:45 +02:00
const senderAddress = "hello@tutao.de"
2023-12-18 11:36:38 +01:00
o . spec ( "CryptoFacadeTest" , function ( ) {
2023-09-26 18:03:30 +02:00
let restClient : RestClient
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
2025-05-16 16:03:24 +02:00
let instancePipeline
2025-03-10 16:19:11 +01:00
2022-03-09 17:43:29 +01:00
let serviceExecutor : IServiceExecutor
let entityClient : EntityClient
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
let ownerEncSessionKeysUpdateQueue : OwnerEncSessionKeysUpdateQueue
2022-03-09 17:43:29 +01:00
let crypto : CryptoFacade
2022-04-12 14:23:38 +02:00
let userFacade : UserFacade
2024-04-17 10:34:33 +02:00
let keyLoaderFacade : KeyLoaderFacade
2024-01-31 18:55:21 +01:00
let cache : DefaultEntityRestCache
2025-02-10 13:15:28 +01:00
let asymmetricCryptoFacade : AsymmetricCryptoFacade
2025-01-28 18:46:02 +01:00
let keyRotationFacade : KeyRotationFacade
2025-05-16 16:03:24 +02:00
let typeModelResolver : TypeModelResolver
async function prepareBucketKeyInstance (
bucketEncMailSessionKey : Uint8Array ,
fileSessionKeys : Array < AesKey > ,
bk : AesKey ,
pubEncBucketKey : Uint8Array ,
recipientUser : TestUser ,
mail : Mail ,
senderPubEccKey : Versioned < X25519PublicKey > | undefined ,
recipientKeyVersion : NumberString ,
protocolVersion : CryptoProtocolVersion ,
asymmetricCryptoFacade : AsymmetricCryptoFacade ,
) {
const MailTypeModel = await typeModelResolver . resolveClientTypeReference ( MailTypeRef )
const mailInstanceSessionKey = createTestEntity ( InstanceSessionKeyTypeRef , {
typeInfo : createTestEntity ( TypeInfoTypeRef , {
application : MailTypeModel.app ,
typeId : String ( MailTypeModel . id ) ,
} ) ,
symEncSessionKey : bucketEncMailSessionKey ,
instanceList : "mailListId" ,
instanceId : "mailId" ,
} )
const FileTypeModel = await typeModelResolver . resolveClientTypeReference ( FileTypeRef )
const bucketEncSessionKeys = fileSessionKeys . map ( ( fileSessionKey , index ) = > {
return createTestEntity ( InstanceSessionKeyTypeRef , {
typeInfo : createTestEntity ( TypeInfoTypeRef , {
application : FileTypeModel.app ,
typeId : String ( FileTypeModel . id ) ,
} ) ,
symEncSessionKey : encryptKey ( bk , fileSessionKey ) ,
instanceList : "fileListId" ,
instanceId : "fileId" + ( index + 1 ) ,
} )
} )
bucketEncSessionKeys . push ( mailInstanceSessionKey )
const bucketKey = createTestEntity ( BucketKeyTypeRef , {
pubEncBucketKey ,
keyGroup : recipientUser.userGroup._id ,
bucketEncSessionKeys : bucketEncSessionKeys ,
recipientKeyVersion ,
senderKeyVersion : senderPubEccKey != null ? senderPubEccKey . version . toString ( ) : "0" ,
protocolVersion ,
} )
when (
asymmetricCryptoFacade . loadKeyPairAndDecryptSymKey (
assertNotNull ( bucketKey . keyGroup ) ,
parseKeyVersion ( bucketKey . recipientKeyVersion ) ,
asCryptoProtoocolVersion ( bucketKey . protocolVersion ) ,
pubEncBucketKey ,
anything ( ) ,
) ,
) . thenResolve ( { decryptedAesKey : bk , senderIdentityPubKey : senderPubEccKey?.object ? ? null } )
mail . bucketKey = bucketKey
}
2017-11-23 13:30:17 +01:00
o . before ( function ( ) {
2023-09-26 18:03:30 +02:00
restClient = object ( )
2023-12-18 11:36:38 +01:00
when ( restClient . request ( anything ( ) , anything ( ) , anything ( ) ) ) . thenResolve ( undefined )
2022-04-12 14:23:38 +02:00
userFacade = object ( )
2024-01-31 18:55:21 +01:00
cache = object ( )
2017-11-23 13:30:17 +01:00
} )
2022-03-09 17:43:29 +01:00
o . beforeEach ( function ( ) {
serviceExecutor = object ( )
entityClient = object ( )
2024-09-05 13:11:59 +02:00
asymmetricCryptoFacade = object ( )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
ownerEncSessionKeysUpdateQueue = object ( )
2025-06-05 17:07:31 +02:00
publicEncryptionKeyProvider = object ( )
2025-01-28 18:46:02 +01:00
keyLoaderFacade = object ( )
keyRotationFacade = object ( )
2025-05-16 16:03:24 +02:00
typeModelResolver = clientInitializedTypeModelResolver ( )
instancePipeline = instancePipelineFromTypeModelResolver ( typeModelResolver )
2024-04-17 10:34:33 +02:00
crypto = new CryptoFacade (
userFacade ,
entityClient ,
restClient ,
serviceExecutor ,
2025-03-10 16:19:11 +01:00
instancePipeline ,
2024-04-17 10:34:33 +02:00
ownerEncSessionKeysUpdateQueue ,
cache ,
keyLoaderFacade ,
2024-09-05 13:11:59 +02:00
asymmetricCryptoFacade ,
2025-06-05 17:07:31 +02:00
publicEncryptionKeyProvider ,
2025-01-28 18:46:02 +01:00
( ) = > keyRotationFacade ,
2025-05-16 16:03:24 +02:00
typeModelResolver ,
2025-11-13 17:35:16 +01:00
async ( ) = > {
noOp ( )
} ,
2024-04-17 10:34:33 +02:00
)
2022-03-09 17:43:29 +01:00
} )
2024-04-17 10:34:33 +02:00
o ( "resolve session key: unencrypted instance" , async function ( ) {
2025-03-10 16:19:11 +01:00
const customerAccountTerminationRequest = createTestEntity ( CustomerAccountTerminationRequestTypeRef )
o ( await crypto . resolveSessionKey ( customerAccountTerminationRequest ) ) . equals ( null )
2017-08-15 13:54:22 +02:00
} )
2024-04-17 10:34:33 +02:00
o ( "resolve session key: _ownerEncSessionKey instance." , async function ( ) {
const recipientUser = createTestUser ( "Bob" , entityClient )
configureLoggedInUser ( recipientUser , userFacade , keyLoaderFacade )
2023-12-05 14:03:33 +01:00
const sk = aes256RandomKey ( )
2025-03-10 16:19:11 +01:00
const mail = createTestEntity ( MailTypeRef , {
_ownerEncSessionKey : recipientUser.mailGroupKey ? encryptKey ( recipientUser . mailGroupKey , sk ) : null ,
_ownerGroup : recipientUser.mailGroup._id ,
_ownerKeyVersion : recipientUser.mailGroup.groupKeyVersion ,
} )
const sessionKey : AesKey = neverNull ( await crypto . resolveSessionKey ( mail ) )
2024-04-17 10:34:33 +02:00
o ( sessionKey ) . deepEquals ( sk )
2017-08-15 13:54:22 +02:00
} )
2024-04-17 10:34:33 +02:00
o ( "resolve session key: _ownerEncSessionKey instance, fetches correct version." , async function ( ) {
const recipientUser = createTestUser ( "Bob" , entityClient )
configureLoggedInUser ( recipientUser , userFacade , keyLoaderFacade )
2023-12-18 11:36:38 +01:00
2025-03-10 16:19:11 +01:00
const sk = aes256RandomKey ( )
2024-04-17 10:34:33 +02:00
const groupKey_v1 = aes256RandomKey ( )
when ( keyLoaderFacade . loadSymGroupKey ( recipientUser . mailGroup . _id , 1 ) ) . thenResolve ( groupKey_v1 )
2022-03-09 17:43:29 +01:00
2025-03-10 16:19:11 +01:00
const mail = createTestEntity ( MailTypeRef , {
_ownerGroup : recipientUser.mailGroup._id ,
_ownerEncSessionKey : encryptKey ( groupKey_v1 , sk ) ,
_ownerKeyVersion : "1" ,
} )
const sessionKey : AesKey = neverNull ( await crypto . resolveSessionKey ( mail ) )
2022-01-07 15:58:30 +01:00
o ( sessionKey ) . deepEquals ( sk )
2017-08-15 13:54:22 +02:00
} )
2024-09-05 13:11:59 +02:00
const protocolVersion = CryptoProtocolVersion . TUTA_CRYPT
2024-04-17 10:34:33 +02:00
o ( "resolve session key: rsa public key decryption of session key." , async function ( ) {
2021-01-25 12:50:28 +01:00
o . timeout ( 500 ) // in CI or with debugging it can take a while
2024-04-17 10:34:33 +02:00
const recipientUser = createTestUser ( "Bob" , entityClient )
configureLoggedInUser ( recipientUser , userFacade , keyLoaderFacade )
2021-01-25 12:50:28 +01:00
2017-08-15 13:54:22 +02:00
let confidential = true
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
let bk = aes256RandomKey ( )
2023-12-18 17:30:21 +01:00
let privateKey = RSA_TEST_KEYPAIR . privateKey
let publicKey = RSA_TEST_KEYPAIR . publicKey
2023-11-10 16:59:39 +01:00
const keyPair = createTestEntity ( KeyPairTypeRef , {
2022-03-09 17:43:29 +01:00
_id : "keyPairId" ,
2023-12-18 11:36:38 +01:00
symEncPrivRsaKey : encryptRsaKey ( recipientUser . userGroupKey , privateKey ) ,
2023-12-18 17:30:21 +01:00
pubRsaKey : hexToUint8Array ( rsaPublicKeyToHex ( RSA_TEST_KEYPAIR . publicKey ) ) ,
2022-03-09 17:43:29 +01:00
} )
2024-04-17 10:34:33 +02:00
recipientUser . userGroup . currentKeys = keyPair
2023-12-18 11:36:38 +01:00
2025-03-10 16:19:11 +01:00
const mail = createTestEntity ( MailTypeRef , {
confidential ,
_ownerGroup : recipientUser.mailGroup._id ,
_permissions : "permissionListId" ,
} )
2023-12-18 11:36:38 +01:00
2023-11-10 16:59:39 +01:00
const bucket = createTestEntity ( BucketTypeRef , {
2022-12-27 15:37:40 +01:00
bucketPermissions : "bucketPermissionListId" ,
2022-03-09 17:43:29 +01:00
} )
2023-11-10 16:59:39 +01:00
const permission = createTestEntity ( PermissionTypeRef , {
2022-03-09 17:43:29 +01:00
_id : [ "permissionListId" , "permissionId" ] ,
2023-12-18 11:36:38 +01:00
_ownerGroup : recipientUser.userGroup._id ,
2022-03-09 17:43:29 +01:00
bucketEncSessionKey : encryptKey ( bk , sk ) ,
bucket ,
type : PermissionType . Public ,
} )
2024-09-05 13:11:59 +02:00
const pubEncBucketKey = object < Uint8Array > ( )
2023-11-10 16:59:39 +01:00
const bucketPermission = createTestEntity ( BucketPermissionTypeRef , {
2022-03-09 17:43:29 +01:00
_id : [ "bucketPermissionListId" , "bucketPermissionId" ] ,
2023-12-18 11:36:38 +01:00
_ownerGroup : recipientUser.userGroup._id ,
2022-03-09 17:43:29 +01:00
type : BucketPermissionType . Public ,
2023-12-18 11:36:38 +01:00
group : recipientUser.userGroup._id ,
2022-03-09 17:43:29 +01:00
pubEncBucketKey ,
2024-09-05 13:11:59 +02:00
protocolVersion : protocolVersion ,
2024-04-17 10:34:33 +02:00
pubKeyVersion : "0" ,
2022-03-09 17:43:29 +01:00
} )
2022-04-12 14:23:38 +02:00
2024-09-05 13:11:59 +02:00
when (
asymmetricCryptoFacade . loadKeyPairAndDecryptSymKey (
assertNotNull ( bucketPermission . group ) ,
2025-01-20 13:40:57 +01:00
parseKeyVersion ( bucketPermission . pubKeyVersion ! ) ,
2024-09-05 13:11:59 +02:00
protocolVersion ,
pubEncBucketKey ,
2025-03-28 16:56:47 +01:00
anything ( ) ,
2024-09-05 13:11:59 +02:00
) ,
) . thenResolve ( { decryptedAesKey : bk , senderIdentityPubKey : null } )
2022-03-09 17:43:29 +01:00
when ( entityClient . loadAll ( BucketPermissionTypeRef , getListId ( bucketPermission ) ) ) . thenResolve ( [ bucketPermission ] )
when ( entityClient . loadAll ( PermissionTypeRef , getListId ( permission ) ) ) . thenResolve ( [ permission ] )
2022-12-27 15:37:40 +01:00
when (
serviceExecutor . post (
UpdatePermissionKeyService ,
2023-12-18 11:36:38 +01:00
argThat ( ( p : UpdatePermissionKeyData ) = > {
2022-12-27 15:37:40 +01:00
return isSameId ( p . permission , permission . _id ) && isSameId ( p . bucketPermission , bucketPermission . _id )
} ) ,
) ,
) . thenResolve ( undefined )
2022-03-09 17:43:29 +01:00
2025-03-10 16:19:11 +01:00
const sessionKey = neverNull ( await crypto . resolveSessionKey ( mail ) )
2022-03-09 17:43:29 +01:00
o ( sessionKey ) . deepEquals ( sk )
2017-08-15 13:54:22 +02:00
} )
2024-04-17 10:34:33 +02:00
o ( "resolve session key: pq public key decryption of session key." , async function ( ) {
2023-12-18 11:36:38 +01:00
o . timeout ( 500 ) // in CI or with debugging it can take a while
2024-04-17 10:34:33 +02:00
const recipientTestUser = createTestUser ( "Bob" , entityClient )
configureLoggedInUser ( recipientTestUser , userFacade , keyLoaderFacade )
2023-12-18 11:36:38 +01:00
let pqKeyPairs = await pqFacade . generateKeyPairs ( )
2025-04-02 13:46:11 +02:00
const senderIdentityKeyPair = generateX25519KeyPair ( )
2023-12-18 11:36:38 +01:00
// configure test mail
let sk = aes256RandomKey ( )
let bk = aes256RandomKey ( )
2025-03-10 16:19:11 +01:00
const mail = createTestEntity ( MailTypeRef , {
_permissions : "permissionListId" ,
_ownerGroup : recipientTestUser.mailGroup._id ,
confidential : true ,
} )
2023-12-18 11:36:38 +01:00
const bucket = createBucket ( {
bucketPermissions : "bucketPermissionListId" ,
} )
const permission = createPermission ( {
_format : "" ,
listElementApplication : null ,
listElementTypeId : null ,
ops : null ,
symEncSessionKey : null ,
2024-04-17 10:34:33 +02:00
symKeyVersion : null ,
2023-12-18 11:36:38 +01:00
_id : [ "permissionListId" , "permissionId" ] ,
_ownerGroup : recipientTestUser.mailGroup._id ,
bucketEncSessionKey : encryptKey ( bk , sk ) ,
bucket ,
type : PermissionType . Public ,
_ownerEncSessionKey : null ,
2024-04-17 10:34:33 +02:00
_ownerKeyVersion : null ,
2023-12-18 11:36:38 +01:00
_permissions : "p_id" ,
group : null ,
} )
2024-09-05 13:11:59 +02:00
const pubEncBucketKey = await pqFacade . encapsulateAndEncode (
senderIdentityKeyPair ,
2025-04-02 13:46:11 +02:00
generateX25519KeyPair ( ) ,
2024-09-05 13:11:59 +02:00
pqKeyPairsToPublicKeys ( pqKeyPairs ) ,
bitArrayToUint8Array ( bk ) ,
)
const protocolVersion = CryptoProtocolVersion . RSA
2023-12-18 11:36:38 +01:00
const bucketPermission = createBucketPermission ( {
_id : [ "bucketPermissionListId" , "bucketPermissionId" ] ,
2024-04-17 10:34:33 +02:00
_format : "" ,
_permissions : "" ,
2023-12-18 11:36:38 +01:00
_ownerGroup : recipientTestUser.mailGroup._id ,
type : BucketPermissionType . Public ,
group : recipientTestUser.userGroup._id ,
pubEncBucketKey ,
2024-04-17 10:34:33 +02:00
senderKeyVersion : "0" ,
ownerEncBucketKey : null ,
ownerKeyVersion : null ,
2024-09-05 13:11:59 +02:00
protocolVersion ,
2024-04-17 10:34:33 +02:00
pubKeyVersion : "0" ,
symEncBucketKey : null ,
symKeyVersion : null ,
} )
2024-09-05 13:11:59 +02:00
when (
asymmetricCryptoFacade . loadKeyPairAndDecryptSymKey (
assertNotNull ( bucketPermission . group ) ,
2025-01-20 13:40:57 +01:00
parseKeyVersion ( bucketPermission . pubKeyVersion ! ) ,
2024-09-05 13:11:59 +02:00
protocolVersion ,
pubEncBucketKey ,
2025-03-28 16:56:47 +01:00
anything ( ) ,
2024-09-05 13:11:59 +02:00
) ,
) . thenResolve ( { decryptedAesKey : bk , senderIdentityPubKey : senderIdentityKeyPair.publicKey } )
2024-04-17 10:34:33 +02:00
when ( userFacade . createAuthHeaders ( ) ) . thenReturn ( { } )
2025-06-03 12:08:18 +02:00
when ( restClient . request ( anything ( ) , HttpMethod . PATCH , anything ( ) ) ) . thenResolve ( undefined )
2024-04-17 10:34:33 +02:00
when ( entityClient . loadAll ( BucketPermissionTypeRef , getListId ( bucketPermission ) ) ) . thenResolve ( [ bucketPermission ] )
when ( entityClient . loadAll ( PermissionTypeRef , getListId ( permission ) ) ) . thenResolve ( [ permission ] )
2025-03-10 16:19:11 +01:00
const sessionKey = neverNull ( await crypto . resolveSessionKey ( mail ) )
2024-04-17 10:34:33 +02:00
o ( sessionKey ) . deepEquals ( sk )
} )
o ( "resolve session key: pq public key decryption of session key, fetches correct recipient key version" , async function ( ) {
o . timeout ( 500 ) // in CI or with debugging it can take a while
const recipientTestUser = createTestUser ( "Bob" , entityClient )
configureLoggedInUser ( recipientTestUser , userFacade , keyLoaderFacade )
const pqKeyPairs_v1 = await pqFacade . generateKeyPairs ( )
2025-04-02 13:46:11 +02:00
const senderIdentityKeyPair = generateX25519KeyPair ( )
2024-04-17 10:34:33 +02:00
// configure test mail
const sk = aes256RandomKey ( )
const bk = aes256RandomKey ( )
2025-03-10 16:19:11 +01:00
const mail = createTestEntity ( MailTypeRef , {
_ownerGroup : recipientTestUser.mailGroup._id ,
confidential : true ,
_permissions : "permissionListId" ,
} )
2024-04-17 10:34:33 +02:00
const bucket = createBucket ( {
bucketPermissions : "bucketPermissionListId" ,
} )
const permission = createPermission ( {
_format : "" ,
listElementApplication : null ,
listElementTypeId : null ,
ops : null ,
symEncSessionKey : null ,
symKeyVersion : null ,
_id : [ "permissionListId" , "permissionId" ] ,
_ownerGroup : recipientTestUser.mailGroup._id ,
bucketEncSessionKey : encryptKey ( bk , sk ) ,
bucket ,
type : PermissionType . Public ,
_ownerEncSessionKey : null ,
_ownerKeyVersion : null ,
_permissions : "p_id" ,
group : null ,
} )
2024-09-05 13:11:59 +02:00
const pubEncBucketKey = await pqFacade . encapsulateAndEncode (
2024-04-17 10:34:33 +02:00
senderIdentityKeyPair ,
2025-04-02 13:46:11 +02:00
generateX25519KeyPair ( ) ,
2024-04-17 10:34:33 +02:00
pqKeyPairsToPublicKeys ( pqKeyPairs_v1 ) ,
bitArrayToUint8Array ( bk ) ,
)
2024-09-05 13:11:59 +02:00
const protocolVersion = CryptoProtocolVersion . RSA
2024-04-17 10:34:33 +02:00
const bucketPermission = createBucketPermission ( {
_id : [ "bucketPermissionListId" , "bucketPermissionId" ] ,
2023-12-18 11:36:38 +01:00
_format : "" ,
_permissions : "" ,
2024-04-17 10:34:33 +02:00
_ownerGroup : recipientTestUser.mailGroup._id ,
type : BucketPermissionType . Public ,
group : recipientTestUser.userGroup._id ,
pubEncBucketKey ,
senderKeyVersion : "0" ,
2023-12-18 11:36:38 +01:00
ownerEncBucketKey : null ,
2024-04-17 10:34:33 +02:00
ownerKeyVersion : null ,
2023-12-18 11:36:38 +01:00
protocolVersion : "0" ,
2024-04-17 10:34:33 +02:00
pubKeyVersion : "1" ,
2023-12-18 11:36:38 +01:00
symEncBucketKey : null ,
2024-04-17 10:34:33 +02:00
symKeyVersion : null ,
2023-12-18 11:36:38 +01:00
} )
2024-09-05 13:11:59 +02:00
when (
asymmetricCryptoFacade . loadKeyPairAndDecryptSymKey (
assertNotNull ( bucketPermission . group ) ,
2025-01-20 13:40:57 +01:00
parseKeyVersion ( bucketPermission . pubKeyVersion ! ) ,
2024-09-05 13:11:59 +02:00
protocolVersion ,
pubEncBucketKey ,
2025-03-28 16:56:47 +01:00
anything ( ) ,
2024-09-05 13:11:59 +02:00
) ,
) . thenResolve ( { decryptedAesKey : bk , senderIdentityPubKey : senderIdentityKeyPair.publicKey } )
2023-12-18 11:36:38 +01:00
when ( userFacade . createAuthHeaders ( ) ) . thenReturn ( { } )
2025-06-03 12:08:18 +02:00
when ( restClient . request ( anything ( ) , HttpMethod . PATCH , anything ( ) ) ) . thenResolve ( undefined )
2023-12-18 11:36:38 +01:00
when ( entityClient . loadAll ( BucketPermissionTypeRef , getListId ( bucketPermission ) ) ) . thenResolve ( [ bucketPermission ] )
when ( entityClient . loadAll ( PermissionTypeRef , getListId ( permission ) ) ) . thenResolve ( [ permission ] )
2024-04-17 10:34:33 +02:00
2025-03-10 16:19:11 +01:00
const sessionKey = neverNull ( await crypto . resolveSessionKey ( mail ) )
2024-04-17 10:34:33 +02:00
o ( sessionKey ) . deepEquals ( sk )
} )
o ( "resolve session key: pq public key decryption of session key using bucketKey" , async function ( ) {
o . timeout ( 500 ) // in CI or with debugging it can take a while
let confidential = true
const recipientTestUser = createTestUser ( "Bob" , entityClient )
configureLoggedInUser ( recipientTestUser , userFacade , keyLoaderFacade )
const pqKeyPairs_v1 = await pqFacade . generateKeyPairs ( )
2025-04-02 13:46:11 +02:00
const senderIdentityKeyPair = generateX25519KeyPair ( )
2024-04-17 10:34:33 +02:00
// configure test mail
const sk = aes256RandomKey ( )
const bk = aes256RandomKey ( )
2025-03-10 16:19:11 +01:00
let mail = createTestEntity ( MailTypeRef , {
_id : [ "mailListId" , "mailId" ] ,
_ownerGroup : recipientTestUser.mailGroup._id ,
confidential ,
mailDetails : [ "mailDetailsArchiveId" , "mailDetailsId" ] ,
sender : createTestEntity ( MailAddressTypeRef , {
address : senderAddress ,
name : "sender name" ,
} ) ,
} )
2024-04-17 10:34:33 +02:00
const bucketEncMailSessionKey = encryptKey ( bk , sk )
2024-09-05 13:11:59 +02:00
const pubEncBucketKey = await pqFacade . encapsulateAndEncode (
2024-04-17 10:34:33 +02:00
senderIdentityKeyPair ,
2025-04-02 13:46:11 +02:00
generateX25519KeyPair ( ) ,
2024-04-17 10:34:33 +02:00
pqKeyPairsToPublicKeys ( pqKeyPairs_v1 ) ,
bitArrayToUint8Array ( bk ) ,
)
2024-09-16 11:21:45 +02:00
const senderKeyVersion = 1
2024-09-05 13:11:59 +02:00
await prepareBucketKeyInstance (
bucketEncMailSessionKey ,
[ ] ,
bk ,
pubEncBucketKey ,
recipientTestUser ,
mail ,
{
object : senderIdentityKeyPair . publicKey ,
2024-09-16 11:21:45 +02:00
version : senderKeyVersion ,
2024-09-05 13:11:59 +02:00
} ,
"1" ,
protocolVersion ,
2025-02-10 13:15:28 +01:00
asymmetricCryptoFacade ,
2024-09-05 13:11:59 +02:00
)
2024-04-17 10:34:33 +02:00
2024-09-05 13:11:59 +02:00
when (
asymmetricCryptoFacade . decryptSymKeyWithKeyPair (
{
keyPairType : pqKeyPairs_v1.keyPairType ,
2025-04-02 13:46:11 +02:00
x25519KeyPair : pqKeyPairs_v1.x25519KeyPair ,
2024-09-05 13:11:59 +02:00
kyberKeyPair : pqKeyPairs_v1.kyberKeyPair ,
} ,
protocolVersion ,
pubEncBucketKey ,
) ,
) . thenResolve ( { decryptedAesKey : bk , senderIdentityPubKey : senderIdentityKeyPair.publicKey } )
2024-04-17 10:34:33 +02:00
when ( userFacade . createAuthHeaders ( ) ) . thenReturn ( { } )
2025-06-03 12:08:18 +02:00
when ( restClient . request ( anything ( ) , HttpMethod . PATCH , anything ( ) ) ) . thenResolve ( undefined )
2024-09-16 11:21:45 +02:00
when (
asymmetricCryptoFacade . authenticateSender (
{
identifier : senderAddress ,
identifierType : PublicKeyIdentifierType.MAIL_ADDRESS ,
} ,
senderIdentityKeyPair . publicKey ,
senderKeyVersion ,
) ,
2025-11-03 18:01:36 +01:00
) . thenResolve ( {
authStatus : EncryptionAuthStatus.TUTACRYPT_AUTHENTICATION_SUCCEEDED ,
verificationState : PresentableKeyVerificationState.SECURE ,
} )
2023-12-18 11:36:38 +01:00
2025-03-10 16:19:11 +01:00
const sessionKey = neverNull ( await crypto . resolveSessionKey ( mail ) )
2023-12-18 11:36:38 +01:00
o ( sessionKey ) . deepEquals ( sk )
} )
2024-01-31 18:55:21 +01:00
o ( "enforceSessionKeyUpdateIfNeeded: _ownerEncSessionKey already defined" , async function ( ) {
const files = [ createTestEntity ( FileTypeRef , { _ownerEncSessionKey : new Uint8Array ( ) } ) ]
2025-03-10 16:19:11 +01:00
const mail = createTestEntity ( MailTypeRef , { bucketKey : null } )
await crypto . enforceSessionKeyUpdateIfNeeded ( mail , files )
2024-01-31 18:55:21 +01:00
verify ( ownerEncSessionKeysUpdateQueue . postUpdateSessionKeysService ( anything ( ) ) , { times : 0 } )
verify ( cache . deleteFromCacheIfExists ( anything ( ) , anything ( ) , anything ( ) ) , { times : 0 } )
} )
o ( "enforceSessionKeyUpdateIfNeeded: _ownerEncSessionKey missing" , async function ( ) {
o . timeout ( 500 ) // in CI or with debugging it can take a while
const files = [
createTestEntity ( FileTypeRef , { _id : [ "listId" , "1" ] , _ownerEncSessionKey : new Uint8Array ( ) } ) ,
createTestEntity ( FileTypeRef , { _id : [ "listId" , "2" ] , _ownerEncSessionKey : null } ) ,
]
const testData = await preparePqPubEncBucketKeyResolveSessionKeyTest ( )
2025-03-10 16:19:11 +01:00
const bucketKey = assertNotNull ( testData . mail . bucketKey )
2024-01-31 18:55:21 +01:00
2025-07-09 17:17:35 +02:00
when (
asymmetricCryptoFacade . authenticateSender (
{
identifier : senderAddress ,
identifierType : PublicKeyIdentifierType.MAIL_ADDRESS ,
} ,
testData . senderIdentityKeyPair . publicKey ,
anything ( ) ,
) ,
2025-11-03 18:01:36 +01:00
) . thenResolve ( {
authStatus : EncryptionAuthStatus.TUTACRYPT_AUTHENTICATION_SUCCEEDED ,
verificationState : PresentableKeyVerificationState.SECURE ,
} )
2025-07-09 17:17:35 +02:00
2025-03-10 16:19:11 +01:00
await crypto . enforceSessionKeyUpdateIfNeeded ( testData . mail , files )
2024-01-31 18:55:21 +01:00
verify ( ownerEncSessionKeysUpdateQueue . postUpdateSessionKeysService ( anything ( ) ) , { times : 1 } )
verify ( cache . deleteFromCacheIfExists ( FileTypeRef , "listId" , "2" ) )
} )
2025-02-10 13:15:28 +01:00
o ( "encryptBucketKeyForInternalRecipient with existing PQKeys for sender and recipient" , async function ( ) {
2023-12-18 11:36:38 +01:00
let recipientMailAddress = "bob@tutanota.com"
let senderGroupKey = aes256RandomKey ( )
let bk = aes256RandomKey ( )
const recipientKeyPairs = await pqFacade . generateKeyPairs ( )
const recipientKeyPair = createKeyPair ( {
_id : "recipientKeyPairId" ,
2025-04-02 13:46:11 +02:00
pubEccKey : recipientKeyPairs.x25519KeyPair.publicKey ,
2023-12-18 11:36:38 +01:00
symEncPrivEccKey : null ,
pubKyberKey : kyberPublicKeyToBytes ( recipientKeyPairs . kyberKeyPair . publicKey ) ,
symEncPrivKyberKey : null ,
pubRsaKey : null ,
symEncPrivRsaKey : null ,
2025-06-17 14:14:52 +02:00
signature : null ,
2023-12-18 11:36:38 +01:00
} )
const senderKeyPairs = await pqFacade . generateKeyPairs ( )
const senderKeyPair = createKeyPair ( {
_id : "senderKeyPairId" ,
pubRsaKey : null ,
symEncPrivRsaKey : null ,
2025-04-02 13:46:11 +02:00
pubEccKey : senderKeyPairs.x25519KeyPair.publicKey ,
symEncPrivEccKey : aesEncrypt ( senderGroupKey , senderKeyPairs . x25519KeyPair . privateKey ) ,
2023-12-18 11:36:38 +01:00
pubKyberKey : kyberPublicKeyToBytes ( senderKeyPairs . kyberKeyPair . publicKey ) ,
symEncPrivKyberKey : aesEncrypt ( senderGroupKey , kyberPrivateKeyToBytes ( senderKeyPairs . kyberKeyPair . privateKey ) ) ,
2025-06-17 14:14:52 +02:00
signature : null ,
2023-12-18 11:36:38 +01:00
} )
const senderUserGroup = createGroup ( {
_format : "" ,
_ownerGroup : "" ,
_permissions : "" ,
admin : "admin1" ,
adminGroupEncGKey : null ,
2024-04-17 10:34:33 +02:00
adminGroupKeyVersion : null ,
2023-12-18 11:36:38 +01:00
archives : [ ] ,
customer : "customer1" ,
enabled : false ,
external : false ,
groupInfo : [ "" , "" ] ,
invitations : "" ,
members : "" ,
storageCounter : "counter1" ,
type : "" ,
user : "user1" ,
_id : "userGroupId" ,
2024-04-17 10:34:33 +02:00
currentKeys : senderKeyPair ,
groupKeyVersion : "0" ,
2025-04-10 13:44:34 +02:00
formerGroupKeys : createTestEntity ( GroupKeysRefTypeRef ) ,
2024-04-17 10:34:33 +02:00
pubAdminGroupEncGKey : null ,
2025-06-17 14:14:52 +02:00
identityKeyPair : null ,
2023-12-18 11:36:38 +01:00
} )
2024-04-17 10:34:33 +02:00
2023-12-18 11:36:38 +01:00
const notFoundRecipients = [ ]
2025-03-25 15:35:51 +01:00
const keyVerificationMismatchRecipients = [ ]
2023-12-18 11:36:38 +01:00
const pqEncapsulation : PQBucketKeyEncapsulation = {
kyberCipherText : new Uint8Array ( [ 1 ] ) ,
kekEncBucketKey : new Uint8Array ( [ 2 ] ) ,
}
2024-09-05 13:11:59 +02:00
const encodedPqMessage : Uint8Array = encodePQMessage ( {
2023-12-18 11:36:38 +01:00
senderIdentityPubKey : senderKeyPair.pubEccKey ! ,
ephemeralPubKey : senderKeyPair.pubEccKey ! ,
encapsulation : pqEncapsulation ,
2024-09-05 13:11:59 +02:00
} )
2023-12-18 11:36:38 +01:00
2025-02-10 13:15:28 +01:00
const recipientPublicKeys : Versioned < PQPublicKeys > = {
2025-01-20 13:40:57 +01:00
version : 0 ,
object : {
2025-02-10 13:15:28 +01:00
keyPairType : KeyPairType.TUTA_CRYPT ,
2025-04-02 13:46:11 +02:00
x25519PublicKey : recipientKeyPair.pubEccKey ! ,
2025-02-10 13:15:28 +01:00
kyberPublicKey : {
raw : recipientKeyPair.pubKyberKey ! ,
} ,
2025-01-20 13:40:57 +01:00
} ,
}
2025-06-05 17:07:31 +02:00
const loadedPublicKey : VerifiedPublicEncryptionKey = {
2025-05-23 16:45:41 +02:00
publicEncryptionKey : recipientPublicKeys ,
verificationState : EncryptionKeyVerificationState.NO_ENTRY ,
}
2025-06-05 17:07:31 +02:00
when ( publicEncryptionKeyProvider . loadCurrentPublicEncryptionKey ( anything ( ) ) ) . thenResolve ( loadedPublicKey )
2025-01-20 13:40:57 +01:00
when ( asymmetricCryptoFacade . asymEncryptSymKey ( bk , recipientPublicKeys , senderUserGroup . _id ) ) . thenResolve ( {
recipientKeyVersion : recipientPublicKeys.version ,
senderKeyVersion : parseKeyVersion ( senderUserGroup . groupKeyVersion ) ,
2024-09-05 13:11:59 +02:00
pubEncSymKeyBytes : encodedPqMessage ,
cryptoProtocolVersion : CryptoProtocolVersion.TUTA_CRYPT ,
2023-12-18 11:36:38 +01:00
} )
2025-02-10 13:15:28 +01:00
const internalRecipientKeyData = ( await crypto . encryptBucketKeyForInternalRecipient (
2023-12-18 11:36:38 +01:00
senderUserGroup . _id ,
bk ,
recipientMailAddress ,
notFoundRecipients ,
2025-03-25 15:35:51 +01:00
keyVerificationMismatchRecipients ,
2023-12-18 11:36:38 +01:00
) ) as InternalRecipientKeyData
2024-04-17 10:34:33 +02:00
o ( internalRecipientKeyData ! . recipientKeyVersion ) . equals ( "0" )
2024-09-05 13:11:59 +02:00
o ( internalRecipientKeyData . protocolVersion ) . equals ( CryptoProtocolVersion . TUTA_CRYPT )
2023-12-18 11:36:38 +01:00
o ( internalRecipientKeyData ! . mailAddress ) . equals ( recipientMailAddress )
2024-09-05 13:11:59 +02:00
o ( internalRecipientKeyData ! . pubEncBucketKey ) . deepEquals ( encodedPqMessage )
2025-05-23 16:45:41 +02:00
verify (
2025-06-05 17:07:31 +02:00
publicEncryptionKeyProvider . loadCurrentPublicEncryptionKey ( {
2025-05-23 16:45:41 +02:00
identifierType : PublicKeyIdentifierType.MAIL_ADDRESS ,
identifier : recipientMailAddress ,
} ) ,
{ times : 1 } ,
)
2023-12-18 11:36:38 +01:00
} )
o ( "encryptBucketKeyForInternalRecipient with existing PQKeys for sender" , async ( ) = > {
let recipientMailAddress = "bob@tutanota.com"
let bk = aes256RandomKey ( )
2025-02-10 13:15:28 +01:00
let senderMailAddress = "alice@tutanota.com"
2023-12-18 11:36:38 +01:00
2025-02-10 13:15:28 +01:00
const senderKeyPair : KeyPair = object ( )
2023-12-18 11:36:38 +01:00
const senderUserGroup = createGroup ( {
_id : "userGroupId" ,
2024-04-17 10:34:33 +02:00
currentKeys : senderKeyPair ,
groupKeyVersion : "0" ,
2023-12-18 11:36:38 +01:00
_permissions : "" ,
admin : null ,
adminGroupEncGKey : null ,
2024-04-17 10:34:33 +02:00
adminGroupKeyVersion : null ,
2023-12-18 11:36:38 +01:00
archives : [ ] ,
customer : null ,
enabled : false ,
external : false ,
groupInfo : [ "" , "" ] ,
invitations : "" ,
members : "" ,
storageCounter : null ,
type : "" ,
user : null ,
2025-04-10 13:44:34 +02:00
formerGroupKeys : createTestEntity ( GroupKeysRefTypeRef ) ,
2024-04-17 10:34:33 +02:00
pubAdminGroupEncGKey : null ,
2025-06-17 14:14:52 +02:00
identityKeyPair : null ,
2023-12-18 11:36:38 +01:00
} )
2025-02-10 13:15:28 +01:00
2023-12-18 11:36:38 +01:00
const notFoundRecipients = [ ]
2025-03-25 15:35:51 +01:00
const keyVerificationMismatchRecipients = [ ]
2023-12-18 11:36:38 +01:00
2025-02-10 13:15:28 +01:00
const recipientPublicKeys : Versioned < RsaPublicKey > = {
2025-01-20 13:40:57 +01:00
version : 0 ,
2025-02-10 13:15:28 +01:00
object : object ( ) ,
2025-01-20 13:40:57 +01:00
}
2025-06-05 17:07:31 +02:00
const loadedRecipientPublicKey : VerifiedPublicEncryptionKey = {
2025-05-23 16:45:41 +02:00
publicEncryptionKey : recipientPublicKeys ,
verificationState : EncryptionKeyVerificationState.NO_ENTRY ,
}
2025-06-05 17:07:31 +02:00
when ( publicEncryptionKeyProvider . loadCurrentPublicEncryptionKey ( anything ( ) ) ) . thenResolve ( loadedRecipientPublicKey )
2025-02-10 13:15:28 +01:00
const senderPublicKeys : Versioned < PQPublicKeys > = {
2025-01-20 13:40:57 +01:00
version : 0 ,
2025-02-10 13:15:28 +01:00
object : object ( ) ,
}
2025-06-05 17:07:31 +02:00
const loadedSenderPublicKey : VerifiedPublicEncryptionKey = {
2025-05-23 16:45:41 +02:00
publicEncryptionKey : senderPublicKeys ,
verificationState : EncryptionKeyVerificationState.NO_ENTRY ,
}
2025-02-10 13:15:28 +01:00
when (
2025-06-05 17:07:31 +02:00
publicEncryptionKeyProvider . loadCurrentPublicEncryptionKey ( {
2025-02-10 13:15:28 +01:00
identifierType : PublicKeyIdentifierType.MAIL_ADDRESS ,
identifier : senderMailAddress ,
} ) ,
2025-05-23 16:45:41 +02:00
) . thenResolve ( loadedSenderPublicKey )
2025-02-10 13:15:28 +01:00
2024-09-05 13:11:59 +02:00
const pubEncBucketKey = object < Uint8Array > ( )
2025-01-20 13:40:57 +01:00
when ( asymmetricCryptoFacade . asymEncryptSymKey ( bk , recipientPublicKeys , senderUserGroup . _id ) ) . thenResolve ( {
recipientKeyVersion : recipientPublicKeys.version ,
senderKeyVersion : parseKeyVersion ( senderUserGroup . groupKeyVersion ) ,
2024-09-05 13:11:59 +02:00
pubEncSymKeyBytes : pubEncBucketKey ,
cryptoProtocolVersion : CryptoProtocolVersion.RSA ,
} )
2023-12-18 11:36:38 +01:00
2025-02-10 13:15:28 +01:00
const internalRecipientKeyData = ( await crypto . encryptBucketKeyForInternalRecipient (
2023-12-18 11:36:38 +01:00
senderUserGroup . _id ,
bk ,
recipientMailAddress ,
notFoundRecipients ,
2025-03-25 15:35:51 +01:00
keyVerificationMismatchRecipients ,
2023-12-18 11:36:38 +01:00
) ) as InternalRecipientKeyData
2024-04-17 10:34:33 +02:00
o ( internalRecipientKeyData ! . recipientKeyVersion ) . equals ( "0" )
2023-12-18 11:36:38 +01:00
o ( internalRecipientKeyData ! . mailAddress ) . equals ( recipientMailAddress )
2024-09-05 13:11:59 +02:00
o ( internalRecipientKeyData . protocolVersion ) . equals ( CryptoProtocolVersion . RSA )
o ( internalRecipientKeyData . pubEncBucketKey ) . deepEquals ( pubEncBucketKey )
2025-05-23 16:45:41 +02:00
verify (
2025-06-05 17:07:31 +02:00
publicEncryptionKeyProvider . loadCurrentPublicEncryptionKey ( {
2025-05-23 16:45:41 +02:00
identifierType : PublicKeyIdentifierType.MAIL_ADDRESS ,
identifier : recipientMailAddress ,
} ) ,
{ times : 1 } ,
)
2023-12-18 11:36:38 +01:00
} )
2025-03-25 15:35:51 +01:00
o ( "encryptBucketKeyForInternalRecipient for non-existing recipients" , async function ( ) {
let notFoundRecipientMailAddress = "notfound@tutanota.com"
let bk = aes256RandomKey ( )
const notFoundRecipients : string [ ] = [ ]
const keyVerificationMismatchRecipients : string [ ] = [ ]
when (
2025-06-05 17:07:31 +02:00
publicEncryptionKeyProvider . loadCurrentPublicEncryptionKey ( {
2025-03-25 15:35:51 +01:00
identifierType : PublicKeyIdentifierType.MAIL_ADDRESS ,
identifier : notFoundRecipientMailAddress ,
} ) ,
) . thenReject ( new NotFoundError ( "" ) )
await crypto . encryptBucketKeyForInternalRecipient (
"senderGroupId" ,
bk ,
notFoundRecipientMailAddress ,
notFoundRecipients ,
keyVerificationMismatchRecipients ,
)
o ( notFoundRecipients ) . deepEquals ( [ "notfound@tutanota.com" ] )
o ( keyVerificationMismatchRecipients ) . deepEquals ( [ ] )
verify ( userFacade . getUser ( ) , { times : 0 } )
} )
2025-05-23 16:45:41 +02:00
o ( "encryptBucketKeyForInternalRecipient with non-existing recipients" , async function ( ) {
let notFoundRecipient1MailAddress = "notfound1@tutanota.com"
let notFoundRecipient2MailAddress = "notfound2@tutanota.com"
const validRecipientMailAddress = "alice@tuta.com"
let bk = aes256RandomKey ( )
const notFoundRecipients : string [ ] = [ ]
const mismatchRecipients : string [ ] = [ ]
const recipientPublicKey : Versioned < PQPublicKeys > = {
version : 0 ,
object : object ( ) ,
}
recipientPublicKey . object . keyPairType = KeyPairType . TUTA_CRYPT
2025-06-05 17:07:31 +02:00
const loadedRecipientPublicKey : VerifiedPublicEncryptionKey = {
2025-05-23 16:45:41 +02:00
publicEncryptionKey : recipientPublicKey ,
verificationState : EncryptionKeyVerificationState.NO_ENTRY ,
}
when (
2025-06-05 17:07:31 +02:00
publicEncryptionKeyProvider . loadCurrentPublicEncryptionKey ( {
2025-05-23 16:45:41 +02:00
identifierType : PublicKeyIdentifierType.MAIL_ADDRESS ,
identifier : validRecipientMailAddress ,
} ) ,
) . thenResolve ( loadedRecipientPublicKey )
when (
2025-06-05 17:07:31 +02:00
publicEncryptionKeyProvider . loadCurrentPublicEncryptionKey ( {
2025-05-23 16:45:41 +02:00
identifierType : PublicKeyIdentifierType.MAIL_ADDRESS ,
identifier : notFoundRecipient1MailAddress ,
} ) ,
) . thenReject ( new NotFoundError ( "" ) )
when (
2025-06-05 17:07:31 +02:00
publicEncryptionKeyProvider . loadCurrentPublicEncryptionKey ( {
2025-05-23 16:45:41 +02:00
identifierType : PublicKeyIdentifierType.MAIL_ADDRESS ,
identifier : notFoundRecipient2MailAddress ,
} ) ,
) . thenReject ( new NotFoundError ( "" ) )
await crypto . encryptBucketKeyForInternalRecipient ( "senderGroupId" , bk , notFoundRecipient1MailAddress , notFoundRecipients , mismatchRecipients )
await crypto . encryptBucketKeyForInternalRecipient ( "senderGroupId" , bk , validRecipientMailAddress , notFoundRecipients , mismatchRecipients )
await crypto . encryptBucketKeyForInternalRecipient ( "senderGroupId" , bk , notFoundRecipient2MailAddress , notFoundRecipients , mismatchRecipients )
o ( notFoundRecipients ) . deepEquals ( [ notFoundRecipient1MailAddress , notFoundRecipient2MailAddress ] )
o ( mismatchRecipients ) . deepEquals ( [ ] )
verify ( userFacade . getUser ( ) , { times : 0 } )
} )
2025-03-25 15:35:51 +01:00
o ( "encryptBucketKeyForInternalRecipient for verification-failing recipients" , async function ( ) {
2025-05-23 16:45:41 +02:00
let mismatchRecipient1MailAddress = "mismatch1@tutanota.com"
let mismatchRecipient2MailAddress = "mismatch2@tutanota.com"
const validRecipientMailAddress = "alice@tuta.com"
let bk = aes256RandomKey ( )
const notFoundRecipients : string [ ] = [ ]
const mismatchRecipients : string [ ] = [ ]
const recipientPublicKey : Versioned < PQPublicKeys > = {
version : 0 ,
object : object ( ) ,
}
recipientPublicKey . object . keyPairType = KeyPairType . TUTA_CRYPT
2025-06-05 17:07:31 +02:00
const loadedRecipientPublicKey : VerifiedPublicEncryptionKey = {
2025-05-23 16:45:41 +02:00
publicEncryptionKey : recipientPublicKey ,
verificationState : EncryptionKeyVerificationState.NO_ENTRY ,
}
when (
2025-06-05 17:07:31 +02:00
publicEncryptionKeyProvider . loadCurrentPublicEncryptionKey ( {
2025-05-23 16:45:41 +02:00
identifierType : PublicKeyIdentifierType.MAIL_ADDRESS ,
identifier : validRecipientMailAddress ,
} ) ,
) . thenResolve ( loadedRecipientPublicKey )
when (
2025-06-05 17:07:31 +02:00
publicEncryptionKeyProvider . loadCurrentPublicEncryptionKey ( {
2025-05-23 16:45:41 +02:00
identifierType : PublicKeyIdentifierType.MAIL_ADDRESS ,
identifier : mismatchRecipient1MailAddress ,
} ) ,
) . thenReject ( new KeyVerificationMismatchError ( "" ) )
when (
2025-06-05 17:07:31 +02:00
publicEncryptionKeyProvider . loadCurrentPublicEncryptionKey ( {
2025-05-23 16:45:41 +02:00
identifierType : PublicKeyIdentifierType.MAIL_ADDRESS ,
identifier : mismatchRecipient2MailAddress ,
} ) ,
) . thenReject ( new KeyVerificationMismatchError ( "" ) )
await crypto . encryptBucketKeyForInternalRecipient ( "senderGroupId" , bk , mismatchRecipient1MailAddress , notFoundRecipients , mismatchRecipients )
await crypto . encryptBucketKeyForInternalRecipient ( "senderGroupId" , bk , validRecipientMailAddress , notFoundRecipients , mismatchRecipients )
await crypto . encryptBucketKeyForInternalRecipient ( "senderGroupId" , bk , mismatchRecipient2MailAddress , notFoundRecipients , mismatchRecipients )
o ( notFoundRecipients ) . deepEquals ( [ ] )
o ( mismatchRecipients ) . deepEquals ( [ mismatchRecipient1MailAddress , mismatchRecipient2MailAddress ] )
verify ( userFacade . getUser ( ) , { times : 0 } )
2025-03-25 15:35:51 +01:00
} )
2023-12-18 11:36:38 +01:00
o ( "authenticateSender | sender is authenticated for correct SenderIdentityKey" , async function ( ) {
o . timeout ( 500 ) // in CI or with debugging it can take a while
const testData = await preparePqPubEncBucketKeyResolveSessionKeyTest ( )
2024-09-16 11:21:45 +02:00
const senderKeyVersion = "0"
when (
asymmetricCryptoFacade . authenticateSender (
{
identifier : senderAddress ,
identifierType : PublicKeyIdentifierType.MAIL_ADDRESS ,
} ,
testData . senderIdentityKeyPair . publicKey ,
2025-01-20 13:40:57 +01:00
parseKeyVersion ( senderKeyVersion ) ,
2024-09-16 11:21:45 +02:00
) ,
2025-11-03 18:01:36 +01:00
) . thenResolve ( {
authStatus : EncryptionAuthStatus.TUTACRYPT_AUTHENTICATION_SUCCEEDED ,
verificationState : PresentableKeyVerificationState.SECURE ,
} )
2023-12-18 11:36:38 +01:00
2025-03-10 16:19:11 +01:00
const sessionKey : AesKey = neverNull ( await crypto . resolveSessionKey ( testData . mail ) )
2023-12-18 11:36:38 +01:00
o ( sessionKey ) . deepEquals ( testData . sk )
const updatedInstanceSessionKeysCaptor = captor ( )
2024-06-10 14:05:35 +02:00
verify ( ownerEncSessionKeysUpdateQueue . updateInstanceSessionKeys ( updatedInstanceSessionKeysCaptor . capture ( ) , anything ( ) ) )
2023-12-18 11:36:38 +01:00
const updatedInstanceSessionKeys = updatedInstanceSessionKeysCaptor . value as Array < InstanceSessionKey >
2025-03-10 16:19:11 +01:00
o ( updatedInstanceSessionKeys . length ) . equals ( testData . mail . bucketKey ! . bucketEncSessionKeys . length )
2023-12-18 11:36:38 +01:00
const mailInstanceSessionKey = updatedInstanceSessionKeys . find ( ( instanceSessionKey ) = >
2025-03-10 16:19:11 +01:00
isSameId ( [ instanceSessionKey . instanceList , instanceSessionKey . instanceId ] , testData . mail . _id ) ,
2023-12-18 11:36:38 +01:00
)
const actualAutStatus = utf8Uint8ArrayToString ( aesDecrypt ( testData . sk , neverNull ( mailInstanceSessionKey ) . encryptionAuthStatus ! ) )
2024-05-06 11:08:05 +02:00
o ( actualAutStatus ) . deepEquals ( EncryptionAuthStatus . TUTACRYPT_AUTHENTICATION_SUCCEEDED )
2023-12-18 11:36:38 +01:00
} )
o ( "authenticateSender | sender is authenticated for correct SenderIdentityKey from system@tutanota.de" , async function ( ) {
o . timeout ( 500 ) // in CI or with debugging it can take a while
const testData = await preparePqPubEncBucketKeyResolveSessionKeyTest ( [ ] , false )
2024-09-16 11:21:45 +02:00
const senderKeyVersion = "0"
const senderIdentifier = "system@tutanota.de"
when (
asymmetricCryptoFacade . authenticateSender (
{
identifier : senderIdentifier ,
identifierType : PublicKeyIdentifierType.MAIL_ADDRESS ,
} ,
testData . senderIdentityKeyPair . publicKey ,
2025-01-20 13:40:57 +01:00
parseKeyVersion ( senderKeyVersion ) ,
2024-09-16 11:21:45 +02:00
) ,
2025-11-03 18:01:36 +01:00
) . thenResolve ( {
authStatus : EncryptionAuthStatus.TUTACRYPT_AUTHENTICATION_SUCCEEDED ,
verificationState : PresentableKeyVerificationState.SECURE ,
} )
2023-12-18 11:36:38 +01:00
2025-03-10 16:19:11 +01:00
const sessionKey : AesKey = neverNull ( await crypto . resolveSessionKey ( testData . mail ) )
2023-12-18 11:36:38 +01:00
o ( sessionKey ) . deepEquals ( testData . sk )
const updatedInstanceSessionKeysCaptor = captor ( )
2024-06-10 14:05:35 +02:00
verify ( ownerEncSessionKeysUpdateQueue . updateInstanceSessionKeys ( updatedInstanceSessionKeysCaptor . capture ( ) , anything ( ) ) )
2023-12-18 11:36:38 +01:00
const updatedInstanceSessionKeys = updatedInstanceSessionKeysCaptor . value as Array < InstanceSessionKey >
2025-03-10 16:19:11 +01:00
o ( updatedInstanceSessionKeys . length ) . equals ( testData . mail . bucketKey ! . bucketEncSessionKeys . length )
const mailInstanceSessionKey = assertNotNull (
updatedInstanceSessionKeys . find ( ( instanceSessionKey ) = >
isSameId ( [ instanceSessionKey . instanceList , instanceSessionKey . instanceId ] , testData . mail . _id ) ,
) ,
2023-12-18 11:36:38 +01:00
)
2025-03-10 16:19:11 +01:00
const actualAutStatus = utf8Uint8ArrayToString ( aesDecrypt ( testData . sk , mailInstanceSessionKey . encryptionAuthStatus ! ) )
2024-05-06 11:08:05 +02:00
o ( actualAutStatus ) . deepEquals ( EncryptionAuthStatus . TUTACRYPT_AUTHENTICATION_SUCCEEDED )
2023-12-18 11:36:38 +01:00
} )
o ( "authenticateSender | sender is not authenticated for incorrect SenderIdentityKey" , async function ( ) {
o . timeout ( 500 ) // in CI or with debugging it can take a while
const testData = await preparePqPubEncBucketKeyResolveSessionKeyTest ( )
2024-09-16 11:21:45 +02:00
const senderKeyVersion = "0"
when (
asymmetricCryptoFacade . authenticateSender (
{
identifier : senderAddress ,
identifierType : PublicKeyIdentifierType.MAIL_ADDRESS ,
} ,
testData . senderIdentityKeyPair . publicKey ,
2025-01-20 13:40:57 +01:00
parseKeyVersion ( senderKeyVersion ) ,
2024-09-16 11:21:45 +02:00
) ,
2025-11-03 18:01:36 +01:00
) . thenResolve ( {
authStatus : EncryptionAuthStatus.TUTACRYPT_AUTHENTICATION_FAILED ,
verificationState : PresentableKeyVerificationState.ALERT ,
} )
2023-12-18 11:36:38 +01:00
2025-03-10 16:19:11 +01:00
const sessionKey = neverNull ( await crypto . resolveSessionKey ( testData . mail ) )
2023-12-18 11:36:38 +01:00
o ( sessionKey ) . deepEquals ( testData . sk )
const updatedInstanceSessionKeysCaptor = captor ( )
2024-06-10 14:05:35 +02:00
verify ( ownerEncSessionKeysUpdateQueue . updateInstanceSessionKeys ( updatedInstanceSessionKeysCaptor . capture ( ) , anything ( ) ) )
2023-12-18 11:36:38 +01:00
const updatedInstanceSessionKeys = updatedInstanceSessionKeysCaptor . value as Array < InstanceSessionKey >
2025-03-10 16:19:11 +01:00
o ( updatedInstanceSessionKeys . length ) . equals ( testData . mail . bucketKey ! . bucketEncSessionKeys . length )
2023-12-18 11:36:38 +01:00
const mailInstanceSessionKey = updatedInstanceSessionKeys . find ( ( instanceSessionKey ) = >
2025-03-10 16:19:11 +01:00
isSameId ( [ instanceSessionKey . instanceList , instanceSessionKey . instanceId ] , testData . mail . _id ) ,
2023-12-18 11:36:38 +01:00
)
const actualAutStatus = utf8Uint8ArrayToString ( aesDecrypt ( testData . sk , neverNull ( mailInstanceSessionKey ) . encryptionAuthStatus ! ) )
2024-05-06 11:08:05 +02:00
o ( actualAutStatus ) . deepEquals ( EncryptionAuthStatus . TUTACRYPT_AUTHENTICATION_FAILED )
2023-12-18 11:36:38 +01:00
} )
o ( "authenticateSender | no authentication needed for sender with RSAKeypair" , async function ( ) {
o . timeout ( 500 ) // in CI or with debugging it can take a while
const testData = await prepareRsaPubEncBucketKeyResolveSessionKeyTest ( )
2025-03-10 16:19:11 +01:00
const sessionKey = assertNotNull ( await crypto . resolveSessionKey ( testData . mail ) )
2023-12-18 11:36:38 +01:00
o ( sessionKey ) . deepEquals ( testData . sk )
const updatedInstanceSessionKeysCaptor = captor ( )
2024-06-10 14:05:35 +02:00
verify ( ownerEncSessionKeysUpdateQueue . updateInstanceSessionKeys ( updatedInstanceSessionKeysCaptor . capture ( ) , anything ( ) ) , { times : 1 } )
2023-12-18 11:36:38 +01:00
const updatedInstanceSessionKeys = updatedInstanceSessionKeysCaptor . value as Array < InstanceSessionKey >
2025-03-10 16:19:11 +01:00
o ( updatedInstanceSessionKeys . length ) . equals ( testData . mail . bucketKey ! . bucketEncSessionKeys . length )
2023-12-18 11:36:38 +01:00
const mailInstanceSessionKey = updatedInstanceSessionKeys . find ( ( instanceSessionKey ) = >
2025-03-10 16:19:11 +01:00
isSameId ( [ instanceSessionKey . instanceList , instanceSessionKey . instanceId ] , testData . mail . _id ) ,
2023-12-18 11:36:38 +01:00
)
2025-03-10 16:19:11 +01:00
const actualAuthStatus = utf8Uint8ArrayToString ( aesDecrypt ( testData . sk , assertNotNull ( mailInstanceSessionKey ) . encryptionAuthStatus ! ) )
o ( actualAuthStatus ) . deepEquals ( EncryptionAuthStatus . RSA_NO_AUTHENTICATION )
2023-12-18 11:36:38 +01:00
} )
2025-01-28 18:46:02 +01:00
o ( "authenticateSender | RSA was used despite recipient having tutacrypt" , async function ( ) {
o . timeout ( 500 ) // in CI or with debugging it can take a while
const testData = await prepareRsaPubEncBucketKeyResolveSessionKeyTest ( )
when ( keyLoaderFacade . loadCurrentKeyPair ( anything ( ) ) ) . thenResolve ( {
version : 1 ,
object : {
keyPairType : KeyPairType.TUTA_CRYPT ,
kyberKeyPair : object ( ) ,
2025-04-02 13:46:11 +02:00
x25519KeyPair : object ( ) ,
2025-01-28 18:46:02 +01:00
} ,
} )
when ( keyRotationFacade . getGroupIdsThatPerformedKeyRotations ( ) ) . thenResolve ( [ ] )
2025-03-10 16:19:11 +01:00
const sessionKey = neverNull ( await crypto . resolveSessionKey ( testData . mail ) )
2025-01-28 18:46:02 +01:00
o ( sessionKey ) . deepEquals ( testData . sk )
const updatedInstanceSessionKeysCaptor = captor ( )
verify ( ownerEncSessionKeysUpdateQueue . updateInstanceSessionKeys ( updatedInstanceSessionKeysCaptor . capture ( ) , anything ( ) ) , { times : 1 } )
const updatedInstanceSessionKeys = updatedInstanceSessionKeysCaptor . value as Array < InstanceSessionKey >
2025-03-10 16:19:11 +01:00
o ( updatedInstanceSessionKeys . length ) . equals ( testData . mail . bucketKey ! . bucketEncSessionKeys . length )
2025-01-28 18:46:02 +01:00
const mailInstanceSessionKey = updatedInstanceSessionKeys . find ( ( instanceSessionKey ) = >
2025-03-10 16:19:11 +01:00
isSameId ( [ instanceSessionKey . instanceList , instanceSessionKey . instanceId ] , testData . mail . _id ) ,
2025-01-28 18:46:02 +01:00
)
const actualAutStatus = utf8Uint8ArrayToString ( aesDecrypt ( testData . sk , neverNull ( mailInstanceSessionKey ) . encryptionAuthStatus ! ) )
o ( actualAutStatus ) . deepEquals ( EncryptionAuthStatus . RSA_DESPITE_TUTACRYPT )
} )
o ( "authenticateSender | RSA was used right after a key rotation" , async function ( ) {
o . timeout ( 500 ) // in CI or with debugging it can take a while
const testData = await prepareRsaPubEncBucketKeyResolveSessionKeyTest ( )
when ( keyLoaderFacade . loadCurrentKeyPair ( anything ( ) ) ) . thenResolve ( {
version : 1 ,
object : {
keyPairType : KeyPairType.TUTA_CRYPT ,
kyberKeyPair : object ( ) ,
2025-04-02 13:46:11 +02:00
x25519KeyPair : object ( ) ,
2025-01-28 18:46:02 +01:00
} ,
} )
when ( keyRotationFacade . getGroupIdsThatPerformedKeyRotations ( ) ) . thenResolve ( [ testData . userGroupId ] )
2025-03-10 16:19:11 +01:00
const sessionKey = neverNull ( await crypto . resolveSessionKey ( testData . mail ) )
const bucketKey = assertNotNull ( testData . mail . bucketKey )
2025-01-28 18:46:02 +01:00
o ( sessionKey ) . deepEquals ( testData . sk )
const updatedInstanceSessionKeysCaptor = captor ( )
verify ( ownerEncSessionKeysUpdateQueue . updateInstanceSessionKeys ( updatedInstanceSessionKeysCaptor . capture ( ) , anything ( ) ) , { times : 1 } )
const updatedInstanceSessionKeys = updatedInstanceSessionKeysCaptor . value as Array < InstanceSessionKey >
2025-03-10 16:19:11 +01:00
o ( updatedInstanceSessionKeys . length ) . equals ( bucketKey . bucketEncSessionKeys . length )
2025-01-28 18:46:02 +01:00
const mailInstanceSessionKey = updatedInstanceSessionKeys . find ( ( instanceSessionKey ) = >
2025-03-10 16:19:11 +01:00
isSameId ( [ instanceSessionKey . instanceList , instanceSessionKey . instanceId ] , testData . mail . _id ) ,
2025-01-28 18:46:02 +01:00
)
const actualAutStatus = utf8Uint8ArrayToString ( aesDecrypt ( testData . sk , neverNull ( mailInstanceSessionKey ) . encryptionAuthStatus ! ) )
o ( actualAutStatus ) . deepEquals ( EncryptionAuthStatus . RSA_NO_AUTHENTICATION )
} )
2023-12-18 11:36:38 +01:00
o ( "authenticateSender | no authentication needed for secure external recipient" , async function ( ) {
o . timeout ( 500 ) // in CI or with debugging it can take a while
2023-12-05 14:03:33 +01:00
const file1SessionKey = aes256RandomKey ( )
const file2SessionKey = aes256RandomKey ( )
2023-12-18 11:36:38 +01:00
const testData = await prepareConfidentialMailToExternalRecipient ( [ file1SessionKey , file2SessionKey ] )
2025-03-10 16:19:11 +01:00
const mailSessionKey = neverNull ( await crypto . resolveSessionKey ( testData . entityAdapter ) )
2023-12-18 11:36:38 +01:00
o ( mailSessionKey ) . deepEquals ( testData . sk )
const updatedInstanceSessionKeysCaptor = captor ( )
2024-06-10 14:05:35 +02:00
verify ( ownerEncSessionKeysUpdateQueue . updateInstanceSessionKeys ( updatedInstanceSessionKeysCaptor . capture ( ) , anything ( ) ) , { times : 1 } )
2023-12-18 11:36:38 +01:00
const updatedInstanceSessionKeys = updatedInstanceSessionKeysCaptor . value as Array < InstanceSessionKey >
o ( updatedInstanceSessionKeys . length ) . equals ( testData . bucketKey . bucketEncSessionKeys . length )
const mailInstanceSessionKey = updatedInstanceSessionKeys . find ( ( instanceSessionKey ) = >
2025-03-10 16:19:11 +01:00
isSameId ( [ instanceSessionKey . instanceList , instanceSessionKey . instanceId ] , testData . entityAdapter . _id ) ,
2023-12-18 11:36:38 +01:00
)
const actualAutStatus = utf8Uint8ArrayToString ( aesDecrypt ( testData . sk , neverNull ( mailInstanceSessionKey ) . encryptionAuthStatus ! ) )
o ( actualAutStatus ) . deepEquals ( EncryptionAuthStatus . AES_NO_AUTHENTICATION )
} )
o ( "authenticateSender | no authentication needed for secure external sender" , async function ( ) {
//o.timeout(500) // in CI or with debugging it can take a while
const testData = await prepareConfidentialReplyFromExternalUser ( )
2024-04-17 10:34:33 +02:00
const externalUser = testData . externalUser
2023-12-18 11:36:38 +01:00
2025-03-10 16:19:11 +01:00
const mailSessionKey = neverNull ( await crypto . resolveSessionKey ( testData . entityAdapter ) )
2023-12-18 11:36:38 +01:00
o ( mailSessionKey ) . deepEquals ( testData . sk )
2024-04-17 10:34:33 +02:00
const mailCaptor = matchers . captor ( )
const userCaptor = matchers . captor ( )
2025-01-20 13:40:57 +01:00
verify ( keyLoaderFacade . loadSymGroupKey ( externalUser . userGroup . _id , parseKeyVersion ( externalUser . mailGroup . adminGroupKeyVersion ! ) , userCaptor . capture ( ) ) )
2024-04-17 10:34:33 +02:00
verify ( keyLoaderFacade . loadSymGroupKey ( externalUser . mailGroup . _id , testData . recipientKeyVersion , mailCaptor . capture ( ) ) )
2025-01-20 13:40:57 +01:00
o ( userCaptor . value . version ) . equals ( parseKeyVersion ( externalUser . userGroup . groupKeyVersion ) )
o ( mailCaptor . value . version ) . equals ( parseKeyVersion ( externalUser . mailGroup . groupKeyVersion ) )
2024-04-17 10:34:33 +02:00
2023-12-18 11:36:38 +01:00
const updatedInstanceSessionKeysCaptor = captor ( )
2024-06-10 14:05:35 +02:00
verify ( ownerEncSessionKeysUpdateQueue . updateInstanceSessionKeys ( updatedInstanceSessionKeysCaptor . capture ( ) , anything ( ) ) , { times : 1 } )
2023-12-18 11:36:38 +01:00
const updatedInstanceSessionKeys = updatedInstanceSessionKeysCaptor . value as Array < InstanceSessionKey >
o ( updatedInstanceSessionKeys . length ) . equals ( testData . bucketKey . bucketEncSessionKeys . length )
const mailInstanceSessionKey = updatedInstanceSessionKeys . find ( ( instanceSessionKey ) = >
2025-03-10 16:19:11 +01:00
isSameId ( [ instanceSessionKey . instanceList , instanceSessionKey . instanceId ] , testData . entityAdapter . _id ) ,
2023-12-18 11:36:38 +01:00
)
const actualAutStatus = utf8Uint8ArrayToString ( aesDecrypt ( testData . sk , neverNull ( mailInstanceSessionKey ) . encryptionAuthStatus ! ) )
o ( actualAutStatus ) . deepEquals ( EncryptionAuthStatus . AES_NO_AUTHENTICATION )
} )
2025-03-10 16:19:11 +01:00
o ( "resolve session key: rsa public key decryption of session key using BucketKey aggregated type" , async function ( ) {
2023-12-18 11:36:38 +01:00
o . timeout ( 500 ) // in CI or with debugging it can take a while
const testData = await prepareRsaPubEncBucketKeyResolveSessionKeyTest ( )
2025-03-10 16:19:11 +01:00
const sessionKey = neverNull ( await crypto . resolveSessionKey ( testData . mail ) )
2023-12-18 11:36:38 +01:00
o ( sessionKey ) . deepEquals ( testData . sk )
} )
o (
"resolve session key: rsa public key decryption of mail session key using BucketKey aggregated type - already decoded/decrypted Mail referencing MailDetailsDraft" ,
async function ( ) {
2023-01-12 16:48:28 +01:00
o . timeout ( 500 ) // in CI or with debugging it can take a while
2023-12-18 11:36:38 +01:00
const testData = await prepareRsaPubEncBucketKeyResolveSessionKeyTest ( )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
2023-12-18 11:36:38 +01:00
// do not use testdouble here because it's hard to not break the function itself and then verify invocations
2025-03-10 16:19:11 +01:00
const decryptAndMapToInstance = ( instancePipeline . cryptoMapper . decryptParsedInstance = spy ( instancePipeline . cryptoMapper . decryptParsedInstance ) )
2023-12-18 11:36:38 +01:00
2025-03-10 16:19:11 +01:00
const sessionKey = neverNull ( await crypto . resolveSessionKey ( testData . mail ) )
2023-12-18 11:36:38 +01:00
o ( decryptAndMapToInstance . invocations . length ) . equals ( 0 )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
2023-01-12 16:48:28 +01:00
o ( sessionKey ) . deepEquals ( testData . sk )
2023-12-18 11:36:38 +01:00
} ,
)
o ( "resolve session key: rsa public key decryption of session key using BucketKey aggregated type - Mail referencing MailDetailsBlob" , async function ( ) {
o . timeout ( 500 ) // in CI or with debugging it can take a while
const testData = await prepareRsaPubEncBucketKeyResolveSessionKeyTest ( )
2025-03-10 16:19:11 +01:00
const sessionKey = neverNull ( await crypto . resolveSessionKey ( testData . mail ) )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
2023-12-18 11:36:38 +01:00
o ( sessionKey ) . deepEquals ( testData . sk )
} )
o (
"resolve session key: rsa public key decryption of session key using BucketKey aggregated type - Mail referencing MailDetailsBlob with attachments" ,
async function ( ) {
2023-01-12 16:48:28 +01:00
o . timeout ( 500 ) // in CI or with debugging it can take a while
2023-12-05 14:03:33 +01:00
const file1SessionKey = aes256RandomKey ( )
const file2SessionKey = aes256RandomKey ( )
2023-12-18 11:36:38 +01:00
const testData = await prepareRsaPubEncBucketKeyResolveSessionKeyTest ( [ file1SessionKey , file2SessionKey ] )
2023-01-12 16:48:28 +01:00
2025-03-10 16:19:11 +01:00
const mailSessionKey = assertNotNull ( await crypto . resolveSessionKey ( testData . mail ) )
2023-12-18 11:36:38 +01:00
o ( mailSessionKey ) . deepEquals ( testData . sk )
2023-01-12 16:48:28 +01:00
2025-03-10 16:19:11 +01:00
const bucketKey = assertNotNull ( testData . mail . bucketKey )
o ( bucketKey . bucketEncSessionKeys . length ) . equals ( 3 ) //mail, file1, file2
2023-12-18 11:36:38 +01:00
const updatedInstanceSessionKeysCaptor = captor ( )
2024-06-10 14:05:35 +02:00
verify ( ownerEncSessionKeysUpdateQueue . updateInstanceSessionKeys ( updatedInstanceSessionKeysCaptor . capture ( ) , anything ( ) ) )
2023-12-18 11:36:38 +01:00
const updatedInstanceSessionKeys = updatedInstanceSessionKeysCaptor . value
2025-03-10 16:19:11 +01:00
o ( updatedInstanceSessionKeys . length ) . equals ( bucketKey . bucketEncSessionKeys . length )
for ( const isk of bucketKey . bucketEncSessionKeys ) {
2023-12-05 14:03:33 +01:00
const expectedSessionKey = decryptKey ( testData . bk , isk . symEncSessionKey )
2023-12-18 11:36:38 +01:00
o (
2023-12-05 14:03:33 +01:00
updatedInstanceSessionKeys . some ( ( updatedKey ) = > {
let updatedSessionKey = decryptKey ( testData . mailGroupKey , updatedKey . symEncSessionKey )
return (
2023-12-18 11:36:38 +01:00
updatedKey . instanceId === isk . instanceId &&
updatedKey . instanceList === isk . instanceList &&
updatedKey . typeInfo . application === isk . typeInfo . application &&
updatedKey . typeInfo . typeId === isk . typeInfo . typeId &&
2023-12-05 14:03:33 +01:00
arrayEquals ( updatedSessionKey , expectedSessionKey )
)
} ) ,
2023-12-18 11:36:38 +01:00
) . equals ( true )
}
} ,
)
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
2023-12-18 11:36:38 +01:00
// ------------
2023-01-12 16:48:28 +01:00
2025-03-10 16:19:11 +01:00
o ( "resolve session key: pq public key decryption of mail session key using BucketKey aggregated type - Mail" , async function ( ) {
2023-12-18 11:36:38 +01:00
o . timeout ( 500 ) // in CI or with debugging it can take a while
const testData = await preparePqPubEncBucketKeyResolveSessionKeyTest ( )
2025-07-09 17:17:35 +02:00
when (
asymmetricCryptoFacade . authenticateSender (
{
identifier : senderAddress ,
identifierType : PublicKeyIdentifierType.MAIL_ADDRESS ,
} ,
anything ( ) ,
anything ( ) ,
) ,
2025-11-03 18:01:36 +01:00
) . thenResolve ( {
authStatus : EncryptionAuthStatus.TUTACRYPT_AUTHENTICATION_SUCCEEDED ,
verificationState : PresentableKeyVerificationState.SECURE ,
} )
2025-07-09 17:17:35 +02:00
2025-03-10 16:19:11 +01:00
const sessionKey = neverNull ( await crypto . resolveSessionKey ( testData . mail ) )
2023-12-18 11:36:38 +01:00
o ( sessionKey ) . deepEquals ( testData . sk )
} )
o (
"resolve session key: pq public key decryption of mail session key using BucketKey aggregated type - already decoded/decrypted Mail referencing MailDetailsDraft" ,
async function ( ) {
2023-01-12 16:48:28 +01:00
o . timeout ( 500 ) // in CI or with debugging it can take a while
2023-12-18 11:36:38 +01:00
2025-03-10 16:19:11 +01:00
const testData = await preparePqPubEncBucketKeyResolveSessionKeyTest ( )
2023-12-18 11:36:38 +01:00
2025-07-09 17:17:35 +02:00
when (
asymmetricCryptoFacade . authenticateSender (
{
identifier : senderAddress ,
identifierType : PublicKeyIdentifierType.MAIL_ADDRESS ,
} ,
anything ( ) ,
anything ( ) ,
) ,
2025-11-03 18:01:36 +01:00
) . thenResolve ( {
authStatus : EncryptionAuthStatus.TUTACRYPT_AUTHENTICATION_SUCCEEDED ,
verificationState : PresentableKeyVerificationState.SECURE ,
} )
2025-07-09 17:17:35 +02:00
2023-12-18 11:36:38 +01:00
// do not use testdouble here because it's hard to not break the function itself and then verify invocations
2025-03-10 16:19:11 +01:00
const decryptAndMapToInstance = ( instancePipeline . cryptoMapper . decryptParsedInstance = spy ( instancePipeline . cryptoMapper . decryptParsedInstance ) )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
2025-03-10 16:19:11 +01:00
const sessionKey = neverNull ( await crypto . resolveSessionKey ( testData . mail ) )
o ( decryptAndMapToInstance . invocations . length ) . equals ( 0 )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
2023-01-12 16:48:28 +01:00
o ( sessionKey ) . deepEquals ( testData . sk )
2023-12-18 11:36:38 +01:00
} ,
)
2022-03-09 17:43:29 +01:00
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
o (
2023-12-18 11:36:38 +01:00
"resolve session key: pq public key decryption of session key using BucketKey aggregated type - Mail referencing MailDetailsBlob with attachments" ,
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
async function ( ) {
o . timeout ( 500 ) // in CI or with debugging it can take a while
2023-12-05 14:03:33 +01:00
const file1SessionKey = aes256RandomKey ( )
const file2SessionKey = aes256RandomKey ( )
2023-12-18 11:36:38 +01:00
const testData = await preparePqPubEncBucketKeyResolveSessionKeyTest ( [ file1SessionKey , file2SessionKey ] )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
2025-07-09 17:17:35 +02:00
when (
asymmetricCryptoFacade . authenticateSender (
{
identifier : senderAddress ,
identifierType : PublicKeyIdentifierType.MAIL_ADDRESS ,
} ,
anything ( ) ,
anything ( ) ,
) ,
2025-11-03 18:01:36 +01:00
) . thenResolve ( {
authStatus : EncryptionAuthStatus.TUTACRYPT_AUTHENTICATION_SUCCEEDED ,
verificationState : PresentableKeyVerificationState.SECURE ,
} )
2025-07-09 17:17:35 +02:00
2025-03-10 16:19:11 +01:00
const mailSessionKey = neverNull ( await crypto . resolveSessionKey ( testData . mail ) )
const bucketKey = assertNotNull ( testData . mail . bucketKey )
2023-12-18 11:36:38 +01:00
o ( mailSessionKey ) . deepEquals ( testData . sk )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
2025-03-10 16:19:11 +01:00
o ( bucketKey . bucketEncSessionKeys . length ) . equals ( 3 ) //mail, file1, file2
2023-12-18 11:36:38 +01:00
const updatedInstanceSessionKeysCaptor = captor ( )
2024-06-10 14:05:35 +02:00
verify ( ownerEncSessionKeysUpdateQueue . updateInstanceSessionKeys ( updatedInstanceSessionKeysCaptor . capture ( ) , anything ( ) ) )
2023-12-18 11:36:38 +01:00
const updatedInstanceSessionKeys = updatedInstanceSessionKeysCaptor . value
2025-03-10 16:19:11 +01:00
o ( updatedInstanceSessionKeys . length ) . equals ( bucketKey . bucketEncSessionKeys . length )
for ( const isk of bucketKey . bucketEncSessionKeys ) {
2023-12-05 14:03:33 +01:00
const expectedSessionKey = decryptKey ( testData . bk , isk . symEncSessionKey )
2023-12-18 11:36:38 +01:00
if (
2023-12-05 14:03:33 +01:00
! updatedInstanceSessionKeys . some ( ( updatedKey ) = > {
const updatedSessionKey = decryptKey ( testData . mailGroupKey , updatedKey . symEncSessionKey )
return (
2023-12-18 11:36:38 +01:00
updatedKey . instanceId === isk . instanceId &&
updatedKey . instanceList === isk . instanceList &&
updatedKey . typeInfo . application === isk . typeInfo . application &&
updatedKey . typeInfo . typeId === isk . typeInfo . typeId &&
2023-12-05 14:03:33 +01:00
arrayEquals ( updatedSessionKey , expectedSessionKey )
)
} )
2023-12-18 11:36:38 +01:00
) {
console . log ( "===============================" )
updatedInstanceSessionKeys . some ( ( updatedKey ) = > {
2023-12-05 14:03:33 +01:00
const updatedSessionKey = decryptKey ( testData . mailGroupKey , updatedKey . symEncSessionKey )
2023-12-18 11:36:38 +01:00
console . log ( ">>>>>>>>>>>>>>>>>>>>>>>" )
console . log ( "1 " , updatedKey . instanceId , isk . instanceId )
console . log ( "2 " , updatedKey . instanceList , isk . instanceList )
console . log ( "3 " , updatedKey . typeInfo . application , isk . typeInfo . application )
console . log ( "4 " , updatedKey . typeInfo . typeId , isk . typeInfo . typeId )
2023-12-05 14:03:33 +01:00
console . log ( "5 " , updatedSessionKey , expectedSessionKey )
2023-12-18 11:36:38 +01:00
} )
}
o (
2023-12-05 14:03:33 +01:00
updatedInstanceSessionKeys . some ( ( updatedKey ) = > {
const updatedSessionKey = decryptKey ( testData . mailGroupKey , updatedKey . symEncSessionKey )
return (
2023-12-18 11:36:38 +01:00
updatedKey . instanceId === isk . instanceId &&
updatedKey . instanceList === isk . instanceList &&
updatedKey . typeInfo . application === isk . typeInfo . application &&
updatedKey . typeInfo . typeId === isk . typeInfo . typeId &&
2023-12-05 14:03:33 +01:00
arrayEquals ( updatedSessionKey , expectedSessionKey )
)
} ) ,
2023-12-18 11:36:38 +01:00
) . equals ( true )
}
} ,
)
o (
"resolve session key: external user key decryption of session key using BucketKey aggregated type encrypted with MailGroupKey - Mail referencing MailDetailsBlob with attachments" ,
async function ( ) {
o . timeout ( 500 ) // in CI or with debugging it can take a while
2023-12-05 14:03:33 +01:00
const file1SessionKey = aes256RandomKey ( )
const file2SessionKey = aes256RandomKey ( )
2023-12-18 11:36:38 +01:00
const testData = await prepareConfidentialMailToExternalRecipient ( [ file1SessionKey , file2SessionKey ] )
2025-03-10 16:19:11 +01:00
const mailSessionKey = neverNull ( await crypto . resolveSessionKey ( testData . entityAdapter ) )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
o ( mailSessionKey ) . deepEquals ( testData . sk )
} ,
)
2023-01-26 16:34:37 +01:00
o (
"resolve session key: external user key decryption of session key using BucketKey aggregated type encrypted with UserGroupKey - Mail referencing MailDetailsBlob with attachments" ,
async function ( ) {
o . timeout ( 500 ) // in CI or with debugging it can take a while
2023-12-05 14:03:33 +01:00
const file1SessionKey = aes256RandomKey ( )
const file2SessionKey = aes256RandomKey ( )
2023-12-18 11:36:38 +01:00
const testData = await prepareConfidentialMailToExternalRecipient ( [ file1SessionKey , file2SessionKey ] , true )
2023-01-26 16:34:37 +01:00
2025-03-10 16:19:11 +01:00
const mailSessionKey = neverNull ( await crypto . resolveSessionKey ( testData . entityAdapter ) )
2023-01-26 16:34:37 +01:00
o ( mailSessionKey ) . deepEquals ( testData . sk )
} ,
)
2023-08-08 14:52:14 +02:00
o ( "resolve session key: MailDetailsBlob" , async function ( ) {
2023-12-05 14:03:33 +01:00
const gk = aes256RandomKey ( )
const sk = aes256RandomKey ( )
2024-04-17 10:34:33 +02:00
const ownerGroup = "mailGroupId"
when ( keyLoaderFacade . getCurrentSymGroupKey ( ownerGroup ) ) . thenResolve ( { object : gk , version : 0 } )
when ( userFacade . hasGroup ( ownerGroup ) ) . thenReturn ( true )
2023-08-08 14:52:14 +02:00
when ( userFacade . isFullyLoggedIn ( ) ) . thenReturn ( true )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
2025-03-10 16:19:11 +01:00
const mailDetailsBlob = createTestEntity ( MailDetailsBlobTypeRef , {
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
_id : [ "mailDetailsArchiveId" , "mailDetailsId" ] ,
2024-04-17 10:34:33 +02:00
_ownerGroup : ownerGroup ,
2023-08-08 14:52:14 +02:00
_ownerEncSessionKey : encryptKey ( gk , sk ) ,
2025-03-10 16:19:11 +01:00
} )
2024-04-17 10:34:33 +02:00
when ( keyLoaderFacade . loadSymGroupKey ( ownerGroup , 0 ) ) . thenResolve ( gk )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
2025-03-10 16:19:11 +01:00
const mailDetailsBlobSessionKey = neverNull ( await crypto . resolveSessionKey ( mailDetailsBlob ) )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
o ( mailDetailsBlobSessionKey ) . deepEquals ( sk )
} )
2023-08-08 14:52:14 +02:00
o ( "resolve session key: MailDetailsBlob - session key not found" , async function ( ) {
2025-03-10 16:19:11 +01:00
const mailDetailsBlob = createTestEntity ( MailDetailsBlobTypeRef , {
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
_id : [ "mailDetailsArchiveId" , "mailDetailsId" ] ,
_permissions : "permissionListId" ,
2025-03-10 16:19:11 +01:00
} )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
when ( entityClient . loadAll ( PermissionTypeRef , "permissionListId" ) ) . thenResolve ( [ ] )
try {
2025-03-10 16:19:11 +01:00
await crypto . resolveSessionKey ( mailDetailsBlob )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
o ( true ) . equals ( false ) // let the test fails if there is no exception
} catch ( error ) {
o ( error . constructor ) . equals ( SessionKeyNotFoundError )
}
} )
/ * *
2023-12-18 11:36:38 +01:00
* Prepares the environment to test receiving rsa asymmetric encrypted emails that have been sent with the simplified permission system .
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
* - Creates key pair for the recipient user
* - Creates group , bucket and session keys
* - Creates mail literal and encrypts all encrypted attributes of the mail
* - Create BucketKey object on the mail
*
* @param fileSessionKeys List of session keys for the attachments . When the list is empty there are no attachments
* /
2023-12-05 14:03:33 +01:00
async function prepareRsaPubEncBucketKeyResolveSessionKeyTest ( fileSessionKeys : Array < Aes256Key > = [ ] ) : Promise < {
2025-03-10 16:19:11 +01:00
mail : Mail
2023-12-05 14:03:33 +01:00
sk : Aes256Key
bk : Aes256Key
mailGroupKey : Aes256Key
2025-01-28 18:46:02 +01:00
userGroupId : Id
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
} > {
2023-12-18 11:36:38 +01:00
// configure test user
2024-04-17 10:34:33 +02:00
const recipientUser = createTestUser ( "Bob" , entityClient )
configureLoggedInUser ( recipientUser , userFacade , keyLoaderFacade )
2023-12-18 11:36:38 +01:00
2023-12-18 17:30:21 +01:00
let privateKey = RSA_TEST_KEYPAIR . privateKey
let publicKey = RSA_TEST_KEYPAIR . publicKey
2023-12-18 11:36:38 +01:00
const keyPair = createTestEntity ( KeyPairTypeRef , {
_id : "keyPairId" ,
symEncPrivRsaKey : encryptRsaKey ( recipientUser . userGroupKey , privateKey ) ,
2023-12-18 17:30:21 +01:00
pubRsaKey : hexToUint8Array ( rsaPublicKeyToHex ( publicKey ) ) ,
2023-12-18 11:36:38 +01:00
} )
2024-04-17 10:34:33 +02:00
recipientUser . userGroup . currentKeys = keyPair
2023-12-18 11:36:38 +01:00
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
let bk = aes256RandomKey ( )
2023-12-18 11:36:38 +01:00
2025-03-10 16:19:11 +01:00
const mail = createTestEntity ( MailTypeRef , {
_id : [ "mailListId" , "mailId" ] ,
_permissions : "permissionListId" ,
_ownerGroup : recipientUser.mailGroup._id ,
confidential : true ,
subject : "oh no is this a subject" ,
} )
2023-12-18 11:36:38 +01:00
2024-09-05 13:11:59 +02:00
const pubEncBucketKey = new Uint8Array ( [ 1 , 2 , 3 , 4 ] )
2023-12-18 11:36:38 +01:00
const bucketEncMailSessionKey = encryptKey ( bk , sk )
const mailInstanceSessionKey = createInstanceSessionKey ( {
typeInfo : createTypeInfo ( {
2025-03-10 16:19:11 +01:00
application : MailTypeRef.app ,
typeId : MailTypeRef.typeId.toString ( ) ,
2023-12-18 11:36:38 +01:00
} ) ,
symEncSessionKey : bucketEncMailSessionKey ,
2025-03-10 16:19:11 +01:00
instanceList : listIdPart ( mail . _id ) ,
instanceId : elementIdPart ( mail . _id ) ,
2023-12-18 11:36:38 +01:00
encryptionAuthStatus : null ,
2024-04-17 10:34:33 +02:00
symKeyVersion : "0" ,
2025-07-09 17:17:35 +02:00
keyVerificationState : null ,
2020-04-29 15:55:56 +02:00
} )
2025-05-16 16:03:24 +02:00
const FileTypeModel = await typeModelResolver . resolveClientTypeReference ( FileTypeRef )
2023-12-18 11:36:38 +01:00
const bucketEncSessionKeys = fileSessionKeys . map ( ( fileSessionKey , index ) = > {
return createInstanceSessionKey ( {
typeInfo : createTypeInfo ( {
application : FileTypeModel.app ,
typeId : String ( FileTypeModel . id ) ,
} ) ,
symEncSessionKey : encryptKey ( bk , fileSessionKey ) ,
2024-04-17 10:34:33 +02:00
symKeyVersion : "0" ,
2023-12-18 11:36:38 +01:00
instanceList : "fileListId" ,
instanceId : "fileId" + ( index + 1 ) ,
encryptionAuthStatus : null ,
2025-07-09 17:17:35 +02:00
keyVerificationState : null ,
2023-12-18 11:36:38 +01:00
} )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
} )
2023-12-18 11:36:38 +01:00
bucketEncSessionKeys . push ( mailInstanceSessionKey )
2024-09-05 13:11:59 +02:00
const protocolVersion = CryptoProtocolVersion . RSA
2023-12-18 11:36:38 +01:00
const bucketKey = createBucketKey ( {
2024-09-05 13:11:59 +02:00
pubEncBucketKey ,
2023-12-18 11:36:38 +01:00
keyGroup : recipientUser.userGroup._id ,
bucketEncSessionKeys : bucketEncSessionKeys ,
groupEncBucketKey : null ,
2024-09-05 13:11:59 +02:00
protocolVersion ,
2024-04-17 10:34:33 +02:00
senderKeyVersion : null ,
recipientKeyVersion : "0" ,
2023-12-18 11:36:38 +01:00
} )
2025-01-28 18:46:02 +01:00
when ( keyLoaderFacade . loadCurrentKeyPair ( recipientUser . userGroup . _id ) ) . thenResolve ( {
object : {
keyPairType : KeyPairType.RSA ,
publicKey : RSA_TEST_KEYPAIR.publicKey ,
privateKey : RSA_TEST_KEYPAIR.privateKey ,
} ,
version : 0 ,
} )
2023-12-18 11:36:38 +01:00
2024-09-05 13:11:59 +02:00
when (
asymmetricCryptoFacade . loadKeyPairAndDecryptSymKey (
assertNotNull ( bucketKey . keyGroup ) ,
2025-01-20 13:40:57 +01:00
parseKeyVersion ( bucketKey . recipientKeyVersion ) ,
2024-09-05 13:11:59 +02:00
asCryptoProtoocolVersion ( bucketKey . protocolVersion ) ,
pubEncBucketKey ,
2025-03-28 16:56:47 +01:00
anything ( ) ,
2024-09-05 13:11:59 +02:00
) ,
) . thenResolve ( { decryptedAesKey : bk , senderIdentityPubKey : null } )
2025-03-10 16:19:11 +01:00
mail . bucketKey = bucketKey
2023-12-18 11:36:38 +01:00
return {
2025-03-10 16:19:11 +01:00
mail ,
2023-12-18 11:36:38 +01:00
sk ,
bk ,
mailGroupKey : recipientUser.mailGroupKey ,
2025-01-28 18:46:02 +01:00
userGroupId : recipientUser.userGroup._id ,
2023-12-18 11:36:38 +01:00
}
}
/ * *
* Prepares the environment to test receiving pq asymmetric encrypted emails that have been sent with the simplified permission system .
* - Creates key pair for the recipient user
* - Creates group , bucket and session keys
* - Creates mail literal and encrypts all encrypted attributes of the mail
* - Create BucketKey object on the mail
*
* @param fileSessionKeys List of session keys for the attachments . When the list is empty there are no attachments
* /
async function preparePqPubEncBucketKeyResolveSessionKeyTest (
2024-04-17 10:34:33 +02:00
fileSessionKeys : Array < AesKey > = [ ] ,
2023-12-18 11:36:38 +01:00
confidential : boolean = true ,
) : Promise < {
2025-03-10 16:19:11 +01:00
mail : Mail
2024-04-17 10:34:33 +02:00
sk : AesKey
bk : AesKey
mailGroupKey : AesKey
2025-04-02 13:46:11 +02:00
senderIdentityKeyPair : X25519KeyPair
2023-12-18 11:36:38 +01:00
} > {
// create test user
2024-04-17 10:34:33 +02:00
const recipientUser = createTestUser ( "Bob" , entityClient )
configureLoggedInUser ( recipientUser , userFacade , keyLoaderFacade )
2023-12-18 11:36:38 +01:00
let pqKeyPairs = await pqFacade . generateKeyPairs ( )
const recipientKeyPair = createKeyPair ( {
_id : "keyPairId" ,
2025-04-02 13:46:11 +02:00
pubEccKey : pqKeyPairs.x25519KeyPair.publicKey ,
symEncPrivEccKey : aesEncrypt ( recipientUser . userGroupKey , pqKeyPairs . x25519KeyPair . privateKey ) ,
2023-12-18 11:36:38 +01:00
pubKyberKey : kyberPublicKeyToBytes ( pqKeyPairs . kyberKeyPair . publicKey ) ,
symEncPrivKyberKey : aesEncrypt ( recipientUser . userGroupKey , kyberPrivateKeyToBytes ( pqKeyPairs . kyberKeyPair . privateKey ) ) ,
pubRsaKey : null ,
symEncPrivRsaKey : null ,
2025-06-17 14:14:52 +02:00
signature : null ,
2023-12-18 11:36:38 +01:00
} )
2024-04-17 10:34:33 +02:00
recipientUser . userGroup . currentKeys = recipientKeyPair
2023-12-18 11:36:38 +01:00
2025-04-02 13:46:11 +02:00
const senderIdentityKeyPair = generateX25519KeyPair ( )
2023-12-18 11:36:38 +01:00
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
let bk = aes256RandomKey ( )
2023-12-18 11:36:38 +01:00
2025-03-10 16:19:11 +01:00
const mail = createTestEntity ( MailTypeRef , {
2023-12-18 11:36:38 +01:00
confidential ,
2025-03-10 16:19:11 +01:00
_ownerGroup : recipientUser.mailGroup._id ,
_ownerEncSessionKey : null , // enforce asymmetric crypto to resolve session key
_id : [ "mailListId" , "mailId" ] ,
_permissions : "permissionListId" ,
sender : createTestEntity ( MailAddressTypeRef , {
address : senderAddress ,
name : "sender name" ,
} ) ,
} )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
2024-09-05 13:11:59 +02:00
const pubEncBucketKey = await pqFacade . encapsulateAndEncode (
senderIdentityKeyPair ,
2025-04-02 13:46:11 +02:00
generateX25519KeyPair ( ) ,
2024-09-05 13:11:59 +02:00
pqKeyPairsToPublicKeys ( pqKeyPairs ) ,
bitArrayToUint8Array ( bk ) ,
)
2025-03-10 16:19:11 +01:00
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
const bucketEncMailSessionKey = encryptKey ( bk , sk )
2025-03-10 16:19:11 +01:00
await prepareBucketKeyInstance (
2024-04-17 10:34:33 +02:00
bucketEncMailSessionKey ,
fileSessionKeys ,
bk ,
pubEncBucketKey ,
recipientUser ,
2025-03-10 16:19:11 +01:00
mail ,
2025-02-10 13:15:28 +01:00
undefined ,
"0" ,
CryptoProtocolVersion . TUTA_CRYPT ,
asymmetricCryptoFacade ,
2024-04-17 10:34:33 +02:00
)
2022-03-09 17:43:29 +01:00
2024-09-05 13:11:59 +02:00
when (
asymmetricCryptoFacade . decryptSymKeyWithKeyPair (
{
keyPairType : pqKeyPairs.keyPairType ,
2025-04-02 13:46:11 +02:00
x25519KeyPair : pqKeyPairs.x25519KeyPair ,
2024-09-05 13:11:59 +02:00
kyberKeyPair : pqKeyPairs.kyberKeyPair ,
} ,
CryptoProtocolVersion . TUTA_CRYPT ,
pubEncBucketKey ,
) ,
) . thenResolve ( { decryptedAesKey : bk , senderIdentityPubKey : senderIdentityKeyPair.publicKey } )
when (
asymmetricCryptoFacade . loadKeyPairAndDecryptSymKey (
2025-03-10 16:19:11 +01:00
assertNotNull ( mail . bucketKey ? . keyGroup ) ,
parseKeyVersion ( assertNotNull ( mail . bucketKey ? . recipientKeyVersion ) ) ,
asCryptoProtoocolVersion ( assertNotNull ( mail . bucketKey ? . protocolVersion ) ) ,
2024-09-05 13:11:59 +02:00
pubEncBucketKey ,
2025-03-28 16:56:47 +01:00
anything ( ) ,
2024-09-05 13:11:59 +02:00
) ,
) . thenResolve ( { decryptedAesKey : bk , senderIdentityPubKey : senderIdentityKeyPair.publicKey } )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
return {
2025-03-10 16:19:11 +01:00
mail ,
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
sk ,
bk ,
2023-12-18 11:36:38 +01:00
mailGroupKey : recipientUser.mailGroupKey ,
senderIdentityKeyPair ,
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
}
}
2022-03-09 17:43:29 +01:00
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
/ * *
* Prepares the environment to test receiving symmetric encrypted emails ( mails sent from internal to external user ) that have been sent with the simplified permission system .
* - Creates group , bucket and session keys
* - Creates mail literal and encrypts all encrypted attributes of the mail
* - Create BucketKey object on the mail
*
* @param fileSessionKeys List of session keys for the attachments . When the list is empty there are no attachments
2023-12-18 11:36:38 +01:00
* @param externalUserGroupEncBucketKey for legacy external user group to encrypt bucket key
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
* /
2023-12-18 11:36:38 +01:00
async function prepareConfidentialMailToExternalRecipient (
2024-04-17 10:34:33 +02:00
fileSessionKeys : Array < AesKey > = [ ] ,
2023-01-26 16:34:37 +01:00
externalUserGroupEncBucketKey = false ,
) : Promise < {
2025-03-10 16:19:11 +01:00
entityAdapter : EntityAdapter
2023-12-18 11:36:38 +01:00
bucketKey : BucketKey
2024-04-17 10:34:33 +02:00
sk : AesKey
bk : AesKey
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
MailTypeModel : TypeModel
} > {
2023-12-18 11:36:38 +01:00
// create user
2024-04-17 10:34:33 +02:00
const externalUser = createTestUser ( "Bob" , entityClient )
configureLoggedInUser ( externalUser , userFacade , keyLoaderFacade )
2023-12-18 11:36:38 +01:00
// create test mail
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
let confidential = true
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
let bk = aes256RandomKey ( )
2023-01-26 16:34:37 +01:00
2025-03-10 16:19:11 +01:00
const mailUntypedInstance = await createUntypedMailInstance ( null , sk , confidential , externalUser . mailGroup . _id )
2020-04-29 15:55:56 +02:00
2023-12-18 11:36:38 +01:00
const groupKeyToEncryptBucketKey = externalUserGroupEncBucketKey ? externalUser.userGroupKey : externalUser.mailGroupKey
2023-01-26 16:34:37 +01:00
const groupEncBucketKey = encryptKey ( groupKeyToEncryptBucketKey , bk )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
const bucketEncMailSessionKey = encryptKey ( bk , sk )
2025-05-16 16:03:24 +02:00
const MailTypeModel = await typeModelResolver . resolveServerTypeReference ( MailTypeRef )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
2023-11-10 16:59:39 +01:00
const mailInstanceSessionKey = createTestEntity ( InstanceSessionKeyTypeRef , {
typeInfo : createTestEntity ( TypeInfoTypeRef , {
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
application : MailTypeModel.app ,
typeId : String ( MailTypeModel . id ) ,
} ) ,
symEncSessionKey : bucketEncMailSessionKey ,
instanceList : "mailListId" ,
instanceId : "mailId" ,
} )
2025-05-16 16:03:24 +02:00
const FileTypeModel = await typeModelResolver . resolveServerTypeReference ( FileTypeRef )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
const bucketEncSessionKeys = fileSessionKeys . map ( ( fileSessionKey , index ) = > {
2023-11-10 16:59:39 +01:00
return createTestEntity ( InstanceSessionKeyTypeRef , {
typeInfo : createTestEntity ( TypeInfoTypeRef , {
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
application : FileTypeModel.app ,
typeId : String ( FileTypeModel . id ) ,
2022-03-09 17:43:29 +01:00
} ) ,
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
symEncSessionKey : encryptKey ( bk , fileSessionKey ) ,
instanceList : "fileListId" ,
instanceId : "fileId" + ( index + 1 ) ,
2022-03-09 17:43:29 +01:00
} )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
} )
bucketEncSessionKeys . push ( mailInstanceSessionKey )
2022-03-09 17:43:29 +01:00
2023-11-10 16:59:39 +01:00
const bucketKey = createTestEntity ( BucketKeyTypeRef , {
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
pubEncBucketKey : null ,
2023-12-18 11:36:38 +01:00
keyGroup : externalUserGroupEncBucketKey ? externalUser.userGroup._id : null ,
2023-01-26 16:34:37 +01:00
groupEncBucketKey : groupEncBucketKey ,
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
bucketEncSessionKeys : bucketEncSessionKeys ,
} )
2025-03-10 16:19:11 +01:00
const bucketKeyUntypedInstance : UntypedInstance = await instancePipeline . mapAndEncrypt ( BucketKeyTypeRef , bucketKey , null )
mailUntypedInstance [ assertNotNull ( AttributeModel . getAttributeId ( MailTypeModel , "bucketKey" ) ) ] = [ bucketKeyUntypedInstance ]
const mailEncryptedParsedInstance = await instancePipeline . typeMapper . applyJsTypes ( MailTypeModel , mailUntypedInstance )
2022-03-09 17:43:29 +01:00
2023-12-18 11:36:38 +01:00
return {
2025-03-10 16:19:11 +01:00
entityAdapter : await EntityAdapter . from ( MailTypeModel , mailEncryptedParsedInstance , instancePipeline ) ,
2023-12-18 11:36:38 +01:00
bucketKey ,
sk ,
bk ,
MailTypeModel ,
}
}
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
2023-12-18 11:36:38 +01:00
/ * *
* Prepares the environment to test receiving symmetric encrypted emails from an external sender ( mails sent from external to internal user ) that have been sent with the simplified permission system .
* - Creates group , bucket and session keys
* - Creates mail literal and encrypts all encrypted attributes of the mail
* - Create BucketKey object on the mail
*
* @param fileSessionKeys List of session keys for the attachments . When the list is empty there are no attachments
* /
async function prepareConfidentialReplyFromExternalUser ( ) : Promise < {
2025-03-10 16:19:11 +01:00
entityAdapter : EntityAdapter
2023-12-18 11:36:38 +01:00
bucketKey : BucketKey
2024-04-17 10:34:33 +02:00
sk : AesKey
bk : AesKey
2023-12-18 11:36:38 +01:00
MailTypeModel : TypeModel
internalUser : TestUser
externalUser : TestUser
2025-01-20 13:40:57 +01:00
recipientKeyVersion : KeyVersion
2023-12-18 11:36:38 +01:00
} > {
// Setup test users and groups
2024-04-17 10:34:33 +02:00
const internalUser = createTestUser ( "Alice" , entityClient )
const externalUser = createTestUser ( "Bob" , entityClient )
2023-12-18 11:36:38 +01:00
// Setup relationship between internal and external user
externalUser . userGroup . admin = internalUser . userGroup . _id
externalUser . userGroup . adminGroupEncGKey = encryptKey ( internalUser . userGroupKey , externalUser . userGroupKey )
2024-04-17 10:34:33 +02:00
externalUser . userGroup . adminGroupKeyVersion = "0"
2023-12-18 11:36:38 +01:00
externalUser . mailGroup . admin = externalUser . userGroup . _id
externalUser . mailGroup . adminGroupEncGKey = encryptKey ( externalUser . userGroupKey , externalUser . mailGroupKey )
2024-04-17 10:34:33 +02:00
externalUser . mailGroup . adminGroupKeyVersion = "4"
const recipientKeyVersion = "5"
externalUser . userGroup . groupKeyVersion = "7"
externalUser . mailGroup . groupKeyVersion = "8"
2023-12-18 11:36:38 +01:00
2024-04-17 10:34:33 +02:00
configureLoggedInUser ( internalUser , userFacade , keyLoaderFacade )
2023-12-18 11:36:38 +01:00
2025-01-20 13:40:57 +01:00
when ( keyLoaderFacade . loadSymGroupKey ( externalUser . mailGroup . _id , parseKeyVersion ( recipientKeyVersion ) , anything ( ) ) ) . thenResolve (
externalUser . mailGroupKey ,
)
when ( keyLoaderFacade . loadSymGroupKey ( externalUser . userGroup . _id , parseKeyVersion ( externalUser . mailGroup . adminGroupKeyVersion ) , anything ( ) ) ) . thenResolve (
2024-04-17 10:34:33 +02:00
externalUser . userGroupKey ,
)
// setup test mail (confidential reply from external)
2023-12-18 11:36:38 +01:00
let confidential = true
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
let bk = aes256RandomKey ( )
2025-03-10 16:19:11 +01:00
const untypedMailInstance = await createUntypedMailInstance ( null , sk , confidential , internalUser . mailGroup . _id )
2023-12-18 11:36:38 +01:00
const keyGroup = externalUser . mailGroup . _id
const groupEncBucketKey = encryptKey ( externalUser . mailGroupKey , bk )
const bucketEncMailSessionKey = encryptKey ( bk , sk )
2025-05-16 16:03:24 +02:00
const MailTypeModel = await typeModelResolver . resolveServerTypeReference ( MailTypeRef )
2023-12-18 11:36:38 +01:00
const mailInstanceSessionKey = createTestEntity ( InstanceSessionKeyTypeRef , {
typeInfo : createTestEntity ( TypeInfoTypeRef , {
application : MailTypeModel.app ,
typeId : String ( MailTypeModel . id ) ,
} ) ,
symEncSessionKey : bucketEncMailSessionKey ,
instanceList : "mailListId" ,
instanceId : "mailId" ,
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
} )
2023-12-18 11:36:38 +01:00
const bucketEncSessionKeys = new Array < InstanceSessionKey > ( )
bucketEncSessionKeys . push ( mailInstanceSessionKey )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
2023-12-18 11:36:38 +01:00
const bucketKey = createTestEntity ( BucketKeyTypeRef , {
pubEncBucketKey : null ,
keyGroup : keyGroup ,
groupEncBucketKey : groupEncBucketKey ,
2024-04-17 10:34:33 +02:00
recipientKeyVersion ,
2023-12-18 11:36:38 +01:00
bucketEncSessionKeys : bucketEncSessionKeys ,
2024-04-17 10:34:33 +02:00
protocolVersion : CryptoProtocolVersion.SYMMETRIC_ENCRYPTION ,
senderKeyVersion : null ,
2023-12-18 11:36:38 +01:00
} )
2025-03-10 16:19:11 +01:00
const bucketKeyUntypedInstance : UntypedInstance = await instancePipeline . mapAndEncrypt ( BucketKeyTypeRef , bucketKey , null )
untypedMailInstance [ assertNotNull ( AttributeModel . getAttributeId ( MailTypeModel , "bucketKey" ) ) ] = [ bucketKeyUntypedInstance ]
const encryptedMailParsedInstance = await instancePipeline . typeMapper . applyJsTypes ( MailTypeModel , untypedMailInstance )
const entityAdapter = await EntityAdapter . from ( MailTypeModel , encryptedMailParsedInstance , instancePipeline )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
return {
2025-03-10 16:19:11 +01:00
entityAdapter : entityAdapter ,
2023-12-18 11:36:38 +01:00
bucketKey ,
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
sk ,
bk ,
MailTypeModel ,
2023-12-18 11:36:38 +01:00
internalUser ,
externalUser ,
2025-01-20 13:40:57 +01:00
recipientKeyVersion : parseKeyVersion ( recipientKeyVersion ) ,
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
}
}
2023-12-18 11:36:38 +01:00
2025-03-10 16:19:11 +01:00
async function createUntypedMailInstance (
ownerGroupKey : AesKey | null ,
sessionKey : AesKey ,
confidential : boolean ,
ownerGroupId : string ,
) : Promise < ServerModelUntypedInstance > {
const mail = createMail ( {
_format : "0" ,
_ownerGroup : ownerGroupId ,
_ownerEncSessionKey : ownerGroupKey ? encryptKey ( ownerGroupKey , sessionKey ) : null ,
_permissions : "permissionListId" ,
_id : [ "mailListId" , "mailId" ] ,
receivedDate : new Date ( 1470039025474 ) ,
state : "" ,
unread : true ,
subject : "any subject" ,
replyType : "" ,
confidential : confidential ,
sender : createMailAddress ( {
address : senderAddress ,
name : "any sender" ,
contact : null ,
} ) ,
bucketKey : null ,
2025-10-16 13:16:42 +02:00
authStatus : null ,
2025-03-10 16:19:11 +01:00
listUnsubscribe : false ,
method : "" ,
phishingStatus : "0" ,
recipientCount : "0" ,
differentEnvelopeSender : null ,
movedTime : null ,
encryptionAuthStatus : null ,
_ownerKeyVersion : null ,
attachments : [ ] ,
conversationEntry : [ "entryListId" , "entryId" ] ,
firstRecipient : null ,
mailDetails : null ,
mailDetailsDraft : null ,
sets : [ ] ,
2025-07-09 17:17:35 +02:00
keyVerificationState : null ,
2025-10-14 12:11:22 +02:00
processingState : ProcessingState.INBOX_RULE_APPLIED ,
clientSpamClassifierResult : null ,
2025-11-03 18:01:36 +01:00
processNeeded : false ,
2025-03-10 16:19:11 +01:00
} )
// casting here is fine, since we just want to mimic server response data
return ( await instancePipeline . mapAndEncrypt ( MailTypeRef , mail , sessionKey ) ) as unknown as ServerModelUntypedInstance
2024-04-17 10:34:33 +02:00
}
2025-03-10 16:19:11 +01:00
} )
2023-12-18 11:36:38 +01:00
2024-04-17 10:34:33 +02:00
export function createTestUser ( name : string , entityClient : EntityClient ) : TestUser {
const userGroupKey = aes256RandomKey ( )
const mailGroupKey = aes256RandomKey ( )
2023-12-18 11:36:38 +01:00
2024-04-17 10:34:33 +02:00
const userGroup = createTestEntity ( GroupTypeRef , {
_id : "userGroup" + name ,
type : GroupType . User ,
currentKeys : null ,
groupKeyVersion : "0" ,
} )
2023-12-18 11:36:38 +01:00
2024-04-17 10:34:33 +02:00
const mailGroup = createTestEntity ( GroupTypeRef , {
_id : "mailGroup" + name ,
type : GroupType . Mail ,
currentKeys : null ,
groupKeyVersion : "0" ,
} )
2023-12-18 11:36:38 +01:00
2024-04-17 10:34:33 +02:00
const userGroupMembership = createTestEntity ( GroupMembershipTypeRef , {
group : userGroup._id ,
} )
const mailGroupMembership = createTestEntity ( GroupMembershipTypeRef , {
group : mailGroup._id ,
} )
2023-12-18 11:36:38 +01:00
2024-04-17 10:34:33 +02:00
const user = createTestEntity ( UserTypeRef , {
userGroup : userGroupMembership ,
memberships : [ mailGroupMembership ] ,
} )
2023-12-18 11:36:38 +01:00
2024-04-17 10:34:33 +02:00
when ( entityClient . load ( GroupTypeRef , userGroup . _id ) ) . thenResolve ( userGroup )
when ( entityClient . load ( GroupTypeRef , mailGroup . _id ) ) . thenResolve ( mailGroup )
return {
user ,
userGroup ,
mailGroup ,
userGroupKey ,
mailGroupKey ,
name ,
2023-12-18 11:36:38 +01:00
}
2024-04-17 10:34:33 +02:00
}
/ * *
* Helper function to mock the user facade so that the given test user is considered as logged in user .
* /
export function configureLoggedInUser ( testUser : TestUser , userFacade : UserFacade , keyLoaderFacade : KeyLoaderFacade ) {
when ( userFacade . getLoggedInUser ( ) ) . thenReturn ( testUser . user )
2025-03-13 17:00:34 +01:00
when ( keyLoaderFacade . getCurrentSymGroupKey ( testUser . mailGroup . _id ) ) . thenResolve ( {
object : testUser . mailGroupKey ,
version : 0 ,
} )
when ( keyLoaderFacade . getCurrentSymGroupKey ( testUser . userGroup . _id ) ) . thenResolve ( {
object : testUser . userGroupKey ,
version : 0 ,
} )
2024-04-17 10:34:33 +02:00
when ( userFacade . hasGroup ( testUser . userGroup . _id ) ) . thenReturn ( true )
when ( userFacade . hasGroup ( testUser . mailGroup . _id ) ) . thenReturn ( true )
when ( userFacade . getCurrentUserGroupKey ( ) ) . thenReturn ( { object : testUser . userGroupKey , version : 0 } )
when ( userFacade . isLeader ( ) ) . thenReturn ( true )
when ( userFacade . isFullyLoggedIn ( ) ) . thenReturn ( true )
when ( keyLoaderFacade . loadSymGroupKey ( testUser . mailGroup . _id , 0 ) ) . thenResolve ( testUser . mailGroupKey )
when ( keyLoaderFacade . loadSymGroupKey ( testUser . userGroup . _id , 0 ) ) . thenResolve ( testUser . userGroupKey )
}