2023-06-29 18:26:45 +02:00
import o from "@tutao/otest"
2019-08-21 15:12:04 +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
arrayEquals ,
2019-08-21 15:12:04 +02:00
base64ToUint8Array ,
hexToUint8Array ,
2021-11-23 16:09:12 +01:00
isSameTypeRef ,
neverNull ,
2019-08-21 15:12:04 +02:00
stringToUtf8Uint8Array ,
uint8ArrayToBase64 ,
2022-01-07 15:58:30 +01:00
utf8Uint8ArrayToString ,
2021-11-04 14:05:23 +01:00
} from "@tutao/tutanota-utils"
2023-01-12 16:48:28 +01:00
import { CryptoFacade } from "../../../../../src/api/worker/crypto/CryptoFacade.js"
import { ProgrammingError } from "../../../../../src/api/common/error/ProgrammingError.js"
import { Cardinality , ValueType } from "../../../../../src/api/common/EntityConstants.js"
2023-12-18 11:36:38 +01:00
import { BucketPermissionType , EncryptionAuthStatus , GroupType , PermissionType } from "../../../../../src/api/common/TutanotaConstants.js"
2022-04-19 16:51:08 +02:00
import {
2023-11-10 16:59:39 +01:00
BirthdayTypeRef ,
2023-11-09 17:04:42 +01:00
ContactAddressTypeRef ,
2022-04-19 16:51:08 +02:00
ContactTypeRef ,
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 ,
2022-04-19 16:51:08 +02: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 ,
2022-05-12 16:51:15 +02:00
} from "../../../../../src/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 ,
createPublicKeyGetIn ,
createPublicKeyGetOut ,
createTypeInfo ,
Group ,
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 ,
KeyPairTypeRef ,
2022-04-19 16:51:08 +02:00
PermissionTypeRef ,
2023-12-18 11:36:38 +01:00
PublicKeyGetIn ,
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 ,
2024-01-30 18:18:19 +01:00
UserReturn ,
UserReturnTypeRef ,
2023-11-10 16:59:39 +01:00
UserTypeRef ,
2022-05-12 16:51:15 +02:00
} from "../../../../../src/api/entities/sys/TypeRefs.js"
2023-06-29 18:26:45 +02:00
import { assertThrows , spy } from "@tutao/tutanota-test-utils"
2023-01-12 16:48:28 +01:00
import { RestClient } from "../../../../../src/api/worker/rest/RestClient.js"
import { EntityClient } from "../../../../../src/api/common/EntityClient.js"
2022-01-07 15:58:30 +01:00
import {
2023-12-18 11:36:38 +01:00
Aes128Key ,
Aes256Key ,
aes256RandomKey ,
2023-09-26 18:03:30 +02:00
aesDecrypt ,
2023-09-13 11:42:57 +02:00
aesEncrypt ,
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 ,
2023-12-18 11:36:38 +01:00
EccKeyPair ,
2022-01-07 15:58:30 +01:00
ENABLE_MAC ,
encryptKey ,
encryptRsaKey ,
2023-12-18 11:36:38 +01:00
generateEccKeyPair ,
2022-01-07 15:58:30 +01:00
IV_BYTE_LENGTH ,
2023-12-18 11:36:38 +01:00
kyberPrivateKeyToBytes ,
kyberPublicKeyToBytes ,
2024-01-30 18:18:19 +01:00
pqKeyPairsToPublicKeys ,
2022-12-27 15:37:40 +01:00
random ,
2023-12-18 11:36:38 +01:00
rsaPrivateKeyToHex ,
rsaPublicKeyToHex ,
2022-01-07 15:58:30 +01:00
} from "@tutao/tutanota-crypto"
2023-01-12 16:48:28 +01:00
import { RsaWeb } from "../../../../../src/api/worker/crypto/RsaImplementation.js"
import { decryptValue , encryptValue , InstanceMapper } from "../../../../../src/api/worker/crypto/InstanceMapper.js"
import type { ModelValue , TypeModel } from "../../../../../src/api/common/EntityTypes.js"
import { IServiceExecutor } from "../../../../../src/api/common/ServiceRequest.js"
2023-12-18 11:36:38 +01:00
import { instance , matchers , object , verify , when } from "testdouble"
import { PublicKeyService , UpdatePermissionKeyService } from "../../../../../src/api/entities/sys/Services.js"
2023-01-12 16:48:28 +01:00
import { getListId , isSameId } from "../../../../../src/api/common/utils/EntityUtils.js"
2023-12-18 11:36:38 +01:00
import { HttpMethod , resolveTypeReference , typeModels } from "../../../../../src/api/common/EntityFunctions.js"
2023-01-12 16:48:28 +01:00
import { UserFacade } from "../../../../../src/api/worker/facades/UserFacade.js"
import { SessionKeyNotFoundError } from "../../../../../src/api/common/error/SessionKeyNotFoundError.js"
import { OwnerEncSessionKeysUpdateQueue } from "../../../../../src/api/worker/crypto/OwnerEncSessionKeysUpdateQueue.js"
2023-12-18 11:36:38 +01:00
import { WASMKyberFacade } from "../../../../../src/api/worker/facades/KyberFacade.js"
import { PQFacade } from "../../../../../src/api/worker/facades/PQFacade.js"
import { encodePQMessage , PQBucketKeyEncapsulation , PQMessage } from "../../../../../src/api/worker/facades/PQMessage.js"
import { loadLibOQSWASM } from "../WASMTestUtils.js"
2023-11-09 17:04:42 +01:00
import { createTestEntity } from "../../../TestUtils.js"
2023-12-18 17:30:21 +01:00
import { RSA_TEST_KEYPAIR } from "../facades/RsaPqPerformanceTest.js"
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
2021-11-23 16:09:12 +01:00
const rsa = new RsaWeb ( )
const rsaEncrypt = rsa . encrypt
2023-12-18 11:36:38 +01:00
const kyberFacade = new WASMKyberFacade ( await loadLibOQSWASM ( ) )
const pqFacade : PQFacade = new PQFacade ( kyberFacade )
/ * *
* Helper to have all the mocked items available in the test case .
* /
type TestUser = {
user : User
name : string
userGroup : Group
mailGroup : Group
userGroupKey : Aes128Key
mailGroupKey : Aes128Key
}
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
2021-12-15 16:07:07 +01:00
let instanceMapper = new InstanceMapper ( )
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
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 ( )
2017-11-23 13:30:17 +01:00
} )
2022-03-09 17:43:29 +01:00
o . beforeEach ( function ( ) {
serviceExecutor = object ( )
entityClient = 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 ( )
2023-12-18 11:36:38 +01:00
crypto = new CryptoFacade ( userFacade , entityClient , restClient , rsa , serviceExecutor , instanceMapper , ownerEncSessionKeysUpdateQueue , pqFacade )
2022-03-09 17:43:29 +01:00
} )
2023-01-12 16:48:28 +01:00
function createValueType ( type , encrypted , cardinality ) : ModelValue & { name : string ; since : number } {
2017-08-15 13:54:22 +02:00
return {
2022-01-07 15:58:30 +01:00
name : "test" ,
id : 426 ,
since : 6 ,
type : type ,
cardinality : cardinality ,
final : true ,
encrypted : encrypted ,
2022-01-13 13:24:37 +01:00
}
2017-08-15 13:54:22 +02:00
}
o . spec ( "decrypt value" , function ( ) {
2020-11-04 15:52:09 +01:00
o ( "decrypt string / number value without mac" , function ( ) {
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
2017-09-25 16:22:38 +02:00
let value = "this is a string value"
2023-12-05 14:03:33 +01:00
let encryptedValue = uint8ArrayToBase64 ( aesEncrypt ( sk , stringToUtf8Uint8Array ( value ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , true ) )
2022-12-27 15:37:40 +01:00
o ( decryptValue ( "test" , createValueType ( ValueType . String , true , Cardinality . One ) , encryptedValue , sk ) ) . equals ( value )
2017-09-25 16:22:38 +02:00
value = "516546"
2023-12-05 14:03:33 +01:00
encryptedValue = uint8ArrayToBase64 ( aesEncrypt ( sk , stringToUtf8Uint8Array ( value ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , true ) )
2022-12-27 15:37:40 +01:00
o ( decryptValue ( "test" , createValueType ( ValueType . String , true , Cardinality . One ) , encryptedValue , sk ) ) . equals ( value )
2017-09-25 16:22:38 +02:00
} )
2020-11-04 15:52:09 +01:00
o ( "decrypt string / number value with mac" , function ( ) {
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
2017-08-15 13:54:22 +02:00
let value = "this is a string value"
2023-09-13 11:42:57 +02:00
let encryptedValue = uint8ArrayToBase64 ( aesEncrypt ( sk , stringToUtf8Uint8Array ( value ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , true ) )
2022-12-27 15:37:40 +01:00
o ( decryptValue ( "test" , createValueType ( ValueType . String , true , Cardinality . One ) , encryptedValue , sk ) ) . equals ( value )
2017-08-15 13:54:22 +02:00
value = "516546"
2023-09-13 11:42:57 +02:00
encryptedValue = uint8ArrayToBase64 ( aesEncrypt ( sk , stringToUtf8Uint8Array ( value ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , true ) )
2022-12-27 15:37:40 +01:00
o ( decryptValue ( "test" , createValueType ( ValueType . String , true , Cardinality . One ) , encryptedValue , sk ) ) . equals ( value )
2017-08-15 13:54:22 +02:00
} )
2020-11-04 15:52:09 +01:00
o ( "decrypt boolean value without mac" , function ( ) {
2017-08-15 13:54:22 +02:00
let valueType : ModelValue = createValueType ( ValueType . Boolean , true , Cardinality . One )
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
2017-08-15 13:54:22 +02:00
let value = "0"
2023-12-05 14:03:33 +01:00
let encryptedValue = uint8ArrayToBase64 ( aesEncrypt ( sk , stringToUtf8Uint8Array ( value ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , true ) )
2019-09-13 13:49:11 +02:00
o ( decryptValue ( "test" , valueType , encryptedValue , sk ) ) . equals ( false )
2017-08-15 13:54:22 +02:00
value = "1"
2023-12-05 14:03:33 +01:00
encryptedValue = uint8ArrayToBase64 ( aesEncrypt ( sk , stringToUtf8Uint8Array ( value ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , true ) )
2019-09-13 13:49:11 +02:00
o ( decryptValue ( "test" , valueType , encryptedValue , sk ) ) . equals ( true )
2017-08-15 13:54:22 +02:00
value = "32498"
2023-12-05 14:03:33 +01:00
encryptedValue = uint8ArrayToBase64 ( aesEncrypt ( sk , stringToUtf8Uint8Array ( value ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , true ) )
2019-09-13 13:49:11 +02:00
o ( decryptValue ( "test" , valueType , encryptedValue , sk ) ) . equals ( true )
2017-08-15 13:54:22 +02:00
} )
2020-11-04 15:52:09 +01:00
o ( "decrypt boolean value with mac" , function ( ) {
2017-09-25 16:22:38 +02:00
let valueType : ModelValue = createValueType ( ValueType . Boolean , true , Cardinality . One )
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
2017-09-25 16:22:38 +02:00
let value = "0"
2023-09-13 11:42:57 +02:00
let encryptedValue = uint8ArrayToBase64 ( aesEncrypt ( sk , stringToUtf8Uint8Array ( value ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , true ) )
2019-09-13 13:49:11 +02:00
o ( decryptValue ( "test" , valueType , encryptedValue , sk ) ) . equals ( false )
2017-09-25 16:22:38 +02:00
value = "1"
2023-09-13 11:42:57 +02:00
encryptedValue = uint8ArrayToBase64 ( aesEncrypt ( sk , stringToUtf8Uint8Array ( value ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , true ) )
2019-09-13 13:49:11 +02:00
o ( decryptValue ( "test" , valueType , encryptedValue , sk ) ) . equals ( true )
2017-09-25 16:22:38 +02:00
value = "32498"
2023-09-13 11:42:57 +02:00
encryptedValue = uint8ArrayToBase64 ( aesEncrypt ( sk , stringToUtf8Uint8Array ( value ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , true ) )
2019-09-13 13:49:11 +02:00
o ( decryptValue ( "test" , valueType , encryptedValue , sk ) ) . equals ( true )
2017-09-25 16:22:38 +02:00
} )
2020-11-04 15:52:09 +01:00
o ( "decrypt date value without mac" , function ( ) {
2017-09-25 16:22:38 +02:00
let valueType : ModelValue = createValueType ( ValueType . Date , true , Cardinality . One )
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
2017-09-25 16:22:38 +02:00
let value = new Date ( ) . getTime ( ) . toString ( )
2023-12-05 14:03:33 +01:00
let encryptedValue = uint8ArrayToBase64 ( aesEncrypt ( sk , stringToUtf8Uint8Array ( value ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , true ) )
2019-09-13 13:49:11 +02:00
o ( decryptValue ( "test" , valueType , encryptedValue , sk ) ) . deepEquals ( new Date ( parseInt ( value ) ) )
2017-09-25 16:22:38 +02:00
} )
2020-11-04 15:52:09 +01:00
o ( "decrypt date value with mac" , function ( ) {
2017-08-15 13:54:22 +02:00
let valueType : ModelValue = createValueType ( ValueType . Date , true , Cardinality . One )
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
2017-08-15 13:54:22 +02:00
let value = new Date ( ) . getTime ( ) . toString ( )
2023-09-13 11:42:57 +02:00
let encryptedValue = uint8ArrayToBase64 ( aesEncrypt ( sk , stringToUtf8Uint8Array ( value ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , true ) )
2019-09-13 13:49:11 +02:00
o ( decryptValue ( "test" , valueType , encryptedValue , sk ) ) . deepEquals ( new Date ( parseInt ( value ) ) )
2017-08-15 13:54:22 +02:00
} )
2020-11-04 15:52:09 +01:00
o ( "decrypt bytes value without mac" , function ( ) {
2017-09-25 16:22:38 +02:00
let valueType : ModelValue = createValueType ( ValueType . Bytes , true , Cardinality . One )
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
2017-09-25 16:22:38 +02:00
let value = random . generateRandomData ( 5 )
2023-12-05 14:03:33 +01:00
let encryptedValue = uint8ArrayToBase64 ( aesEncrypt ( sk , value , random . generateRandomData ( IV_BYTE_LENGTH ) , true , true ) )
2019-09-13 13:49:11 +02:00
let decryptedValue = decryptValue ( "test" , valueType , encryptedValue , sk )
2017-09-25 16:22:38 +02:00
o ( decryptedValue instanceof Uint8Array ) . equals ( true )
o ( Array . from ( decryptedValue ) ) . deepEquals ( Array . from ( value ) )
} )
2020-11-04 15:52:09 +01:00
o ( "decrypt bytes value with mac" , function ( ) {
2017-08-15 13:54:22 +02:00
let valueType : ModelValue = createValueType ( ValueType . Bytes , true , Cardinality . One )
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
2017-08-15 13:54:22 +02:00
let value = random . generateRandomData ( 5 )
2023-09-13 11:42:57 +02:00
let encryptedValue = uint8ArrayToBase64 ( aesEncrypt ( sk , value , random . generateRandomData ( IV_BYTE_LENGTH ) , true , true ) )
2019-09-13 13:49:11 +02:00
let decryptedValue = decryptValue ( "test" , valueType , encryptedValue , sk )
2017-08-15 13:54:22 +02:00
o ( decryptedValue instanceof Uint8Array ) . equals ( true )
o ( Array . from ( decryptedValue ) ) . deepEquals ( Array . from ( value ) )
} )
2020-11-04 15:52:09 +01:00
o ( "decrypt compressedString" , function ( ) {
2019-08-21 15:12:04 +02:00
let valueType : ModelValue = createValueType ( ValueType . CompressedString , true , Cardinality . One )
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
2019-09-03 15:09:55 +02:00
let value = base64ToUint8Array ( "QHRlc3Q=" )
2023-09-13 11:42:57 +02:00
let encryptedValue = uint8ArrayToBase64 ( aesEncrypt ( sk , value , random . generateRandomData ( IV_BYTE_LENGTH ) , true , true ) )
2019-09-13 13:49:11 +02:00
let decryptedValue = decryptValue ( "test" , valueType , encryptedValue , sk )
2019-08-21 15:12:04 +02:00
o ( typeof decryptedValue === "string" ) . equals ( true )
o ( decryptedValue ) . equals ( "test" )
} )
2019-09-03 15:09:55 +02:00
o ( "decrypt compressedString w resize" , function ( ) {
let valueType : ModelValue = createValueType ( ValueType . CompressedString , true , Cardinality . One )
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
2019-09-03 15:09:55 +02:00
let value = base64ToUint8Array ( "X3RleHQgBQD//1FQdGV4dCA=" )
2023-09-13 11:42:57 +02:00
let encryptedValue = uint8ArrayToBase64 ( aesEncrypt ( sk , value , random . generateRandomData ( IV_BYTE_LENGTH ) , true , true ) )
2019-09-13 13:49:11 +02:00
let decryptedValue = decryptValue ( "test" , valueType , encryptedValue , sk )
2019-09-03 15:09:55 +02:00
o ( typeof decryptedValue === "string" ) . equals ( true )
2022-01-07 15:58:30 +01:00
o ( decryptedValue ) . equals (
"text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text " ,
)
2019-09-03 15:09:55 +02:00
} )
2020-11-04 15:52:09 +01:00
o ( "decrypt empty compressedString" , function ( ) {
2019-08-21 15:12:04 +02:00
let valueType : ModelValue = createValueType ( ValueType . CompressedString , true , Cardinality . One )
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
2023-09-13 11:42:57 +02:00
let encryptedValue = uint8ArrayToBase64 ( aesEncrypt ( sk , new Uint8Array ( [ ] ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , true ) )
2019-09-13 13:49:11 +02:00
let decryptedValue = decryptValue ( "test" , valueType , encryptedValue , sk )
2019-08-21 15:12:04 +02:00
o ( typeof decryptedValue === "string" ) . equals ( true )
o ( decryptedValue ) . equals ( "" )
} )
2020-11-04 15:52:09 +01:00
o ( "do not decrypt null values" , function ( ) {
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
2022-12-27 15:37:40 +01:00
o ( decryptValue ( "test" , createValueType ( ValueType . String , true , Cardinality . ZeroOrOne ) , null , sk ) ) . equals ( null )
2019-09-13 13:49:11 +02:00
o ( decryptValue ( "test" , createValueType ( ValueType . Date , true , Cardinality . ZeroOrOne ) , null , sk ) ) . equals ( null )
2022-12-27 15:37:40 +01:00
o ( decryptValue ( "test" , createValueType ( ValueType . Bytes , true , Cardinality . ZeroOrOne ) , null , sk ) ) . equals ( null )
o ( decryptValue ( "test" , createValueType ( ValueType . Boolean , true , Cardinality . ZeroOrOne ) , null , sk ) ) . equals ( null )
o ( decryptValue ( "test" , createValueType ( ValueType . Number , true , Cardinality . ZeroOrOne ) , null , sk ) ) . equals ( null )
2022-01-07 15:58:30 +01:00
} )
o ( "throw error on ONE null values (String)" , makeTestForErrorOnNull ( ValueType . String ) )
o ( "throw error on ONE null values (Date)" , makeTestForErrorOnNull ( ValueType . Date ) )
o ( "throw error on ONE null values (Bytes)" , makeTestForErrorOnNull ( ValueType . Bytes ) )
o ( "throw error on ONE null values (Boolean)" , makeTestForErrorOnNull ( ValueType . Boolean ) )
o ( "throw error on ONE null values (Number)" , makeTestForErrorOnNull ( ValueType . Number ) )
function makeTestForErrorOnNull ( type ) {
return async ( ) = > {
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
2022-01-07 15:58:30 +01:00
const e = await assertThrows ( ProgrammingError , ( ) = > decryptValue ( "test" , createValueType ( type , true , Cardinality . One ) , null , sk ) )
o ( e . message ) . equals ( "Value test with cardinality ONE can not be null" )
2017-08-15 13:54:22 +02:00
}
}
o ( "convert unencrypted Date to JS type" , function ( ) {
let value = new Date ( ) . getTime ( ) . toString ( )
2022-12-27 15:37:40 +01:00
o ( decryptValue ( "test" , createValueType ( ValueType . Date , false , Cardinality . One ) , value , null ) ) . deepEquals ( new Date ( parseInt ( value ) ) )
2017-08-15 13:54:22 +02:00
} )
o ( "convert unencrypted Bytes to JS type" , function ( ) {
let valueBytes = random . generateRandomData ( 15 )
let value = uint8ArrayToBase64 ( valueBytes )
2022-12-27 15:37:40 +01:00
o ( Array . from ( decryptValue ( "test" , createValueType ( ValueType . Bytes , false , Cardinality . One ) , value , null ) ) ) . deepEquals ( Array . from ( valueBytes ) )
2017-08-15 13:54:22 +02:00
} )
o ( "convert unencrypted Boolean to JS type" , function ( ) {
let value = "0"
2022-12-27 15:37:40 +01:00
o ( decryptValue ( "test" , createValueType ( ValueType . Boolean , false , Cardinality . One ) , value , null ) ) . equals ( false )
2017-08-15 13:54:22 +02:00
value = "1"
2022-12-27 15:37:40 +01:00
o ( decryptValue ( "test" , createValueType ( ValueType . Boolean , false , Cardinality . One ) , value , null ) ) . equals ( true )
2017-08-15 13:54:22 +02:00
} )
o ( "convert unencrypted Number to JS type" , function ( ) {
let value = ""
2019-09-13 13:49:11 +02:00
o ( decryptValue ( "test" , createValueType ( ValueType . Number , false , Cardinality . One ) , value , null ) ) . equals ( "0" )
2017-08-15 13:54:22 +02:00
value = "0"
2019-09-13 13:49:11 +02:00
o ( decryptValue ( "test" , createValueType ( ValueType . Number , false , Cardinality . One ) , value , null ) ) . equals ( "0" )
2017-08-15 13:54:22 +02:00
value = "1"
2019-09-13 13:49:11 +02:00
o ( decryptValue ( "test" , createValueType ( ValueType . Number , false , Cardinality . One ) , value , null ) ) . equals ( "1" )
2017-08-15 13:54:22 +02:00
} )
2019-08-21 15:12:04 +02:00
o ( "convert unencrypted compressedString to JS type" , function ( ) {
let value = ""
2022-12-27 15:37:40 +01:00
o ( decryptValue ( "test" , createValueType ( ValueType . CompressedString , false , Cardinality . One ) , value , null ) ) . equals ( "" )
2019-09-03 15:09:55 +02:00
value = "QHRlc3Q="
2022-12-27 15:37:40 +01:00
o ( decryptValue ( "test" , createValueType ( ValueType . CompressedString , false , Cardinality . One ) , value , null ) ) . equals ( "test" )
2019-08-21 15:12:04 +02:00
} )
2017-08-15 13:54:22 +02:00
} )
o . spec ( "encryptValue" , function ( ) {
2020-11-04 15:52:09 +01:00
o ( "encrypt string / number value" , function ( ) {
2022-04-12 14:23:38 +02:00
const valueType = createValueType ( ValueType . String , true , Cardinality . One )
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
2017-08-15 13:54:22 +02:00
let value = "this is a string value"
2021-07-09 14:38:10 +02:00
let encryptedValue = neverNull ( encryptValue ( "test" , valueType , value , sk ) )
2022-01-07 15:58:30 +01:00
let expected = uint8ArrayToBase64 (
2023-09-13 11:42:57 +02:00
aesEncrypt (
2022-01-07 15:58:30 +01:00
sk ,
stringToUtf8Uint8Array ( value ) ,
base64ToUint8Array ( encryptedValue ) . slice ( ENABLE_MAC ? 1 : 0 , ENABLE_MAC ? 17 : 16 ) ,
true ,
ENABLE_MAC ,
) ,
)
o ( encryptedValue ) . equals ( expected )
2019-09-13 13:49:11 +02:00
o ( decryptValue ( "test" , valueType , encryptedValue , sk ) ) . equals ( value )
2017-08-15 13:54:22 +02:00
} )
2020-11-04 15:52:09 +01:00
o ( "encrypt boolean value" , function ( ) {
2017-08-15 13:54:22 +02:00
let valueType : ModelValue = createValueType ( ValueType . Boolean , true , Cardinality . One )
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
2017-08-15 13:54:22 +02:00
let value = false
2021-07-09 14:38:10 +02:00
let encryptedValue = neverNull ( encryptValue ( "test" , valueType , value , sk ) )
2022-01-07 15:58:30 +01:00
let expected = uint8ArrayToBase64 (
2023-09-13 11:42:57 +02:00
aesEncrypt (
2022-01-07 15:58:30 +01:00
sk ,
stringToUtf8Uint8Array ( value ? "1" : "0" ) ,
base64ToUint8Array ( encryptedValue ) . slice ( ENABLE_MAC ? 1 : 0 , ENABLE_MAC ? 17 : 16 ) ,
true ,
ENABLE_MAC ,
) ,
)
2017-08-15 13:54:22 +02:00
o ( encryptedValue ) . equals ( expected )
2019-09-13 13:49:11 +02:00
o ( decryptValue ( "test" , valueType , encryptedValue , sk ) ) . equals ( false )
2017-08-15 13:54:22 +02:00
value = true
2021-07-09 14:38:10 +02:00
encryptedValue = neverNull ( encryptValue ( "test" , valueType , value , sk ) )
2022-01-07 15:58:30 +01:00
expected = uint8ArrayToBase64 (
2023-09-13 11:42:57 +02:00
aesEncrypt (
2022-01-07 15:58:30 +01:00
sk ,
stringToUtf8Uint8Array ( value ? "1" : "0" ) ,
base64ToUint8Array ( encryptedValue ) . slice ( ENABLE_MAC ? 1 : 0 , ENABLE_MAC ? 17 : 16 ) ,
true ,
ENABLE_MAC ,
) ,
)
2017-08-15 13:54:22 +02:00
o ( encryptedValue ) . equals ( expected )
2019-09-13 13:49:11 +02:00
o ( decryptValue ( "test" , valueType , encryptedValue , sk ) ) . equals ( true )
2017-08-15 13:54:22 +02:00
} )
2020-11-04 15:52:09 +01:00
o ( "encrypt date value" , function ( ) {
2017-08-15 13:54:22 +02:00
let valueType : ModelValue = createValueType ( ValueType . Date , true , Cardinality . One )
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
2017-08-15 13:54:22 +02:00
let value = new Date ( )
2021-07-09 14:38:10 +02:00
let encryptedValue = neverNull ( encryptValue ( "test" , valueType , value , sk ) )
2022-01-07 15:58:30 +01:00
let expected = uint8ArrayToBase64 (
2023-09-13 11:42:57 +02:00
aesEncrypt (
2022-01-07 15:58:30 +01:00
sk ,
stringToUtf8Uint8Array ( value . getTime ( ) . toString ( ) ) ,
base64ToUint8Array ( encryptedValue ) . slice ( ENABLE_MAC ? 1 : 0 , ENABLE_MAC ? 17 : 16 ) ,
true ,
ENABLE_MAC ,
) ,
)
2022-04-12 14:23:38 +02:00
o ( encryptedValue ) . equals ( expected )
2019-09-13 13:49:11 +02:00
o ( decryptValue ( "test" , valueType , encryptedValue , sk ) ) . deepEquals ( value )
2017-08-15 13:54:22 +02:00
} )
2020-11-04 15:52:09 +01:00
o ( "encrypt bytes value" , function ( ) {
2017-08-15 13:54:22 +02:00
let valueType : ModelValue = createValueType ( ValueType . Bytes , true , Cardinality . One )
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
2017-08-15 13:54:22 +02:00
let value = random . generateRandomData ( 5 )
2021-07-09 14:38:10 +02:00
let encryptedValue = neverNull ( encryptValue ( "test" , valueType , value , sk ) )
2022-01-07 15:58:30 +01:00
let expected = uint8ArrayToBase64 (
2023-09-13 11:42:57 +02:00
aesEncrypt ( sk , value , base64ToUint8Array ( encryptedValue ) . slice ( ENABLE_MAC ? 1 : 0 , ENABLE_MAC ? 17 : 16 ) , true , ENABLE_MAC ) ,
2022-01-07 15:58:30 +01:00
)
2017-08-15 13:54:22 +02:00
o ( encryptedValue ) . equals ( expected )
2019-09-13 13:49:11 +02:00
o ( Array . from ( decryptValue ( "test" , valueType , encryptedValue , sk ) ) ) . deepEquals ( Array . from ( value ) )
2017-08-15 13:54:22 +02:00
} )
2020-11-04 15:52:09 +01:00
o ( "do not encrypt null values" , function ( ) {
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
2022-12-27 15:37:40 +01:00
o ( encryptValue ( "test" , createValueType ( ValueType . String , true , Cardinality . ZeroOrOne ) , null , sk ) ) . equals ( null )
2019-09-13 13:49:11 +02:00
o ( encryptValue ( "test" , createValueType ( ValueType . Date , true , Cardinality . ZeroOrOne ) , null , sk ) ) . equals ( null )
2022-12-27 15:37:40 +01:00
o ( encryptValue ( "test" , createValueType ( ValueType . Bytes , true , Cardinality . ZeroOrOne ) , null , sk ) ) . equals ( null )
o ( encryptValue ( "test" , createValueType ( ValueType . Boolean , true , Cardinality . ZeroOrOne ) , null , sk ) ) . equals ( null )
o ( encryptValue ( "test" , createValueType ( ValueType . Number , true , Cardinality . ZeroOrOne ) , null , sk ) ) . equals ( null )
2017-08-15 13:54:22 +02:00
} )
2020-11-04 15:52:09 +01:00
o ( "accept null _id and _permissions value during encryption" , function ( ) {
2022-05-27 16:06:11 +02:00
let vt : ModelValue = {
2022-01-07 15:58:30 +01:00
id : 426 ,
type : ValueType . GeneratedId ,
cardinality : Cardinality.One ,
final : true ,
encrypted : false ,
2017-08-15 13:54:22 +02:00
}
2022-05-27 16:06:11 +02:00
o ( encryptValue ( "_id" , vt , null , null ) ) . equals ( null )
o ( encryptValue ( "_permissions" , vt , null , null ) ) . equals ( null )
2017-08-15 13:54:22 +02:00
} )
2022-01-07 15:58:30 +01:00
o ( "throw error on ONE null values (enc String)" , makeTestForErrorOnNull ( ValueType . String ) )
o ( "throw error on ONE null values (enc Date)" , makeTestForErrorOnNull ( ValueType . Date ) )
o ( "throw error on ONE null values (enc Bytes)" , makeTestForErrorOnNull ( ValueType . Bytes ) )
o ( "throw error on ONE null values (enc Boolean)" , makeTestForErrorOnNull ( ValueType . Boolean ) )
o ( "throw error on ONE null values (enc Number)" , makeTestForErrorOnNull ( ValueType . Number ) )
2017-08-15 13:54:22 +02:00
2022-01-07 15:58:30 +01:00
function makeTestForErrorOnNull ( type ) {
return async ( ) = > {
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
2022-01-07 15:58:30 +01:00
const e = await assertThrows ( ProgrammingError , async ( ) = > encryptValue ( "test" , createValueType ( type , true , Cardinality . One ) , null , sk ) )
o ( e . message ) . equals ( "Value test with cardinality ONE can not be null" )
2017-08-15 13:54:22 +02:00
}
}
o ( "convert unencrypted Date to DB type" , function ( ) {
let value = new Date ( )
2022-12-27 15:37:40 +01:00
o ( encryptValue ( "test" , createValueType ( ValueType . Date , false , Cardinality . One ) , value , null ) ) . equals ( value . getTime ( ) . toString ( ) )
2017-08-15 13:54:22 +02:00
} )
o ( "convert unencrypted Bytes to DB type" , function ( ) {
let valueBytes = random . generateRandomData ( 15 )
2022-12-27 15:37:40 +01:00
o ( encryptValue ( "test" , createValueType ( ValueType . Bytes , false , Cardinality . One ) , valueBytes , null ) ) . equals ( uint8ArrayToBase64 ( valueBytes ) )
2017-08-15 13:54:22 +02:00
} )
o ( "convert unencrypted Boolean to DB type" , function ( ) {
let value = false
2019-09-13 13:49:11 +02:00
o ( encryptValue ( "test" , createValueType ( ValueType . Boolean , false , Cardinality . One ) , value , null ) ) . equals ( "0" )
2017-08-15 13:54:22 +02:00
value = true
2019-09-13 13:49:11 +02:00
o ( encryptValue ( "test" , createValueType ( ValueType . Boolean , false , Cardinality . One ) , value , null ) ) . equals ( "1" )
2017-08-15 13:54:22 +02:00
} )
o ( "convert unencrypted Number to DB type" , function ( ) {
let value = "0"
2019-09-13 13:49:11 +02:00
o ( encryptValue ( "test" , createValueType ( ValueType . Number , false , Cardinality . One ) , value , null ) ) . equals ( "0" )
2017-08-15 13:54:22 +02:00
value = "1"
2019-09-13 13:49:11 +02:00
o ( encryptValue ( "test" , createValueType ( ValueType . Number , false , Cardinality . One ) , value , null ) ) . equals ( "1" )
2017-08-15 13:54:22 +02:00
} )
} )
2023-12-18 11:36:38 +01:00
function createMailLiteral (
ownerGroupKey : Aes128Key | Aes256Key | null ,
sessionKey ,
subject ,
confidential ,
senderName ,
recipientName ,
ownerGroupId : string ,
) : Record < string , any > {
2022-04-12 14:23:38 +02:00
return {
2017-08-15 13:54:22 +02:00
_format : "0" ,
_area : "0" ,
_owner : "ownerId" ,
2023-12-18 11:36:38 +01:00
_ownerGroup : ownerGroupId ,
_ownerEncSessionKey : ownerGroupKey ? encryptKey ( ownerGroupKey , sessionKey ) : null ,
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 : [ "mailListId" , "mailId" ] ,
2017-08-15 13:54:22 +02:00
_permissions : "permissionListId" ,
receivedDate : new Date ( 1470039025474 ) . getTime ( ) . toString ( ) ,
sentDate : new Date ( 1470039021474 ) . getTime ( ) . toString ( ) ,
state : "" ,
trashed : false ,
unread : true ,
2023-12-18 11:36:38 +01:00
subject : uint8ArrayToBase64 ( aesEncrypt ( sessionKey , stringToUtf8Uint8Array ( subject ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , ENABLE_MAC ) ) ,
2017-08-15 13:54:22 +02:00
replyType : "" ,
2022-01-07 15:58:30 +01:00
confidential : uint8ArrayToBase64 (
2023-12-18 11:36:38 +01:00
aesEncrypt ( sessionKey , stringToUtf8Uint8Array ( confidential ? "1" : "0" ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , ENABLE_MAC ) ,
2022-01-07 15:58:30 +01:00
) ,
2017-08-15 13:54:22 +02:00
sender : {
_id : "senderId" ,
address : "hello@tutao.de" ,
2023-12-18 11:36:38 +01:00
name : uint8ArrayToBase64 (
aesEncrypt ( sessionKey , stringToUtf8Uint8Array ( senderName ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , ENABLE_MAC ) ,
) ,
2017-08-15 13:54:22 +02:00
} ,
bccRecipients : [ ] ,
ccRecipients : [ ] ,
2018-10-30 16:43:45 +01:00
toRecipients : [
{
_id : "recipientId" ,
address : "support@yahoo.com" ,
2022-01-07 15:58:30 +01:00
name : uint8ArrayToBase64 (
2023-12-18 11:36:38 +01:00
aesEncrypt ( sessionKey , stringToUtf8Uint8Array ( recipientName ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , ENABLE_MAC ) ,
2022-01-07 15:58:30 +01:00
) ,
} ,
2018-10-30 16:43:45 +01:00
] ,
2022-01-07 15:58:30 +01:00
replyTos : [ ] ,
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 : null ,
attachmentCount : "0" ,
authStatus : "0" ,
2023-12-18 11:36:38 +01:00
listUnsubscribe : uint8ArrayToBase64 (
aesEncrypt ( sessionKey , stringToUtf8Uint8Array ( "" ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , ENABLE_MAC ) ,
) ,
method : uint8ArrayToBase64 ( aesEncrypt ( sessionKey , stringToUtf8Uint8Array ( "" ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , ENABLE_MAC ) ) ,
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
phishingStatus : "0" ,
recipientCount : "0" ,
2017-08-15 13:54:22 +02:00
}
}
2022-04-19 16:51:08 +02:00
o ( "decrypt instance" , async function ( ) {
2019-09-13 13:49:11 +02:00
o . timeout ( 1000 )
2017-08-15 13:54:22 +02:00
let subject = "this is our subject"
let confidential = true
let senderName = "TutanotaTeam"
2023-12-18 11:36:38 +01:00
const user = createTestUser ( "Alice" )
2023-12-05 14:03:33 +01:00
const sk = aes256RandomKey ( )
2023-12-18 11:36:38 +01:00
let mail = createMailLiteral ( user . mailGroupKey , sk , subject , confidential , senderName , user . name , user . mailGroup . _id )
2022-04-19 16:51:08 +02:00
const MailTypeModel = await resolveTypeReference ( MailTypeRef )
2022-12-27 15:37:40 +01:00
return instanceMapper . decryptAndMapToInstance < Mail > ( MailTypeModel , mail , sk ) . then ( ( decrypted ) = > {
2022-01-07 15:58:30 +01:00
o ( isSameTypeRef ( decrypted . _type , MailTypeRef ) ) . equals ( true )
2017-08-15 13:54:22 +02:00
o ( decrypted . receivedDate . getTime ( ) ) . equals ( 1470039025474 )
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 ( neverNull ( decrypted . sentDate ) . getTime ( ) ) . equals ( 1470039021474 )
2017-08-15 13:54:22 +02:00
o ( decrypted . confidential ) . equals ( confidential )
o ( decrypted . subject ) . equals ( subject )
o ( decrypted . replyType ) . equals ( "0" )
// aggregates
2018-10-23 10:57:55 +02:00
o ( isSameTypeRef ( decrypted . sender . _type , MailAddressTypeRef ) ) . equals ( true )
2017-08-15 13:54:22 +02:00
o ( decrypted . sender . name ) . equals ( senderName )
o ( decrypted . sender . address ) . equals ( "hello@tutao.de" )
2023-12-18 11:36:38 +01:00
o ( decrypted . toRecipients [ 0 ] . name ) . equals ( user . name )
2017-08-15 13:54:22 +02:00
o ( decrypted . toRecipients [ 0 ] . address ) . equals ( "support@yahoo.com" )
} )
} )
2021-03-04 17:41:40 +01:00
o ( "encrypt instance" , async function ( ) {
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
2023-11-09 17:04:42 +01:00
let address = createTestEntity ( ContactAddressTypeRef )
2017-08-15 13:54:22 +02:00
address . type = "0"
address . address = "Entenhausen"
address . customTypeName = "0"
2023-11-09 17:04:42 +01:00
let contact = createTestEntity ( ContactTypeRef )
2017-08-15 13:54:22 +02:00
contact . _area = "0"
contact . _owner = "123"
contact . title = "Dr."
contact . firstName = "Max"
contact . lastName = "Meier"
contact . comment = "what?"
contact . company = "WIW"
contact . autoTransmitPassword = "stop bugging me!"
contact . addresses = [ address ]
2022-04-19 16:51:08 +02:00
const ContactTypeModel = await resolveTypeReference ( ContactTypeRef )
const result : any = await instanceMapper . encryptAndMapToLiteral ( ContactTypeModel , contact , sk )
2021-03-04 17:41:40 +01:00
o ( result . _format ) . equals ( "0" )
o ( result . _ownerGroup ) . equals ( null )
o ( result . _ownerEncSessionKey ) . equals ( null )
2023-09-13 11:42:57 +02:00
o ( utf8Uint8ArrayToString ( aesDecrypt ( sk , base64ToUint8Array ( result . addresses [ 0 ] . type ) ) ) ) . equals ( contact . addresses [ 0 ] . type )
o ( utf8Uint8ArrayToString ( aesDecrypt ( sk , base64ToUint8Array ( result . addresses [ 0 ] . address ) ) ) ) . equals ( contact . addresses [ 0 ] . address )
o ( utf8Uint8ArrayToString ( aesDecrypt ( sk , base64ToUint8Array ( result . addresses [ 0 ] . customTypeName ) ) ) ) . equals ( contact . addresses [ 0 ] . customTypeName )
o ( utf8Uint8ArrayToString ( aesDecrypt ( sk , base64ToUint8Array ( result . title ) ) ) ) . equals ( contact . title )
o ( utf8Uint8ArrayToString ( aesDecrypt ( sk , base64ToUint8Array ( result . firstName ) ) ) ) . equals ( contact . firstName )
o ( utf8Uint8ArrayToString ( aesDecrypt ( sk , base64ToUint8Array ( result . lastName ) ) ) ) . equals ( contact . lastName )
o ( utf8Uint8ArrayToString ( aesDecrypt ( sk , base64ToUint8Array ( result . comment ) ) ) ) . equals ( contact . comment )
o ( utf8Uint8ArrayToString ( aesDecrypt ( sk , base64ToUint8Array ( result . company ) ) ) ) . equals ( contact . company )
o ( utf8Uint8ArrayToString ( aesDecrypt ( sk , base64ToUint8Array ( result . autoTransmitPassword ) ) ) ) . equals ( contact . autoTransmitPassword )
2017-08-15 13:54:22 +02:00
} )
2022-01-07 15:58:30 +01:00
o ( "map unencrypted to instance" , async function ( ) {
2024-01-30 18:18:19 +01:00
let userReturnLiteral = {
2022-01-07 15:58:30 +01:00
_format : "0" ,
2024-01-30 18:18:19 +01:00
user : "KOBqO7a----0" ,
2024-02-01 13:54:19 +01:00
userGroup : "someUserGroup" ,
2022-01-07 15:58:30 +01:00
}
2024-01-30 18:18:19 +01:00
const UserReturnTypeModel = await resolveTypeReference ( UserReturnTypeRef )
2024-02-01 13:54:19 +01:00
2024-01-30 18:18:19 +01:00
const userReturn : UserReturn = await instanceMapper . decryptAndMapToInstance ( UserReturnTypeModel , userReturnLiteral , null )
o ( userReturn . _format ) . equals ( "0" )
o ( userReturn . user ) . equals ( "KOBqO7a----0" )
2017-08-15 13:54:22 +02:00
} )
2022-04-19 16:51:08 +02:00
o ( "map unencrypted to DB literal" , async function ( ) {
2024-02-01 13:54:19 +01:00
let userReturn = createTestEntity ( UserReturnTypeRef )
userReturn . _format = "0"
userReturn . user = "KOBqO7a----0"
2024-01-30 18:18:19 +01:00
let userReturnLiteral = {
_format : "0" ,
user : "KOBqO7a----0" ,
2024-02-01 13:54:19 +01:00
userGroup : "someUserGroup" ,
2022-01-07 15:58:30 +01:00
}
2024-01-30 18:18:19 +01:00
const UserReturnTypeModel = await resolveTypeReference ( UserReturnTypeRef )
2024-02-01 13:54:19 +01:00
return instanceMapper . encryptAndMapToLiteral ( UserReturnTypeModel , userReturnLiteral , null ) . then ( ( result ) = > {
2024-01-30 18:18:19 +01:00
o ( result ) . deepEquals ( userReturnLiteral )
2017-08-15 13:54:22 +02:00
} )
} )
2022-03-09 17:43:29 +01:00
o ( "resolve session key: unencrypted instance" , async function ( ) {
2024-01-30 18:18:19 +01:00
const userReturnLiteral = {
2022-01-07 15:58:30 +01:00
_format : "0" ,
2024-01-30 18:18:19 +01:00
user : "KOBqO7a----0" ,
2024-02-01 13:54:19 +01:00
userGroup : "someUserGroup" ,
2022-01-07 15:58:30 +01:00
}
2024-01-30 18:18:19 +01:00
const UserReturnTypeModel = await resolveTypeReference ( UserReturnTypeRef )
o ( await crypto . resolveSessionKey ( UserReturnTypeModel , userReturnLiteral ) ) . equals ( null )
2017-08-15 13:54:22 +02:00
} )
2022-01-07 15:58:30 +01:00
o ( "resolve session key: _ownerEncSessionKey instance" , async function ( ) {
2023-12-18 11:36:38 +01:00
const recipientUser = createTestUser ( "Bob" )
configureLoggedInUser ( recipientUser )
2017-08-15 13:54:22 +02:00
let subject = "this is our subject"
let confidential = true
let senderName = "TutanotaTeam"
2023-12-05 14:03:33 +01:00
const sk = aes256RandomKey ( )
2023-12-18 11:36:38 +01:00
const mail = createMailLiteral ( recipientUser . mailGroupKey , sk , subject , confidential , senderName , recipientUser . name , recipientUser . mailGroup . _id )
2022-03-09 17:43:29 +01:00
2022-04-19 16:51:08 +02:00
const MailTypeModel = await resolveTypeReference ( MailTypeRef )
2022-03-09 17:43:29 +01:00
const sessionKey : Aes128Key = neverNull ( await crypto . resolveSessionKey ( MailTypeModel , mail ) )
2022-01-07 15:58:30 +01:00
o ( sessionKey ) . deepEquals ( sk )
2017-08-15 13:54:22 +02:00
} )
2023-12-18 11:36:38 +01: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
2023-12-18 11:36:38 +01:00
const recipientUser = createTestUser ( "Bob" )
configureLoggedInUser ( recipientUser )
2021-01-25 12:50:28 +01:00
2017-08-15 13:54:22 +02:00
let subject = "this is our subject"
let confidential = true
let senderName = "TutanotaTeam"
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
} )
2023-12-18 11:36:38 +01:00
recipientUser . userGroup . keys . push ( keyPair )
const mail = createMailLiteral ( null , sk , subject , confidential , senderName , recipientUser . name , recipientUser . mailGroup . _id )
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 ,
} )
2020-11-13 10:31:35 +01:00
const pubEncBucketKey = await rsaEncrypt ( publicKey , bitArrayToUint8Array ( bk ) )
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 ,
} )
2022-04-12 14:23:38 +02:00
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
2022-04-19 16:51:08 +02:00
const MailTypeModel = await resolveTypeReference ( MailTypeRef )
2022-03-09 17:43:29 +01:00
const sessionKey = neverNull ( await crypto . resolveSessionKey ( MailTypeModel , mail ) )
o ( sessionKey ) . deepEquals ( sk )
2017-08-15 13:54:22 +02:00
} )
2023-12-18 11:36:38 +01:00
o ( "resolve session key: pq public key decryption of session key" , async function ( ) {
o . timeout ( 500 ) // in CI or with debugging it can take a while
let subject = "this is our subject"
let confidential = true
let senderName = "TutanotaTeam"
const recipientTestUser = createTestUser ( "Bob" )
configureLoggedInUser ( recipientTestUser )
let pqKeyPairs = await pqFacade . generateKeyPairs ( )
const recipientKeyPair = createKeyPair ( {
_id : "keyPairId" ,
pubRsaKey : null ,
symEncPrivRsaKey : null ,
pubEccKey : pqKeyPairs.eccKeyPair.publicKey ,
symEncPrivEccKey : aesEncrypt ( recipientTestUser . userGroupKey , pqKeyPairs . eccKeyPair . privateKey ) ,
pubKyberKey : kyberPublicKeyToBytes ( pqKeyPairs . kyberKeyPair . publicKey ) ,
symEncPrivKyberKey : aesEncrypt ( recipientTestUser . userGroupKey , kyberPrivateKeyToBytes ( pqKeyPairs . kyberKeyPair . privateKey ) ) ,
version : "0" ,
} )
recipientTestUser . userGroup . keys . push ( recipientKeyPair )
const senderIdentityKeyPair = generateEccKeyPair ( )
// configure test mail
let sk = aes256RandomKey ( )
let bk = aes256RandomKey ( )
const mail = createMailLiteral ( null , sk , subject , confidential , senderName , recipientTestUser . name , recipientTestUser . mailGroup . _id )
const bucket = createBucket ( {
bucketPermissions : "bucketPermissionListId" ,
} )
const permission = createPermission ( {
_format : "" ,
listElementApplication : null ,
listElementTypeId : null ,
ops : null ,
symEncSessionKey : null ,
_id : [ "permissionListId" , "permissionId" ] ,
_ownerGroup : recipientTestUser.mailGroup._id ,
bucketEncSessionKey : encryptKey ( bk , sk ) ,
bucket ,
type : PermissionType . Public ,
_ownerEncSessionKey : null ,
_permissions : "p_id" ,
group : null ,
} )
2023-12-18 17:30:21 +01:00
const pqMessage = await pqFacade . encapsulate ( senderIdentityKeyPair , generateEccKeyPair ( ) , pqKeyPairsToPublicKeys ( pqKeyPairs ) , bitArrayToUint8Array ( bk ) )
2023-12-18 11:36:38 +01:00
const pubEncBucketKey = encodePQMessage ( pqMessage )
const bucketPermission = createBucketPermission ( {
_id : [ "bucketPermissionListId" , "bucketPermissionId" ] ,
_ownerGroup : recipientTestUser.mailGroup._id ,
type : BucketPermissionType . Public ,
group : recipientTestUser.userGroup._id ,
pubEncBucketKey ,
_format : "" ,
_permissions : "" ,
ownerEncBucketKey : null ,
protocolVersion : "0" ,
pubKeyVersion : "0" ,
symEncBucketKey : null ,
} )
when ( userFacade . createAuthHeaders ( ) ) . thenReturn ( { } )
when ( restClient . request ( anything ( ) , HttpMethod . PUT , anything ( ) ) ) . thenResolve ( undefined )
when ( entityClient . loadAll ( BucketPermissionTypeRef , getListId ( bucketPermission ) ) ) . thenResolve ( [ bucketPermission ] )
when ( entityClient . loadAll ( PermissionTypeRef , getListId ( permission ) ) ) . thenResolve ( [ permission ] )
const MailTypeModel = await resolveTypeReference ( MailTypeRef )
const sessionKey = neverNull ( await crypto . resolveSessionKey ( MailTypeModel , mail ) )
o ( sessionKey ) . deepEquals ( sk )
} )
o ( "encryptBucketKeyForInternalRecipient with existing PQKeys for sender and recipient" , async ( ) = > {
const pqFacadeMock = instance ( PQFacade )
const cryptoFacadeTmp = new CryptoFacade (
userFacade ,
entityClient ,
restClient ,
rsa ,
serviceExecutor ,
instanceMapper ,
ownerEncSessionKeysUpdateQueue ,
pqFacadeMock ,
)
let senderMailAddress = "alice@tutanota.com"
let recipientMailAddress = "bob@tutanota.com"
let senderGroupKey = aes256RandomKey ( )
let bk = aes256RandomKey ( )
const recipientKeyPairs = await pqFacade . generateKeyPairs ( )
const recipientKeyPair = createKeyPair ( {
_id : "recipientKeyPairId" ,
pubEccKey : recipientKeyPairs.eccKeyPair.publicKey ,
symEncPrivEccKey : null ,
pubKyberKey : kyberPublicKeyToBytes ( recipientKeyPairs . kyberKeyPair . publicKey ) ,
symEncPrivKyberKey : null ,
pubRsaKey : null ,
symEncPrivRsaKey : null ,
version : "0" ,
} )
const senderKeyPairs = await pqFacade . generateKeyPairs ( )
const senderKeyPair = createKeyPair ( {
_id : "senderKeyPairId" ,
pubRsaKey : null ,
symEncPrivRsaKey : null ,
pubEccKey : senderKeyPairs.eccKeyPair.publicKey ,
symEncPrivEccKey : aesEncrypt ( senderGroupKey , senderKeyPairs . eccKeyPair . privateKey ) ,
pubKyberKey : kyberPublicKeyToBytes ( senderKeyPairs . kyberKeyPair . publicKey ) ,
symEncPrivKyberKey : aesEncrypt ( senderGroupKey , kyberPrivateKeyToBytes ( senderKeyPairs . kyberKeyPair . privateKey ) ) ,
version : "0" ,
} )
const senderUserGroup = createGroup ( {
_format : "" ,
_ownerGroup : "" ,
_permissions : "" ,
admin : "admin1" ,
adminGroupEncGKey : null ,
administratedGroups : null ,
archives : [ ] ,
customer : "customer1" ,
enabled : false ,
external : false ,
groupInfo : [ "" , "" ] ,
invitations : "" ,
members : "" ,
storageCounter : "counter1" ,
type : "" ,
user : "user1" ,
_id : "userGroupId" ,
keys : [ senderKeyPair ] ,
} )
const notFoundRecipients = [ ]
const pqEncapsulation : PQBucketKeyEncapsulation = {
kyberCipherText : new Uint8Array ( [ 1 ] ) ,
kekEncBucketKey : new Uint8Array ( [ 2 ] ) ,
}
const pqMessage : PQMessage = {
senderIdentityPubKey : senderKeyPair.pubEccKey ! ,
ephemeralPubKey : senderKeyPair.pubEccKey ! ,
encapsulation : pqEncapsulation ,
}
when ( serviceExecutor . get ( PublicKeyService , createPublicKeyGetIn ( { mailAddress : recipientMailAddress } ) ) ) . thenResolve (
createPublicKeyGetOut ( {
pubKeyVersion : "0" ,
pubEccKey : recipientKeyPair.pubEccKey ,
pubKyberKey : recipientKeyPair.pubKyberKey ,
pubRsaKey : null ,
} ) ,
)
when ( serviceExecutor . get ( PublicKeyService , createPublicKeyGetIn ( { mailAddress : senderMailAddress } ) ) ) . thenResolve (
createPublicKeyGetOut ( {
pubKeyVersion : "0" ,
pubEccKey : senderKeyPair.pubEccKey ,
pubKyberKey : senderKeyPair.pubKyberKey ,
pubRsaKey : null ,
} ) ,
)
2023-12-18 17:30:21 +01:00
when ( pqFacadeMock . encapsulate ( senderKeyPairs . eccKeyPair , anything ( ) , pqKeyPairsToPublicKeys ( recipientKeyPairs ) , bitArrayToUint8Array ( bk ) ) ) . thenResolve (
pqMessage ,
)
2023-12-18 11:36:38 +01:00
when ( entityClient . load ( GroupTypeRef , senderUserGroup . _id ) ) . thenResolve ( senderUserGroup )
when ( userFacade . getGroupKey ( senderUserGroup . _id ) ) . thenReturn ( senderGroupKey )
const internalRecipientKeyData = ( await cryptoFacadeTmp . encryptBucketKeyForInternalRecipient (
senderUserGroup . _id ,
bk ,
recipientMailAddress ,
notFoundRecipients ,
) ) as InternalRecipientKeyData
o ( internalRecipientKeyData ! . pubKeyVersion ) . equals ( "0" )
o ( internalRecipientKeyData ! . mailAddress ) . equals ( recipientMailAddress )
o ( internalRecipientKeyData ! . pubEncBucketKey ) . deepEquals ( encodePQMessage ( pqMessage ) )
verify ( serviceExecutor . put ( PublicKeyService , anything ( ) ) , { times : 0 } )
} )
o ( "encryptBucketKeyForInternalRecipient with existing PQKeys for recipient" , async ( ) = > {
const pqFacadeMock = instance ( PQFacade )
const cryptoFacadeTmp = new CryptoFacade (
userFacade ,
entityClient ,
restClient ,
rsa ,
serviceExecutor ,
instanceMapper ,
ownerEncSessionKeysUpdateQueue ,
pqFacadeMock ,
)
let senderMailAddress = "alice@tutanota.com"
let recipientMailAddress = "bob@tutanota.com"
let senderGroupKey = aes256RandomKey ( )
let bk = aes256RandomKey ( )
const recipientKeyPairs = await pqFacade . generateKeyPairs ( )
const recipientKeyPair = createKeyPair ( {
_ownerGroup : "" ,
pubRsaKey : null ,
symEncPrivEccKey : null ,
symEncPrivKyberKey : null ,
symEncPrivRsaKey : null ,
version : "0" ,
_id : "recipientKeyPairId" ,
pubEccKey : recipientKeyPairs.eccKeyPair.publicKey ,
pubKyberKey : kyberPublicKeyToBytes ( recipientKeyPairs . kyberKeyPair . publicKey ) ,
} )
2023-12-18 17:30:21 +01:00
const senderKeyPairs = RSA_TEST_KEYPAIR
2023-12-18 11:36:38 +01:00
const senderKeyPair = createKeyPair ( {
_id : "senderKeyPairId" ,
_ownerGroup : "" ,
pubEccKey : null ,
pubKyberKey : null ,
symEncPrivEccKey : null ,
symEncPrivKyberKey : null ,
version : "0" ,
pubRsaKey : hexToUint8Array ( rsaPublicKeyToHex ( senderKeyPairs . publicKey ) ) ,
symEncPrivRsaKey : aesEncrypt ( senderGroupKey , hexToUint8Array ( rsaPrivateKeyToHex ( senderKeyPairs . privateKey ) ) ) ,
} )
const senderUserGroup = createGroup ( {
_format : "" ,
_ownerGroup : "" ,
_permissions : "" ,
admin : null ,
adminGroupEncGKey : null ,
administratedGroups : null ,
archives : [ ] ,
customer : null ,
enabled : false ,
external : false ,
groupInfo : [ "" , "" ] ,
invitations : "" ,
members : "" ,
storageCounter : null ,
type : "" ,
user : null ,
_id : "userGroupId" ,
keys : [ senderKeyPair ] ,
} )
const notFoundRecipients = [ ]
const pqEncapsulation : PQBucketKeyEncapsulation = {
kyberCipherText : new Uint8Array ( [ 1 ] ) ,
kekEncBucketKey : new Uint8Array ( [ 2 ] ) ,
}
const dummyEccPubKey = generateEccKeyPair ( ) . publicKey
const pqMessage : PQMessage = {
senderIdentityPubKey : dummyEccPubKey ,
ephemeralPubKey : dummyEccPubKey ,
encapsulation : pqEncapsulation ,
}
when ( serviceExecutor . get ( PublicKeyService , createPublicKeyGetIn ( { mailAddress : recipientMailAddress } ) ) ) . thenResolve (
createPublicKeyGetOut ( {
pubRsaKey : null ,
pubKeyVersion : "0" ,
pubEccKey : recipientKeyPair.pubEccKey ,
pubKyberKey : recipientKeyPair.pubKyberKey ,
} ) ,
)
when ( serviceExecutor . get ( PublicKeyService , createPublicKeyGetIn ( { mailAddress : senderMailAddress } ) ) ) . thenResolve (
createPublicKeyGetOut ( {
pubKeyVersion : "0" ,
pubRsaKey : senderKeyPair.pubRsaKey ,
pubEccKey : null ,
pubKyberKey : null ,
} ) ,
)
2023-12-18 17:30:21 +01:00
when ( pqFacadeMock . encapsulate ( anything ( ) , anything ( ) , pqKeyPairsToPublicKeys ( recipientKeyPairs ) , bitArrayToUint8Array ( bk ) ) ) . thenResolve ( pqMessage )
2023-12-18 11:36:38 +01:00
when ( entityClient . load ( GroupTypeRef , senderUserGroup . _id ) ) . thenResolve ( senderUserGroup )
when ( userFacade . getGroupKey ( senderUserGroup . _id ) ) . thenReturn ( senderGroupKey )
when ( userFacade . getUserGroupKey ( ) ) . thenReturn ( senderGroupKey )
const internalRecipientKeyData = ( await cryptoFacadeTmp . encryptBucketKeyForInternalRecipient (
senderUserGroup . _id ,
bk ,
recipientMailAddress ,
notFoundRecipients ,
) ) as InternalRecipientKeyData
o ( internalRecipientKeyData ! . pubKeyVersion ) . equals ( "0" )
o ( internalRecipientKeyData ! . mailAddress ) . equals ( recipientMailAddress )
o ( internalRecipientKeyData ! . pubEncBucketKey ) . deepEquals ( encodePQMessage ( pqMessage ) )
const pubKeyPutIn = captor ( )
verify ( serviceExecutor . put ( PublicKeyService , pubKeyPutIn . capture ( ) ) , { times : 1 } )
const eccKeyPair = captor ( )
2023-12-18 17:30:21 +01:00
verify ( pqFacadeMock . encapsulate ( eccKeyPair . capture ( ) , anything ( ) , pqKeyPairsToPublicKeys ( recipientKeyPairs ) , bitArrayToUint8Array ( bk ) ) , { times : 1 } )
2023-12-18 11:36:38 +01:00
o ( pubKeyPutIn . value . pubEccKey ) . deepEquals ( eccKeyPair . value . publicKey )
o ( aesDecrypt ( senderGroupKey , pubKeyPutIn . value . symEncPrivEccKey ) ) . deepEquals ( eccKeyPair . value . privateKey )
} )
o ( "encryptBucketKeyForInternalRecipient with existing PQKeys for sender" , async ( ) = > {
const pqFacadeMock = instance ( PQFacade )
const cryptoFacadeTmp = new CryptoFacade (
userFacade ,
entityClient ,
restClient ,
rsa ,
serviceExecutor ,
instanceMapper ,
ownerEncSessionKeysUpdateQueue ,
pqFacadeMock ,
)
let senderMailAddress = "alice@tutanota.com"
let recipientMailAddress = "bob@tutanota.com"
let senderGroupKey = aes256RandomKey ( )
let bk = aes256RandomKey ( )
2023-12-18 17:30:21 +01:00
const recipientKeyPairs = RSA_TEST_KEYPAIR
2023-12-18 11:36:38 +01:00
const recipientKeyPair = createKeyPair ( {
_id : "recipientKeyPairId" ,
pubRsaKey : hexToUint8Array ( rsaPublicKeyToHex ( recipientKeyPairs . publicKey ) ) ,
symEncPrivRsaKey : aesEncrypt ( senderGroupKey , hexToUint8Array ( rsaPrivateKeyToHex ( recipientKeyPairs . privateKey ) ) ) ,
pubEccKey : null ,
pubKyberKey : null ,
symEncPrivEccKey : null ,
symEncPrivKyberKey : null ,
version : "0" ,
} )
const senderKeyPairs = await pqFacade . generateKeyPairs ( )
const senderKeyPair = createKeyPair ( {
_id : "senderKeyPairId" ,
pubEccKey : senderKeyPairs.eccKeyPair.publicKey ,
symEncPrivEccKey : aesEncrypt ( senderGroupKey , senderKeyPairs . eccKeyPair . privateKey ) ,
pubKyberKey : kyberPublicKeyToBytes ( senderKeyPairs . kyberKeyPair . publicKey ) ,
symEncPrivKyberKey : aesEncrypt ( senderGroupKey , kyberPrivateKeyToBytes ( senderKeyPairs . kyberKeyPair . privateKey ) ) ,
pubRsaKey : null ,
symEncPrivRsaKey : null ,
version : "0" ,
} )
const senderUserGroup = createGroup ( {
_id : "userGroupId" ,
keys : [ senderKeyPair ] ,
_permissions : "" ,
admin : null ,
adminGroupEncGKey : null ,
administratedGroups : null ,
archives : [ ] ,
customer : null ,
enabled : false ,
external : false ,
groupInfo : [ "" , "" ] ,
invitations : "" ,
members : "" ,
storageCounter : null ,
type : "" ,
user : null ,
} )
const notFoundRecipients = [ ]
when ( serviceExecutor . get ( PublicKeyService , createPublicKeyGetIn ( { mailAddress : recipientMailAddress } ) ) ) . thenResolve (
createPublicKeyGetOut ( {
pubKeyVersion : "0" ,
pubRsaKey : recipientKeyPair.pubRsaKey ,
pubEccKey : null ,
pubKyberKey : null ,
} ) ,
)
when ( serviceExecutor . get ( PublicKeyService , createPublicKeyGetIn ( { mailAddress : senderMailAddress } ) ) ) . thenResolve (
createPublicKeyGetOut ( {
pubKeyVersion : "0" ,
pubEccKey : senderKeyPair.pubEccKey ,
pubKyberKey : senderKeyPair.pubKyberKey ,
_ownerGroup : "" ,
pubRsaKey : null ,
} ) ,
)
when ( entityClient . load ( GroupTypeRef , senderUserGroup . _id ) ) . thenResolve ( senderUserGroup )
when ( userFacade . getGroupKey ( senderUserGroup . _id ) ) . thenReturn ( senderGroupKey )
const internalRecipientKeyData = ( await cryptoFacadeTmp . encryptBucketKeyForInternalRecipient (
senderUserGroup . _id ,
bk ,
recipientMailAddress ,
notFoundRecipients ,
) ) as InternalRecipientKeyData
o ( internalRecipientKeyData ! . pubKeyVersion ) . equals ( "0" )
o ( internalRecipientKeyData ! . mailAddress ) . equals ( recipientMailAddress )
o ( await rsa . decrypt ( recipientKeyPairs . privateKey , internalRecipientKeyData ! . pubEncBucketKey ) ) . deepEquals ( bitArrayToUint8Array ( bk ) )
verify ( pqFacadeMock , { times : 0 } )
verify ( serviceExecutor . put ( PublicKeyService , anything ( ) ) , { times : 0 } )
} )
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 ( )
Object . assign ( testData . mailLiteral , { body : "bodyId" } )
when ( serviceExecutor . get ( PublicKeyService , anything ( ) ) ) . thenResolve (
createPublicKeyGetOut ( {
pubEccKey : testData.senderIdentityKeyPair.publicKey ,
pubKeyVersion : "0" ,
pubKyberKey : null ,
pubRsaKey : null ,
} ) ,
)
const sessionKey = neverNull ( await crypto . resolveSessionKey ( testData . MailTypeModel , testData . mailLiteral ) )
o ( sessionKey ) . deepEquals ( testData . sk )
const updatedInstanceSessionKeysCaptor = captor ( )
verify ( ownerEncSessionKeysUpdateQueue . updateInstanceSessionKeys ( updatedInstanceSessionKeysCaptor . capture ( ) ) )
const updatedInstanceSessionKeys = updatedInstanceSessionKeysCaptor . value as Array < InstanceSessionKey >
o ( updatedInstanceSessionKeys . length ) . equals ( testData . bucketKey . bucketEncSessionKeys . length )
const mailInstanceSessionKey = updatedInstanceSessionKeys . find ( ( instanceSessionKey ) = >
isSameId ( [ instanceSessionKey . instanceList , instanceSessionKey . instanceId ] , testData . mailLiteral . _id ) ,
)
const actualAutStatus = utf8Uint8ArrayToString ( aesDecrypt ( testData . sk , neverNull ( mailInstanceSessionKey ) . encryptionAuthStatus ! ) )
o ( actualAutStatus ) . deepEquals ( EncryptionAuthStatus . PQ_AUTHENTICATION_SUCCEEDED )
} )
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 )
Object . assign ( testData . mailLiteral , { body : "bodyId" } )
when ( serviceExecutor . get ( PublicKeyService , anything ( ) ) ) . thenResolve (
createPublicKeyGetOut ( {
pubEccKey : testData.senderIdentityKeyPair.publicKey ,
pubKeyVersion : "0" ,
pubKyberKey : null ,
pubRsaKey : null ,
} ) ,
)
const sessionKey = neverNull ( await crypto . resolveSessionKey ( testData . MailTypeModel , testData . mailLiteral ) )
o ( sessionKey ) . deepEquals ( testData . sk )
const updatedInstanceSessionKeysCaptor = captor ( )
verify ( ownerEncSessionKeysUpdateQueue . updateInstanceSessionKeys ( updatedInstanceSessionKeysCaptor . capture ( ) ) )
const updatedInstanceSessionKeys = updatedInstanceSessionKeysCaptor . value as Array < InstanceSessionKey >
o ( updatedInstanceSessionKeys . length ) . equals ( testData . bucketKey . bucketEncSessionKeys . length )
const mailInstanceSessionKey = updatedInstanceSessionKeys . find ( ( instanceSessionKey ) = >
isSameId ( [ instanceSessionKey . instanceList , instanceSessionKey . instanceId ] , testData . mailLiteral . _id ) ,
)
const pubKeyServiceCaptor = captor ( )
verify ( serviceExecutor . get ( PublicKeyService , pubKeyServiceCaptor . capture ( ) ) )
const pubKeyAddress = pubKeyServiceCaptor . value as PublicKeyGetIn
o ( pubKeyAddress . mailAddress ) . equals ( "system@tutanota.de" )
const actualAutStatus = utf8Uint8ArrayToString ( aesDecrypt ( testData . sk , neverNull ( mailInstanceSessionKey ) . encryptionAuthStatus ! ) )
o ( actualAutStatus ) . deepEquals ( EncryptionAuthStatus . PQ_AUTHENTICATION_SUCCEEDED )
} )
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 ( )
Object . assign ( testData . mailLiteral , { body : "bodyId" } )
const wrongSenderIdentityKeyPair = generateEccKeyPair ( )
when ( serviceExecutor . get ( PublicKeyService , anything ( ) ) ) . thenResolve (
createPublicKeyGetOut ( {
pubEccKey : wrongSenderIdentityKeyPair.publicKey ,
pubKeyVersion : "0" ,
pubKyberKey : null ,
pubRsaKey : null ,
} ) ,
)
const sessionKey = neverNull ( await crypto . resolveSessionKey ( testData . MailTypeModel , testData . mailLiteral ) )
o ( sessionKey ) . deepEquals ( testData . sk )
const updatedInstanceSessionKeysCaptor = captor ( )
verify ( ownerEncSessionKeysUpdateQueue . updateInstanceSessionKeys ( updatedInstanceSessionKeysCaptor . capture ( ) ) )
const updatedInstanceSessionKeys = updatedInstanceSessionKeysCaptor . value as Array < InstanceSessionKey >
o ( updatedInstanceSessionKeys . length ) . equals ( testData . bucketKey . bucketEncSessionKeys . length )
const mailInstanceSessionKey = updatedInstanceSessionKeys . find ( ( instanceSessionKey ) = >
isSameId ( [ instanceSessionKey . instanceList , instanceSessionKey . instanceId ] , testData . mailLiteral . _id ) ,
)
const actualAutStatus = utf8Uint8ArrayToString ( aesDecrypt ( testData . sk , neverNull ( mailInstanceSessionKey ) . encryptionAuthStatus ! ) )
o ( actualAutStatus ) . deepEquals ( EncryptionAuthStatus . PQ_AUTHENTICATION_FAILED )
} )
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 ( )
Object . assign ( testData . mailLiteral , { body : "bodyId" } )
const sessionKey = neverNull ( await crypto . resolveSessionKey ( testData . MailTypeModel , testData . mailLiteral ) )
o ( sessionKey ) . deepEquals ( testData . sk )
const updatedInstanceSessionKeysCaptor = captor ( )
verify ( ownerEncSessionKeysUpdateQueue . updateInstanceSessionKeys ( updatedInstanceSessionKeysCaptor . capture ( ) ) , { times : 1 } )
const updatedInstanceSessionKeys = updatedInstanceSessionKeysCaptor . value as Array < InstanceSessionKey >
o ( updatedInstanceSessionKeys . length ) . equals ( testData . bucketKey . bucketEncSessionKeys . length )
const mailInstanceSessionKey = updatedInstanceSessionKeys . find ( ( instanceSessionKey ) = >
isSameId ( [ instanceSessionKey . instanceList , instanceSessionKey . instanceId ] , testData . mailLiteral . _id ) ,
)
const actualAutStatus = utf8Uint8ArrayToString ( aesDecrypt ( testData . sk , neverNull ( mailInstanceSessionKey ) . encryptionAuthStatus ! ) )
o ( actualAutStatus ) . deepEquals ( EncryptionAuthStatus . RSA_NO_AUTHENTICATION )
} )
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 ] )
Object . assign ( testData . mailLiteral , { mailDetails : [ "mailDetailsArchiveId" , "mailDetailsId" ] } )
const mailSessionKey = neverNull ( await crypto . resolveSessionKey ( testData . MailTypeModel , testData . mailLiteral ) )
o ( mailSessionKey ) . deepEquals ( testData . sk )
const updatedInstanceSessionKeysCaptor = captor ( )
verify ( ownerEncSessionKeysUpdateQueue . updateInstanceSessionKeys ( updatedInstanceSessionKeysCaptor . capture ( ) ) , { times : 1 } )
const updatedInstanceSessionKeys = updatedInstanceSessionKeysCaptor . value as Array < InstanceSessionKey >
o ( updatedInstanceSessionKeys . length ) . equals ( testData . bucketKey . bucketEncSessionKeys . length )
const mailInstanceSessionKey = updatedInstanceSessionKeys . find ( ( instanceSessionKey ) = >
isSameId ( [ instanceSessionKey . instanceList , instanceSessionKey . instanceId ] , testData . mailLiteral . _id ) ,
)
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 ( )
const mailSessionKey = neverNull ( await crypto . resolveSessionKey ( testData . MailTypeModel , testData . mailLiteral ) )
o ( mailSessionKey ) . deepEquals ( testData . sk )
const updatedInstanceSessionKeysCaptor = captor ( )
verify ( ownerEncSessionKeysUpdateQueue . updateInstanceSessionKeys ( updatedInstanceSessionKeysCaptor . capture ( ) ) , { times : 1 } )
const updatedInstanceSessionKeys = updatedInstanceSessionKeysCaptor . value as Array < InstanceSessionKey >
o ( updatedInstanceSessionKeys . length ) . equals ( testData . bucketKey . bucketEncSessionKeys . length )
const mailInstanceSessionKey = updatedInstanceSessionKeys . find ( ( instanceSessionKey ) = >
isSameId ( [ instanceSessionKey . instanceList , instanceSessionKey . instanceId ] , testData . mailLiteral . _id ) ,
)
const actualAutStatus = utf8Uint8ArrayToString ( aesDecrypt ( testData . sk , neverNull ( mailInstanceSessionKey ) . encryptionAuthStatus ! ) )
o ( actualAutStatus ) . deepEquals ( EncryptionAuthStatus . AES_NO_AUTHENTICATION )
} )
2022-01-07 15:58:30 +01:00
o ( "decryption errors should be written to _errors field" , async function ( ) {
2023-12-18 11:36:38 +01:00
const testUser = createTestUser ( "Bob" )
configureLoggedInUser ( testUser )
2017-08-15 13:54:22 +02:00
let subject = "this is our subject"
let confidential = true
let senderName = "TutanotaTeam"
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
2023-12-18 11:36:38 +01:00
let mail = createMailLiteral ( testUser . mailGroupKey , sk , subject , confidential , senderName , testUser . name , testUser . mailGroup . _id )
2022-01-07 15:58:30 +01:00
mail . subject = "asdf"
2022-04-19 16:51:08 +02:00
const MailTypeModel = await resolveTypeReference ( MailTypeRef )
2022-01-07 15:58:30 +01:00
const instance : Mail = await instanceMapper . decryptAndMapToInstance ( MailTypeModel , mail , sk )
o ( typeof instance . _errors [ "subject" ] ) . equals ( "string" )
2017-08-15 13:54:22 +02:00
} )
2020-04-29 15:55:56 +02:00
o . spec ( "instance migrations" , function ( ) {
2023-01-12 16:48:28 +01:00
o . beforeEach ( function ( ) {
2023-12-18 11:36:38 +01:00
when ( entityClient . update ( anything ( ) ) ) . thenResolve ( undefined )
2023-01-12 16:48:28 +01:00
} )
o ( "contact migration without birthday" , async function ( ) {
2023-11-09 17:04:42 +01:00
const contact = createTestEntity ( ContactTypeRef )
2022-03-09 17:43:29 +01:00
2023-01-12 16:48:28 +01:00
const migratedContact = await crypto . applyMigrationsForInstance ( contact )
o ( migratedContact . birthdayIso ) . equals ( null )
2023-12-18 11:36:38 +01:00
verify ( entityClient . update ( anything ( ) ) , { times : 0 } )
2023-01-12 16:48:28 +01:00
} )
2022-03-09 17:43:29 +01:00
2023-01-12 16:48:28 +01:00
o ( "contact migration without existing birthday" , async function ( ) {
2023-11-10 16:59:39 +01:00
const contact = createTestEntity ( ContactTypeRef , {
2023-01-12 16:48:28 +01:00
birthdayIso : "2019-05-01" ,
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
const migratedContact = await crypto . applyMigrationsForInstance ( contact )
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 ( migratedContact . birthdayIso ) . equals ( "2019-05-01" )
2023-12-18 11:36:38 +01:00
verify ( entityClient . update ( anything ( ) ) , { times : 0 } )
2023-01-12 16:48:28 +01:00
} )
2022-03-09 17:43:29 +01:00
2023-01-12 16:48:28 +01:00
o ( "contact migration without existing birthday and oldBirthdayDate" , async function ( ) {
2023-11-10 16:59:39 +01:00
const contact = createTestEntity ( ContactTypeRef , {
2023-01-12 16:48:28 +01:00
_id : [ "listid" , "id" ] ,
birthdayIso : "2019-05-01" ,
oldBirthdayDate : new Date ( 2000 , 4 , 1 ) ,
2022-03-09 17:43:29 +01:00
} )
2023-01-12 16:48:28 +01:00
const migratedContact = await crypto . applyMigrationsForInstance ( contact )
o ( migratedContact . birthdayIso ) . equals ( "2019-05-01" )
o ( migratedContact . oldBirthdayAggregate ) . equals ( null )
o ( migratedContact . oldBirthdayDate ) . equals ( null )
2023-12-18 11:36:38 +01:00
verify ( entityClient . update ( anything ( ) ) , { times : 1 } )
2023-01-12 16:48:28 +01:00
} )
2022-03-09 17:43:29 +01:00
2023-01-12 16:48:28 +01:00
o ( "contact migration with existing birthday and oldBirthdayAggregate" , async function ( ) {
2023-11-10 16:59:39 +01:00
const contact = createTestEntity ( ContactTypeRef , {
2023-01-12 16:48:28 +01:00
_id : [ "listid" , "id" ] ,
birthdayIso : "2019-05-01" ,
2023-11-10 16:59:39 +01:00
oldBirthdayAggregate : createTestEntity ( BirthdayTypeRef , {
2023-01-12 16:48:28 +01:00
day : "01" ,
month : "05" ,
year : "2000" ,
} ) ,
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
2023-01-12 16:48:28 +01:00
const migratedContact = await crypto . applyMigrationsForInstance ( contact )
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 ( migratedContact . birthdayIso ) . equals ( "2019-05-01" )
o ( migratedContact . oldBirthdayAggregate ) . equals ( null )
o ( migratedContact . oldBirthdayDate ) . equals ( null )
2023-12-18 11:36:38 +01:00
verify ( entityClient . update ( anything ( ) ) , { times : 1 } )
2023-01-12 16:48:28 +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-01-12 16:48:28 +01:00
o ( "contact migration from oldBirthdayAggregate" , async function ( ) {
2023-11-10 16:59:39 +01:00
const contact = createTestEntity ( ContactTypeRef , {
2023-01-12 16:48:28 +01:00
_id : [ "listid" , "id" ] ,
oldBirthdayDate : new Date ( 1800 , 4 , 1 ) ,
2023-11-10 16:59:39 +01:00
oldBirthdayAggregate : createTestEntity ( BirthdayTypeRef , {
2023-01-12 16:48:28 +01:00
day : "01" ,
month : "05" ,
year : "2000" ,
} ) ,
2022-03-09 17:43:29 +01:00
} )
2023-01-12 16:48:28 +01:00
const migratedContact = await crypto . applyMigrationsForInstance ( contact )
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 ( migratedContact . birthdayIso ) . equals ( "2000-05-01" )
o ( migratedContact . oldBirthdayAggregate ) . equals ( null )
o ( migratedContact . oldBirthdayDate ) . equals ( null )
2023-12-18 11:36:38 +01:00
verify ( entityClient . update ( anything ( ) ) , { times : 1 } )
2023-01-12 16:48:28 +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-01-12 16:48:28 +01:00
o ( "contact migration from oldBirthdayDate" , async function ( ) {
2023-11-10 16:59:39 +01:00
const contact = createTestEntity ( ContactTypeRef , {
2023-01-12 16:48:28 +01:00
_id : [ "listid" , "id" ] ,
birthdayIso : null ,
oldBirthdayDate : new Date ( 1800 , 4 , 1 ) ,
oldBirthdayAggregate : null ,
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
const migratedContact = await crypto . applyMigrationsForInstance ( contact )
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 ( migratedContact . birthdayIso ) . equals ( "1800-05-01" )
o ( migratedContact . oldBirthdayAggregate ) . equals ( null )
o ( migratedContact . oldBirthdayDate ) . equals ( null )
2023-12-18 11:36:38 +01:00
verify ( entityClient . update ( anything ( ) ) , { times : 1 } )
2023-01-12 16:48:28 +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-01-12 16:48:28 +01:00
o ( "contact migration from oldBirthdayAggregate without year" , async function ( ) {
2023-11-10 16:59:39 +01:00
const contact = createTestEntity ( ContactTypeRef , {
2023-01-12 16:48:28 +01:00
_id : [ "listid" , "id" ] ,
birthdayIso : null ,
oldBirthdayDate : null ,
2023-11-10 16:59:39 +01:00
oldBirthdayAggregate : createTestEntity ( BirthdayTypeRef , {
2023-01-12 16:48:28 +01:00
day : "01" ,
month : "05" ,
year : null ,
} ) ,
2022-03-09 17:43:29 +01:00
} )
2023-01-12 16:48:28 +01:00
const migratedContact = await crypto . applyMigrationsForInstance ( contact )
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 ( migratedContact . birthdayIso ) . equals ( "--05-01" )
o ( migratedContact . oldBirthdayAggregate ) . equals ( null )
o ( migratedContact . oldBirthdayDate ) . equals ( null )
2023-12-18 11:36:38 +01:00
verify ( entityClient . update ( anything ( ) ) , { times : 1 } )
2023-01-12 16:48:28 +01:00
} )
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
o ( "resolve session key: rsa public key decryption of mail session key using BucketKey aggregated type - Mail referencing MailBody" , async function ( ) {
o . timeout ( 500 ) // in CI or with debugging it can take a while
const testData = await prepareRsaPubEncBucketKeyResolveSessionKeyTest ( )
Object . assign ( testData . mailLiteral , { body : "bodyId" } )
const sessionKey = neverNull ( await crypto . resolveSessionKey ( testData . MailTypeModel , testData . mailLiteral ) )
o ( sessionKey ) . deepEquals ( testData . sk )
} )
o ( "resolve session key: rsa public key decryption of session key using BucketKey aggregated type - Mail referencing MailDetailsDraft" , async function ( ) {
o . timeout ( 500 ) // in CI or with debugging it can take a while
const testData = await prepareRsaPubEncBucketKeyResolveSessionKeyTest ( )
Object . assign ( testData . mailLiteral , { mailDetailsDraft : [ "draftDetailsListId" , "draftDetailsId" ] } )
const sessionKey = neverNull ( await crypto . resolveSessionKey ( testData . MailTypeModel , testData . mailLiteral ) )
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 ( )
Object . assign ( testData . mailLiteral , {
mailDetailsDraft : [ "draftDetailsListId" , "draftDetailsId" ] ,
} )
const mailInstance = await instanceMapper . decryptAndMapToInstance < Mail > ( testData . MailTypeModel , testData . mailLiteral , 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
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
const decryptAndMapToInstance = ( instanceMapper . decryptAndMapToInstance = spy ( instanceMapper . decryptAndMapToInstance ) )
const convertBucketKeyToInstanceIfNecessary = ( crypto . convertBucketKeyToInstanceIfNecessary = spy ( crypto . convertBucketKeyToInstanceIfNecessary ) )
const sessionKey = neverNull ( await crypto . resolveSessionKey ( testData . MailTypeModel , mailInstance ) )
o ( decryptAndMapToInstance . invocations . length ) . equals ( 0 )
o ( convertBucketKeyToInstanceIfNecessary . invocations . length ) . equals ( 1 )
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 ( )
Object . assign ( testData . mailLiteral , { mailDetails : [ "mailDetailsArchiveId" , "mailDetailsId" ] } )
const sessionKey = neverNull ( await crypto . resolveSessionKey ( testData . MailTypeModel , testData . mailLiteral ) )
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 ] )
Object . assign ( testData . mailLiteral , { mailDetails : [ "mailDetailsArchiveId" , "mailDetailsId" ] } )
2023-01-12 16:48:28 +01:00
2023-12-18 11:36:38 +01:00
const mailSessionKey = neverNull ( await crypto . resolveSessionKey ( testData . MailTypeModel , testData . mailLiteral ) )
o ( mailSessionKey ) . deepEquals ( testData . sk )
2023-01-12 16:48:28 +01:00
2023-12-18 11:36:38 +01:00
o ( testData . bucketKey . bucketEncSessionKeys . length ) . equals ( 3 ) //mail, file1, file2
const updatedInstanceSessionKeysCaptor = captor ( )
verify ( ownerEncSessionKeysUpdateQueue . updateInstanceSessionKeys ( updatedInstanceSessionKeysCaptor . capture ( ) ) )
const updatedInstanceSessionKeys = updatedInstanceSessionKeysCaptor . value
o ( updatedInstanceSessionKeys . length ) . equals ( testData . bucketKey . bucketEncSessionKeys . length )
for ( const isk of testData . 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
2023-12-18 11:36:38 +01:00
o ( "resolve session key: pq public key decryption of mail session key using BucketKey aggregated type - Mail referencing MailBody" , async function ( ) {
o . timeout ( 500 ) // in CI or with debugging it can take a while
const testData = await preparePqPubEncBucketKeyResolveSessionKeyTest ( )
Object . assign ( testData . mailLiteral , { body : "bodyId" } )
when ( serviceExecutor . get ( PublicKeyService , anything ( ) ) ) . thenResolve (
createPublicKeyGetOut ( {
pubEccKey : testData.senderIdentityKeyPair.publicKey ,
pubKeyVersion : "0" ,
pubKyberKey : null ,
pubRsaKey : null ,
} ) ,
)
2023-01-12 16:48:28 +01:00
2023-12-18 11:36:38 +01:00
const sessionKey = neverNull ( await crypto . resolveSessionKey ( testData . MailTypeModel , testData . mailLiteral ) )
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 )
} )
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 ( "resolve session key: pq public key decryption of session key using BucketKey aggregated type - Mail referencing MailDetailsDraft" , async function ( ) {
o . timeout ( 500 ) // in CI or with debugging it can take a while
const testData = await preparePqPubEncBucketKeyResolveSessionKeyTest ( )
Object . assign ( testData . mailLiteral , { mailDetailsDraft : [ "draftDetailsListId" , "draftDetailsId" ] } )
when ( serviceExecutor . get ( PublicKeyService , anything ( ) ) ) . thenResolve (
createPublicKeyGetOut ( {
pubEccKey : testData.senderIdentityKeyPair.publicKey ,
pubKeyVersion : "0" ,
pubKyberKey : null ,
pubRsaKey : null ,
} ) ,
2023-01-12 16:48:28 +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
const sessionKey = neverNull ( await crypto . resolveSessionKey ( testData . MailTypeModel , testData . mailLiteral ) )
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
const testData = await preparePqPubEncBucketKeyResolveSessionKeyTest ( )
Object . assign ( testData . mailLiteral , {
mailDetailsDraft : [ "draftDetailsListId" , "draftDetailsId" ] ,
} )
when ( serviceExecutor . get ( PublicKeyService , anything ( ) ) ) . thenResolve (
createPublicKeyGetOut ( {
pubEccKey : testData.senderIdentityKeyPair.publicKey ,
pubKeyVersion : "0" ,
pubKyberKey : null ,
pubRsaKey : null ,
} ) ,
)
const mailInstance = await instanceMapper . decryptAndMapToInstance < Mail > ( testData . MailTypeModel , testData . mailLiteral , testData . sk )
// do not use testdouble here because it's hard to not break the function itself and then verify invocations
const decryptAndMapToInstance = ( instanceMapper . decryptAndMapToInstance = spy ( instanceMapper . decryptAndMapToInstance ) )
const convertBucketKeyToInstanceIfNecessary = ( crypto . convertBucketKeyToInstanceIfNecessary = spy ( crypto . convertBucketKeyToInstanceIfNecessary ) )
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 sessionKey = neverNull ( await crypto . resolveSessionKey ( testData . MailTypeModel , mailInstance ) )
// TODO is it ok to remove this: decryptAndMapToInstance is now called when resolving the session key
// o(decryptAndMapToInstance.invocations.length).equals(0)
o ( convertBucketKeyToInstanceIfNecessary . invocations . length ) . equals ( 1 )
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
2023-12-18 11:36:38 +01:00
o ( "resolve session key: pq 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 preparePqPubEncBucketKeyResolveSessionKeyTest ( )
Object . assign ( testData . mailLiteral , { mailDetails : [ "mailDetailsArchiveId" , "mailDetailsId" ] } )
when ( serviceExecutor . get ( PublicKeyService , anything ( ) ) ) . thenResolve (
createPublicKeyGetOut ( {
pubEccKey : testData.senderIdentityKeyPair.publicKey ,
pubKeyVersion : "0" ,
pubKyberKey : null ,
pubRsaKey : null ,
} ) ,
2023-01-12 16:48:28 +01:00
)
2023-12-18 11:36:38 +01:00
const sessionKey = neverNull ( await crypto . resolveSessionKey ( testData . MailTypeModel , testData . mailLiteral ) )
o ( sessionKey ) . deepEquals ( testData . sk )
2023-01-12 16:48:28 +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 ] )
2023-01-12 16:48:28 +01:00
Object . assign ( testData . mailLiteral , { mailDetails : [ "mailDetailsArchiveId" , "mailDetailsId" ] } )
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
when ( serviceExecutor . get ( PublicKeyService , anything ( ) ) ) . thenResolve (
createPublicKeyGetOut ( {
pubEccKey : testData.senderIdentityKeyPair.publicKey ,
pubKeyVersion : "0" ,
pubKyberKey : null ,
pubRsaKey : null ,
} ) ,
)
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 mailSessionKey = neverNull ( await crypto . resolveSessionKey ( testData . MailTypeModel , testData . mailLiteral ) )
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
2023-12-18 11:36:38 +01:00
o ( testData . bucketKey . bucketEncSessionKeys . length ) . equals ( 3 ) //mail, file1, file2
const updatedInstanceSessionKeysCaptor = captor ( )
verify ( ownerEncSessionKeysUpdateQueue . updateInstanceSessionKeys ( updatedInstanceSessionKeysCaptor . capture ( ) ) )
const updatedInstanceSessionKeys = updatedInstanceSessionKeysCaptor . value
o ( updatedInstanceSessionKeys . length ) . equals ( testData . bucketKey . bucketEncSessionKeys . length )
for ( const isk of testData . 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 ] )
Object . assign ( testData . mailLiteral , { mailDetails : [ "mailDetailsArchiveId" , "mailDetailsId" ] } )
const mailSessionKey = neverNull ( await crypto . resolveSessionKey ( testData . MailTypeModel , testData . mailLiteral ) )
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
Object . assign ( testData . mailLiteral , { mailDetails : [ "mailDetailsArchiveId" , "mailDetailsId" ] } )
const mailSessionKey = neverNull ( await crypto . resolveSessionKey ( testData . MailTypeModel , testData . mailLiteral ) )
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 ( )
2023-08-08 14:52:14 +02:00
when ( userFacade . getGroupKey ( "mailGroupId" ) ) . thenReturn ( gk )
when ( userFacade . hasGroup ( "mailGroupId" ) ) . thenReturn ( true )
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
const MailDetailsBlobTypeModel = await resolveTypeReference ( MailDetailsBlobTypeRef )
const mailDetailsBlobLiteral = {
_id : [ "mailDetailsArchiveId" , "mailDetailsId" ] ,
2023-08-08 14:52:14 +02:00
_ownerGroup : "mailGroupId" ,
_ownerEncSessionKey : encryptKey ( gk , 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
}
const mailDetailsBlobSessionKey = neverNull ( await crypto . resolveSessionKey ( MailDetailsBlobTypeModel , mailDetailsBlobLiteral ) )
o ( mailDetailsBlobSessionKey ) . deepEquals ( sk )
} )
2023-08-08 14:52:14 +02:00
o ( "resolve session key: MailDetailsBlob - session key not found" , async function ( ) {
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 MailDetailsBlobTypeModel = await resolveTypeReference ( MailDetailsBlobTypeRef )
const mailDetailsBlobLiteral = {
_id : [ "mailDetailsArchiveId" , "mailDetailsId" ] ,
_permissions : "permissionListId" ,
}
when ( entityClient . loadAll ( PermissionTypeRef , "permissionListId" ) ) . thenResolve ( [ ] )
try {
await crypto . resolveSessionKey ( MailDetailsBlobTypeModel , mailDetailsBlobLiteral )
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 < {
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
mailLiteral : Record < string , any >
bucketKey : BucketKey
2023-12-05 14:03:33 +01:00
sk : Aes256Key
bk : Aes256Key
mailGroupKey : Aes256Key
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
// configure test user
const recipientUser = createTestUser ( "Bob" )
configureLoggedInUser ( recipientUser )
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
} )
recipientUser . userGroup . keys . push ( keyPair )
// configure 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 subject = "this is our subject"
let confidential = true
let senderName = "TutanotaTeam"
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
const mailLiteral = createMailLiteral ( null , sk , subject , confidential , senderName , recipientUser . name , recipientUser . mailGroup . _id )
const pubEncBucketKey = await rsaEncrypt ( publicKey , bitArrayToUint8Array ( bk ) )
const bucketEncMailSessionKey = encryptKey ( bk , sk )
const MailTypeModel = await resolveTypeReference ( MailTypeRef )
typeModels . tutanota
const mailInstanceSessionKey = createInstanceSessionKey ( {
typeInfo : createTypeInfo ( {
application : MailTypeModel.app ,
typeId : String ( MailTypeModel . id ) ,
} ) ,
symEncSessionKey : bucketEncMailSessionKey ,
instanceList : "mailListId" ,
instanceId : "mailId" ,
encryptionAuthStatus : null ,
2020-04-29 15:55:56 +02:00
} )
2023-12-18 11:36:38 +01:00
const FileTypeModel = await resolveTypeReference ( FileTypeRef )
const bucketEncSessionKeys = fileSessionKeys . map ( ( fileSessionKey , index ) = > {
return createInstanceSessionKey ( {
typeInfo : createTypeInfo ( {
application : FileTypeModel.app ,
typeId : String ( FileTypeModel . id ) ,
} ) ,
symEncSessionKey : encryptKey ( bk , fileSessionKey ) ,
instanceList : "fileListId" ,
instanceId : "fileId" + ( index + 1 ) ,
encryptionAuthStatus : null ,
} )
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 )
const bucketKey = createBucketKey ( {
pubEncBucketKey : pubEncBucketKey ,
keyGroup : recipientUser.userGroup._id ,
bucketEncSessionKeys : bucketEncSessionKeys ,
groupEncBucketKey : null ,
protocolVersion : "0" ,
} )
const BucketKeyModel = await resolveTypeReference ( BucketKeyTypeRef )
const bucketKeyLiteral = await instanceMapper . encryptAndMapToLiteral ( BucketKeyModel , bucketKey , null )
Object . assign ( mailLiteral , { bucketKey : bucketKeyLiteral } )
return {
mailLiteral ,
bucketKey ,
sk ,
bk ,
mailGroupKey : recipientUser.mailGroupKey ,
MailTypeModel ,
}
}
/ * *
* 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 (
fileSessionKeys : Array < Aes128Key > = [ ] ,
confidential : boolean = true ,
) : Promise < {
mailLiteral : Record < string , any >
bucketKey : BucketKey
sk : Aes128Key
bk : Aes128Key
mailGroupKey : Aes128Key
MailTypeModel : TypeModel
senderIdentityKeyPair : EccKeyPair
} > {
// create test user
const recipientUser = createTestUser ( "Bob" )
configureLoggedInUser ( recipientUser )
let pqKeyPairs = await pqFacade . generateKeyPairs ( )
const recipientKeyPair = createKeyPair ( {
_id : "keyPairId" ,
pubEccKey : pqKeyPairs.eccKeyPair.publicKey ,
symEncPrivEccKey : aesEncrypt ( recipientUser . userGroupKey , pqKeyPairs . eccKeyPair . privateKey ) ,
pubKyberKey : kyberPublicKeyToBytes ( pqKeyPairs . kyberKeyPair . publicKey ) ,
symEncPrivKyberKey : aesEncrypt ( recipientUser . userGroupKey , kyberPrivateKeyToBytes ( pqKeyPairs . kyberKeyPair . privateKey ) ) ,
pubRsaKey : null ,
symEncPrivRsaKey : null ,
version : "0" ,
} )
recipientUser . userGroup . keys . push ( recipientKeyPair )
const senderIdentityKeyPair = generateEccKeyPair ( )
// create test mail
let subject = "this is our subject"
let senderName = "TutanotaTeam"
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
let bk = aes256RandomKey ( )
2023-12-18 11:36:38 +01:00
const mailLiteral = createMailLiteral (
recipientUser . mailGroupKey ,
sk ,
subject ,
confidential ,
senderName ,
recipientUser . name ,
recipientUser . mailGroup . _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
// @ts-ignore
mailLiteral . _ownerEncSessionKey = null
2023-12-18 17:30:21 +01:00
const pqMessage = await pqFacade . encapsulate ( senderIdentityKeyPair , generateEccKeyPair ( ) , pqKeyPairsToPublicKeys ( pqKeyPairs ) , bitArrayToUint8Array ( bk ) )
2023-12-18 11:36:38 +01:00
const pubEncBucketKey = encodePQMessage ( pqMessage )
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 )
const MailTypeModel = await resolveTypeReference ( MailTypeRef )
2020-04-29 15:55:56 +02: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
typeModels . tutanota
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" ,
} )
const FileTypeModel = await resolveTypeReference ( FileTypeRef )
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-12-27 15:37:40 +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 )
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 : pubEncBucketKey ,
2023-12-18 11:36:38 +01:00
keyGroup : recipientUser.userGroup._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
bucketEncSessionKeys : bucketEncSessionKeys ,
} )
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
const BucketKeyModel = await resolveTypeReference ( BucketKeyTypeRef )
const bucketKeyLiteral = await instanceMapper . encryptAndMapToLiteral ( BucketKeyModel , bucketKey , null )
2023-01-12 16:48:28 +01:00
Object . assign ( mailLiteral , { bucketKey : bucketKeyLiteral } )
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
return {
mailLiteral ,
bucketKey ,
sk ,
bk ,
2023-12-18 11:36:38 +01:00
mailGroupKey : recipientUser.mailGroupKey ,
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 ,
2023-12-18 11:36:38 +01:00
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 (
2023-01-26 16:34:37 +01:00
fileSessionKeys : Array < Aes128Key > = [ ] ,
externalUserGroupEncBucketKey = false ,
) : Promise < {
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
mailLiteral : Record < string , any >
2023-12-18 11:36:38 +01:00
bucketKey : 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 : Aes128Key
bk : Aes128Key
MailTypeModel : TypeModel
} > {
2023-12-18 11:36:38 +01:00
// create user
const externalUser = createTestUser ( "Bob" )
configureLoggedInUser ( externalUser )
// 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 subject = "this is our subject"
let confidential = true
let senderName = "TutanotaTeam"
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
let bk = aes256RandomKey ( )
2023-01-26 16:34:37 +01:00
2023-12-18 11:36:38 +01:00
const mailLiteral = createMailLiteral ( null , sk , subject , confidential , senderName , externalUser . name , 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 )
const MailTypeModel = await resolveTypeReference ( MailTypeRef )
typeModels . tutanota
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" ,
} )
const FileTypeModel = await resolveTypeReference ( FileTypeRef )
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 ,
} )
const BucketKeyModel = await resolveTypeReference ( BucketKeyTypeRef )
const bucketKeyLiteral = await instanceMapper . encryptAndMapToLiteral ( BucketKeyModel , bucketKey , null )
2023-01-12 16:48:28 +01:00
Object . assign ( mailLiteral , { bucketKey : bucketKeyLiteral } )
2022-03-09 17:43:29 +01:00
2023-12-18 11:36:38 +01:00
return {
mailLiteral ,
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 < {
mailLiteral : Record < string , any >
bucketKey : BucketKey
sk : Aes128Key
bk : Aes128Key
MailTypeModel : TypeModel
internalUser : TestUser
externalUser : TestUser
} > {
// Setup test users and groups
const internalUser = createTestUser ( "Alice" )
const externalUser = createTestUser ( "Bob" )
// Setup relationship between internal and external user
externalUser . userGroup . admin = internalUser . userGroup . _id
externalUser . userGroup . adminGroupEncGKey = encryptKey ( internalUser . userGroupKey , externalUser . userGroupKey )
externalUser . mailGroup . admin = externalUser . userGroup . _id
externalUser . mailGroup . adminGroupEncGKey = encryptKey ( externalUser . userGroupKey , externalUser . mailGroupKey )
configureLoggedInUser ( internalUser )
// setup test mail (confidentail reply from external)
let subject = "this is our subject"
let confidential = true
2023-12-05 14:03:33 +01:00
let sk = aes256RandomKey ( )
let bk = aes256RandomKey ( )
2023-12-18 11:36:38 +01:00
const mailLiteral = createMailLiteral ( null , sk , subject , confidential , externalUser . name , internalUser . name , internalUser . mailGroup . _id )
const keyGroup = externalUser . mailGroup . _id
const groupEncBucketKey = encryptKey ( externalUser . mailGroupKey , bk )
const bucketEncMailSessionKey = encryptKey ( bk , sk )
const MailTypeModel = await resolveTypeReference ( MailTypeRef )
typeModels . tutanota
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 ,
bucketEncSessionKeys : bucketEncSessionKeys ,
} )
const BucketKeyModel = await resolveTypeReference ( BucketKeyTypeRef )
const bucketKeyLiteral = await instanceMapper . encryptAndMapToLiteral ( BucketKeyModel , bucketKey , null )
Object . assign ( mailLiteral , { bucketKey : bucketKeyLiteral } )
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 {
mailLiteral ,
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 ,
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
function createTestUser ( name : string ) : TestUser {
2023-12-05 14:03:33 +01:00
const userGroupKey = aes256RandomKey ( )
const mailGroupKey = aes256RandomKey ( )
2023-12-18 11:36:38 +01:00
const userGroup = createTestEntity ( GroupTypeRef , {
_id : "userGroup" + name ,
type : GroupType . User ,
keys : [ ] ,
} )
const mailGroup = createTestEntity ( GroupTypeRef , {
_id : "mailGroup" + name ,
type : GroupType . Mail ,
keys : [ ] ,
} )
const userGroupMembership = createTestEntity ( GroupMembershipTypeRef , {
group : userGroup._id ,
} )
const mailGroupMembership = createTestEntity ( GroupMembershipTypeRef , {
group : mailGroup._id ,
} )
const user = createTestEntity ( UserTypeRef , {
userGroup : userGroupMembership ,
memberships : [ mailGroupMembership ] ,
} )
when ( entityClient . load ( GroupTypeRef , userGroup . _id ) ) . thenResolve ( userGroup )
when ( entityClient . load ( GroupTypeRef , mailGroup . _id ) ) . thenResolve ( mailGroup )
return {
user ,
userGroup ,
mailGroup ,
userGroupKey ,
mailGroupKey ,
name ,
}
}
/ * *
* Helper function to mock the user facade so that the given test user is considered as logged in user .
* /
function configureLoggedInUser ( testUser : TestUser ) {
when ( userFacade . getLoggedInUser ( ) ) . thenReturn ( testUser . user )
when ( userFacade . getGroupKey ( testUser . mailGroup . _id ) ) . thenReturn ( testUser . mailGroupKey )
when ( userFacade . getGroupKey ( testUser . userGroup . _id ) ) . thenReturn ( testUser . userGroupKey )
when ( userFacade . hasGroup ( testUser . userGroup . _id ) ) . thenReturn ( true )
when ( userFacade . hasGroup ( testUser . mailGroup . _id ) ) . thenReturn ( true )
when ( userFacade . getUserGroupKey ( ) ) . thenReturn ( testUser . userGroupKey )
when ( userFacade . isLeader ( ) ) . thenReturn ( true )
when ( userFacade . isFullyLoggedIn ( ) ) . thenReturn ( true )
}
2022-12-27 15:37:40 +01:00
} )