2019-09-13 13:49:11 +02:00
import o from "ospec"
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 ,
2021-11-23 16:09:12 +01:00
downcast ,
2019-08-21 15:12:04 +02:00
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"
import { BucketPermissionType , PermissionType } from "../../../../../src/api/common/TutanotaConstants.js"
2022-05-12 16:51:15 +02:00
import * as Contact from "../../../../../src/api/entities/tutanota/TypeRefs.js"
2022-04-19 16:51:08 +02:00
import {
ContactTypeRef ,
createBirthday ,
createContact ,
createContactAddress ,
2023-01-17 15:42:18 +01:00
createFile ,
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-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"
import * as UserIdReturn from "../../../../../src/api/entities/sys/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 ,
createBucket ,
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
createBucketKey ,
2022-04-19 16:51:08 +02:00
createBucketPermission ,
createGroup ,
createGroupMembership ,
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
createInstanceSessionKey ,
2022-04-19 16:51:08 +02:00
createKeyPair ,
createPermission ,
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
createTypeInfo ,
2022-04-19 16:51:08 +02:00
createUser ,
createUserIdReturn ,
GroupTypeRef ,
PermissionTypeRef ,
UpdatePermissionKeyData ,
2023-01-12 16:48:28 +01:00
UserIdReturnTypeRef ,
2022-05-12 16:51:15 +02:00
} from "../../../../../src/api/entities/sys/TypeRefs.js"
2023-01-12 16:48:28 +01:00
import { assertThrows } from "@tutao/tutanota-test-utils"
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 {
aes128Decrypt ,
aes128Encrypt ,
aes128RandomKey ,
bitArrayToUint8Array ,
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
decryptKey ,
2022-01-07 15:58:30 +01:00
ENABLE_MAC ,
encryptKey ,
encryptRsaKey ,
2022-02-10 16:32:47 +01:00
hexToPrivateKey ,
hexToPublicKey ,
2022-01-07 15:58:30 +01:00
IV_BYTE_LENGTH ,
2022-12-27 15:37:40 +01:00
random ,
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"
import { matchers , object , verify , when } from "testdouble"
import { UpdatePermissionKeyService } from "../../../../../src/api/entities/sys/Services.js"
import { getListId , isSameId } from "../../../../../src/api/common/utils/EntityUtils.js"
import { resolveTypeReference , typeModels } from "../../../../../src/api/common/EntityFunctions.js"
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"
const { anything , captor } = 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
2017-08-15 13:54:22 +02:00
o . spec ( "crypto facade" , function ( ) {
2022-01-07 15:58:30 +01:00
let rsaPrivateHexKey =
"02008e8bf43e2990a46042da8168aebec699d62e1e1fd068c5582fd1d5433cee8c8b918799e8ee1a22dd9d6e21dd959d7faed8034663225848c21b88c2733c73788875639425a87d54882285e598bf7e8c83861e8b77ab3cf62c53d35e143cee9bb8b3f36850aebd1548c1881dc7485bb51aa13c5a0391b88a8d7afce88ecd4a7e231ca7cfd063216d1d573ad769a6bb557c251ad34beb393a8fff4a886715315ba9eac0bc31541999b92fcb33d15efd2bd50bf77637d3fc5ba1c21082f67281957832ac832fbad6c383779341555993bd945659d7797b9c993396915e6decee9da2d5e060c27c3b5a9bc355ef4a38088af53e5f795ccc837f45d0583052547a736f02002a7622214a3c5dda96cf83f0ececc3381c06ccce69446c54a299fccef49d929c1893ae1326a9fe6cc9727f00048b4ff7833d26806d40a31bbf1bf3e063c779c61c41b765a854fd1338456e691bd1d48571343413479cf72fa920b34b9002fbbbff4ea86a3042fece17683686a055411357a824a01f8e3b277dd54c690d59fd4c8258009707d917ce43d4a337dc58bb55394c4f87b902e7f78fa0abe35e35444bda46bfbc38cf87c60fbe5c4beff49f8e6ddbf50d6caafeb92a6ccef75474879bdb82c9c9c5c35611207dbdb7601c87b254927f4d9fd25ba7694987b5ca70c8184058a91e86cb974a2b7694d6bb08a349b953e4c9a017d9eecada49eb2981dfe10100c7905e44c348447551bea10787da3aa869bbe45f10cff87688e2696474bd18405432f4846dcee886d2a967a61c1adb9a9bc08d75cee678053bf41262f0d9882c230bd5289518569714b961cec3072ed2900f52c9cdc802ee4e63781a3c4acaee4347bd9ab701399a0b96cdf22a75501f7f232069e7f00f5649be5ac3d73edd970100b6dbc3e909e1b69ab3f5dd6a55d7cc68d2b803d3da16941410ab7a5b963e5c50316a52380d4b571633d870ca746b4d6f36e0a9d90cf96a2ddb9c61d5bc9dbe74473f0be99f3642100c1b8ad9d592c6a28fa6570ccbb3f7bb86be8056f76473b978a55d458343dba3d0dcaf152d225f20ccd384706dda9dd2fb0f5f6976e603e901002fd80cc1af8fc3d9dc9f373bf6f5fada257f46610446d7ea9326b4ddc09f1511571e6040df929b6cb754a5e4cd18234e0dc93c20e2599eaca29301557728afdce50a1130898e2c344c63a56f4c928c472f027d76a43f2f74b2966654e3df8a8754d9fe3af964f1ca5cbceae3040adc0ab1105ad5092624872b66d79bdc1ed6410100295bc590e4ea4769f04030e747293b138e6d8e781140c01755b9e33fe9d88afa9c62a6dc04adc0b1c5e23388a71249fe589431f664c7d8eb2c5bcf890f53426b7c5dd72ced14d1965d96b12e19ef4bbc22ef858ae05c01314a05b673751b244d93eb1b1088e3053fa512f50abe1da314811f6a3a1faeadb9b58d419052132e59010032611a3359d91ce3567675726e48aca0601def22111f73a9fea5faeb9a95ec37754d2e52d7ae9444765c39c66264c02b38d096df1cebe6ea9951676663301e577fa5e3aec29a660e0fff36389671f47573d2259396874c33069ddb25dd5b03dcbf803272e68713c320ef7db05765f1088473c9788642e4b80a8eb40968fc0d7c"
let rsaPublicHexKey =
"02008e8bf43e2990a46042da8168aebec699d62e1e1fd068c5582fd1d5433cee8c8b918799e8ee1a22dd9d6e21dd959d7faed8034663225848c21b88c2733c73788875639425a87d54882285e598bf7e8c83861e8b77ab3cf62c53d35e143cee9bb8b3f36850aebd1548c1881dc7485bb51aa13c5a0391b88a8d7afce88ecd4a7e231ca7cfd063216d1d573ad769a6bb557c251ad34beb393a8fff4a886715315ba9eac0bc31541999b92fcb33d15efd2bd50bf77637d3fc5ba1c21082f67281957832ac832fbad6c383779341555993bd945659d7797b9c993396915e6decee9da2d5e060c27c3b5a9bc355ef4a38088af53e5f795ccc837f45d0583052547a736f"
2021-12-07 15:30:53 +01:00
let 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 ( ) {
2021-10-15 16:50:50 +02:00
const suspensionHandler = downcast ( { } )
restClient = new RestClient ( suspensionHandler )
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 ( )
crypto = new CryptoFacade ( userFacade , entityClient , restClient , rsa , serviceExecutor , instanceMapper , ownerEncSessionKeysUpdateQueue )
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 ( ) {
2017-09-25 16:22:38 +02:00
let sk = aes128RandomKey ( )
let value = "this is a string value"
2022-12-27 15:37:40 +01:00
let encryptedValue = uint8ArrayToBase64 ( aes128Encrypt ( sk , stringToUtf8Uint8Array ( value ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , false ) )
o ( decryptValue ( "test" , createValueType ( ValueType . String , true , Cardinality . One ) , encryptedValue , sk ) ) . equals ( value )
2017-09-25 16:22:38 +02:00
value = "516546"
2022-12-27 15:37:40 +01:00
encryptedValue = uint8ArrayToBase64 ( aes128Encrypt ( sk , stringToUtf8Uint8Array ( value ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , false ) )
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 ( ) {
2017-08-15 13:54:22 +02:00
let sk = aes128RandomKey ( )
let value = "this is a string value"
2022-12-27 15:37:40 +01:00
let encryptedValue = uint8ArrayToBase64 ( aes128Encrypt ( sk , stringToUtf8Uint8Array ( value ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , true ) )
o ( decryptValue ( "test" , createValueType ( ValueType . String , true , Cardinality . One ) , encryptedValue , sk ) ) . equals ( value )
2017-08-15 13:54:22 +02:00
value = "516546"
2022-12-27 15:37:40 +01:00
encryptedValue = uint8ArrayToBase64 ( aes128Encrypt ( sk , stringToUtf8Uint8Array ( value ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , true ) )
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 )
let sk = aes128RandomKey ( )
let value = "0"
2022-12-27 15:37:40 +01:00
let encryptedValue = uint8ArrayToBase64 ( aes128Encrypt ( sk , stringToUtf8Uint8Array ( value ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , false ) )
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"
2022-12-27 15:37:40 +01:00
encryptedValue = uint8ArrayToBase64 ( aes128Encrypt ( sk , stringToUtf8Uint8Array ( value ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , false ) )
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"
2022-12-27 15:37:40 +01:00
encryptedValue = uint8ArrayToBase64 ( aes128Encrypt ( sk , stringToUtf8Uint8Array ( value ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , false ) )
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 )
let sk = aes128RandomKey ( )
let value = "0"
2022-12-27 15:37:40 +01:00
let encryptedValue = uint8ArrayToBase64 ( aes128Encrypt ( 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"
2022-12-27 15:37:40 +01:00
encryptedValue = uint8ArrayToBase64 ( aes128Encrypt ( 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"
2022-12-27 15:37:40 +01:00
encryptedValue = uint8ArrayToBase64 ( aes128Encrypt ( 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 )
let sk = aes128RandomKey ( )
let value = new Date ( ) . getTime ( ) . toString ( )
2022-12-27 15:37:40 +01:00
let encryptedValue = uint8ArrayToBase64 ( aes128Encrypt ( sk , stringToUtf8Uint8Array ( value ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , false ) )
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 )
let sk = aes128RandomKey ( )
let value = new Date ( ) . getTime ( ) . toString ( )
2022-12-27 15:37:40 +01:00
let encryptedValue = uint8ArrayToBase64 ( aes128Encrypt ( 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 )
let sk = aes128RandomKey ( )
let value = random . generateRandomData ( 5 )
2022-12-27 15:37:40 +01:00
let encryptedValue = uint8ArrayToBase64 ( aes128Encrypt ( sk , value , random . generateRandomData ( IV_BYTE_LENGTH ) , true , false ) )
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 )
let sk = aes128RandomKey ( )
let value = random . generateRandomData ( 5 )
2022-12-27 15:37:40 +01:00
let encryptedValue = uint8ArrayToBase64 ( aes128Encrypt ( 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 )
let sk = aes128RandomKey ( )
2019-09-03 15:09:55 +02:00
let value = base64ToUint8Array ( "QHRlc3Q=" )
2022-12-27 15:37:40 +01:00
let encryptedValue = uint8ArrayToBase64 ( aes128Encrypt ( 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 )
let sk = aes128RandomKey ( )
let value = base64ToUint8Array ( "X3RleHQgBQD//1FQdGV4dCA=" )
2022-12-27 15:37:40 +01:00
let encryptedValue = uint8ArrayToBase64 ( aes128Encrypt ( 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 )
let sk = aes128RandomKey ( )
2022-12-27 15:37:40 +01:00
let encryptedValue = uint8ArrayToBase64 ( aes128Encrypt ( 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 ( ) {
2017-08-15 13:54:22 +02:00
let sk = aes128RandomKey ( )
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 ( ) = > {
2017-08-15 13:54:22 +02:00
let sk = aes128RandomKey ( )
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 )
2017-08-15 13:54:22 +02:00
let sk = aes128RandomKey ( )
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 (
aes128Encrypt (
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 )
let sk = aes128RandomKey ( )
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 (
aes128Encrypt (
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 (
aes128Encrypt (
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 )
let sk = aes128RandomKey ( )
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 (
aes128Encrypt (
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 )
let sk = aes128RandomKey ( )
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 (
2022-12-27 15:37:40 +01:00
aes128Encrypt ( 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 ( ) {
2017-08-15 13:54:22 +02:00
let sk = aes128RandomKey ( )
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 ( ) = > {
2017-08-15 13:54:22 +02:00
let sk = aes128RandomKey ( )
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
} )
} )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
function createMailLiteral ( gk , sk , subject , confidential , senderName , recipientName ) : 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" ,
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
_ownerGroup : "mailGroupId" ,
2017-08-15 13:54:22 +02:00
_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
_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 ,
2022-12-27 15:37:40 +01:00
subject : uint8ArrayToBase64 ( aes128Encrypt ( sk , 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 (
2022-12-27 15:37:40 +01:00
aes128Encrypt ( sk , 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" ,
2022-12-27 15:37:40 +01:00
name : uint8ArrayToBase64 ( aes128Encrypt ( sk , 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 (
2022-12-27 15:37:40 +01:00
aes128Encrypt ( sk , 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" ,
listUnsubscribe : uint8ArrayToBase64 ( aes128Encrypt ( sk , stringToUtf8Uint8Array ( "" ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , ENABLE_MAC ) ) ,
method : uint8ArrayToBase64 ( aes128Encrypt ( sk , stringToUtf8Uint8Array ( "" ) , random . generateRandomData ( IV_BYTE_LENGTH ) , true , ENABLE_MAC ) ) ,
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"
let recipientName = "Yahoo"
let gk = aes128RandomKey ( )
let sk = aes128RandomKey ( )
let mail = createMailLiteral ( gk , sk , subject , confidential , senderName , recipientName )
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" )
o ( decrypted . toRecipients [ 0 ] . name ) . equals ( recipientName )
o ( decrypted . toRecipients [ 0 ] . address ) . equals ( "support@yahoo.com" )
} )
} )
2021-03-04 17:41:40 +01:00
o ( "encrypt instance" , async function ( ) {
2017-08-15 13:54:22 +02:00
let sk = aes128RandomKey ( )
let address = createContactAddress ( )
address . type = "0"
address . address = "Entenhausen"
address . customTypeName = "0"
let contact = Contact . createContact ( )
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 )
2022-12-27 15:37:40 +01:00
o ( utf8Uint8ArrayToString ( aes128Decrypt ( sk , base64ToUint8Array ( result . addresses [ 0 ] . type ) ) ) ) . equals ( contact . addresses [ 0 ] . type )
o ( utf8Uint8ArrayToString ( aes128Decrypt ( sk , base64ToUint8Array ( result . addresses [ 0 ] . address ) ) ) ) . equals ( contact . addresses [ 0 ] . address )
o ( utf8Uint8ArrayToString ( aes128Decrypt ( sk , base64ToUint8Array ( result . addresses [ 0 ] . customTypeName ) ) ) ) . equals ( contact . addresses [ 0 ] . customTypeName )
2021-03-04 17:41:40 +01:00
o ( utf8Uint8ArrayToString ( aes128Decrypt ( sk , base64ToUint8Array ( result . title ) ) ) ) . equals ( contact . title )
o ( utf8Uint8ArrayToString ( aes128Decrypt ( sk , base64ToUint8Array ( result . firstName ) ) ) ) . equals ( contact . firstName )
o ( utf8Uint8ArrayToString ( aes128Decrypt ( sk , base64ToUint8Array ( result . lastName ) ) ) ) . equals ( contact . lastName )
o ( utf8Uint8ArrayToString ( aes128Decrypt ( sk , base64ToUint8Array ( result . comment ) ) ) ) . equals ( contact . comment )
o ( utf8Uint8ArrayToString ( aes128Decrypt ( sk , base64ToUint8Array ( result . company ) ) ) ) . equals ( contact . company )
2022-12-27 15:37:40 +01:00
o ( utf8Uint8ArrayToString ( aes128Decrypt ( 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 ( ) {
let userIdLiteral = {
_format : "0" ,
userId : "KOBqO7a----0" ,
}
2022-04-19 16:51:08 +02:00
const UserIdReturnTypeModel = await resolveTypeReference ( UserIdReturnTypeRef )
const userIdReturn : UserIdReturn.UserIdReturn = await instanceMapper . decryptAndMapToInstance ( UserIdReturnTypeModel , userIdLiteral , null )
2022-01-07 15:58:30 +01:00
o ( userIdReturn . _format ) . equals ( "0" )
o ( userIdReturn . userId ) . 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 ( ) {
2017-08-15 13:54:22 +02:00
let userIdReturn = createUserIdReturn ( )
userIdReturn . _format = "0"
userIdReturn . userId = "KOBqO7a----0"
2022-01-07 15:58:30 +01:00
let userIdLiteral = {
_format : "0" ,
userId : "KOBqO7a----0" ,
}
2022-04-19 16:51:08 +02:00
const UserIdReturnTypeModel = await resolveTypeReference ( UserIdReturnTypeRef )
2022-12-27 15:37:40 +01:00
return instanceMapper . encryptAndMapToLiteral ( UserIdReturnTypeModel , userIdReturn , null ) . then ( ( result ) = > {
2017-08-15 13:54:22 +02:00
o ( result ) . deepEquals ( userIdLiteral )
} )
} )
2022-03-09 17:43:29 +01:00
o ( "resolve session key: unencrypted instance" , async function ( ) {
const userIdLiteral = {
2022-01-07 15:58:30 +01:00
_format : "0" ,
userId : "KOBqO7a----0" ,
}
2022-04-19 16:51:08 +02:00
const UserIdReturnTypeModel = await resolveTypeReference ( UserIdReturnTypeRef )
o ( await crypto . resolveSessionKey ( UserIdReturnTypeModel , userIdLiteral ) ) . 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 ( ) {
2017-08-15 13:54:22 +02:00
let subject = "this is our subject"
let confidential = true
let senderName = "TutanotaTeam"
let recipientName = "Yahoo"
2022-01-07 15:58:30 +01:00
const gk = aes128RandomKey ( )
const sk = aes128RandomKey ( )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
when ( userFacade . getGroupKey ( "mailGroupId" ) ) . thenReturn ( gk )
2022-04-12 14:23:38 +02:00
const user = createUser ( {
userGroup : createGroupMembership ( {
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
group : "mailGroupId" ,
2022-12-27 15:37:40 +01:00
} ) ,
2022-03-09 17:43:29 +01:00
} )
Offline login
A lot of commits were squashed: these were the messages
Adjust for partial login state on the worker side, #3888
Co-authored-by: tih<tih@tutao.de>
Handle partial and full login on the client side, #3888
Co-authored-by: tih<tih@tutao.de>
Attempt to log in when coming online if async login fails, #3888
Co-authored-by: tih<tih@tutao.de>
Allow only Premium customers to log in offline, #3888
We return result from resumeLogin to not add a bespoke error class for
our use case. We cannot use UserError there either. We should probably
convert more expected errors to results as it's hard to know what
should be handled when we reach UI layer.
Co-authored-by: tih <tih@tutao.de>
Allow fixing credentials after offline login, #3888
Also improve progress display in password prompt dialog
Co-authored-by: tih <tih@tutao.de>
Allow re-initializing cache storage when the first login fails, #3888
Co-authored-by: tih<tih@tutao.de>
Improve LoginFacadeTest
Do not keep credentials for retry if they cannot be used again, #3888
Co-authored-by: tih<tih@tutao.de>
Fix initialising indexer from LoginFacade, #3888
Co-authored-by: tih<tih@tutao.de>
Add offlineLoginRequiresPremium_msg for de, de_sie, #3888
Cleanup facades fields after review with jom
Co-authored-by: tih <tih@tutao.de>
Cleanup UserFacade, fix tests
Co-authored-by: tih <tih@tutao.de>
Fix waiting for full login in LoginController
Co-authored-by: tih<tih@tutao.de>
Split AsyncActions into partial and full login
Co-authored-by: tih <tih@tutao.de>
Cleanup registering of post-login actions
Co-authored-by: tih <tih@tutao.de>
Change offlineDb parameter on CredentialsProvider after review with jom
Co-authored-by: tih <tih@tutao.de>
Remove out-of-sync handling on cache init
Current approach does not work in offline, we are going to reimplement
it.
See #4067
Suppress connection error during offline login, #3888
Do not wait for ConnectionError in LoginFacadeTest
* ConnectionError is suppressed in offline login
Prevent endless waiting for contacts after offline login, fix #4078
* When the user is logged in offline the indexer has not been initialized
and searching for contacts will never resolve.
Handle UserGroupKeyNotFoundError, see #4078
The userGroupKey is saved after login. However, when the user logs in
offline, the key is not saved and cannot be used to encrypt. We handle
this in the same way we handle ConnectionErrors.
2022-04-13 10:23:09 +02:00
when ( userFacade . isFullyLoggedIn ( ) ) . thenReturn ( true )
2022-04-12 14:23:38 +02:00
when ( userFacade . getLoggedInUser ( ) ) . thenReturn ( user )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
when ( userFacade . hasGroup ( "mailGroupId" ) ) . thenReturn ( true )
2022-03-09 17:43:29 +01:00
const mail = createMailLiteral ( gk , sk , subject , confidential , senderName , recipientName )
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
} )
2020-11-13 10:31:35 +01:00
o ( "resolve session key: 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
2017-08-15 13:54:22 +02:00
let subject = "this is our subject"
let confidential = true
let senderName = "TutanotaTeam"
let recipientName = "Yahoo"
let gk = aes128RandomKey ( )
let sk = aes128RandomKey ( )
let bk = aes128RandomKey ( )
let privateKey = hexToPrivateKey ( rsaPrivateHexKey )
let publicKey = hexToPublicKey ( rsaPublicHexKey )
2022-03-09 17:43:29 +01:00
const keyPair = createKeyPair ( {
_id : "keyPairId" ,
symEncPrivKey : encryptRsaKey ( gk , privateKey ) ,
2022-12-27 15:37:40 +01:00
pubKey : hexToUint8Array ( rsaPublicHexKey ) ,
2022-03-09 17:43:29 +01:00
} )
const userGroup = createGroup ( {
_id : "userGroupId" ,
2022-12-27 15:37:40 +01:00
keys : [ keyPair ] ,
2022-03-09 17:43:29 +01:00
} )
const mail = createMailLiteral ( gk , sk , subject , confidential , senderName , recipientName )
2022-01-07 15:58:30 +01:00
// @ts-ignore
2017-08-15 13:54:22 +02:00
mail . _ownerEncSessionKey = null
2022-03-09 17:43:29 +01:00
const bucket = createBucket ( {
2022-12-27 15:37:40 +01:00
bucketPermissions : "bucketPermissionListId" ,
2022-03-09 17:43:29 +01:00
} )
const permission = createPermission ( {
_id : [ "permissionListId" , "permissionId" ] ,
_ownerGroup : userGroup._id ,
bucketEncSessionKey : encryptKey ( bk , sk ) ,
bucket ,
type : PermissionType . Public ,
} )
2020-11-13 10:31:35 +01:00
const pubEncBucketKey = await rsaEncrypt ( publicKey , bitArrayToUint8Array ( bk ) )
2022-03-09 17:43:29 +01:00
const bucketPermission = createBucketPermission ( {
_id : [ "bucketPermissionListId" , "bucketPermissionId" ] ,
_ownerGroup : userGroup._id ,
type : BucketPermissionType . Public ,
group : userGroup._id ,
pubEncBucketKey ,
} )
const mem = createGroupMembership ( {
group : userGroup._id ,
} )
2022-04-12 14:23:38 +02:00
const user = createUser ( {
userGroup : mem ,
2022-01-07 15:58:30 +01:00
} )
2022-04-12 14:23:38 +02:00
when ( userFacade . getLoggedInUser ( ) ) . thenReturn ( user )
when ( userFacade . getGroupKey ( "userGroupId" ) ) . thenReturn ( gk )
when ( userFacade . isLeader ( ) ) . thenReturn ( true )
2022-03-09 17:43:29 +01:00
when ( entityClient . loadAll ( BucketPermissionTypeRef , getListId ( bucketPermission ) ) ) . thenResolve ( [ bucketPermission ] )
when ( entityClient . loadAll ( PermissionTypeRef , getListId ( permission ) ) ) . thenResolve ( [ permission ] )
when ( entityClient . load ( GroupTypeRef , userGroup . _id ) ) . thenResolve ( userGroup )
2022-12-27 15:37:40 +01:00
when (
serviceExecutor . post (
UpdatePermissionKeyService ,
matchers . argThat ( ( p : UpdatePermissionKeyData ) = > {
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
} )
2022-01-07 15:58:30 +01:00
o ( "decryption errors should be written to _errors field" , async function ( ) {
2017-08-15 13:54:22 +02:00
let subject = "this is our subject"
let confidential = true
let senderName = "TutanotaTeam"
let recipientName = "Yahoo"
let gk = aes128RandomKey ( )
let sk = aes128RandomKey ( )
let mail = createMailLiteral ( gk , sk , subject , confidential , senderName , recipientName )
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 ( ) {
when ( entityClient . update ( matchers . anything ( ) ) ) . thenResolve ( undefined )
} )
o ( "contact migration without birthday" , async function ( ) {
const contact = createContact ( )
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 )
verify ( entityClient . update ( matchers . anything ( ) ) , { times : 0 } )
} )
2022-03-09 17:43:29 +01:00
2023-01-12 16:48:28 +01:00
o ( "contact migration without existing birthday" , async function ( ) {
const contact = createContact ( {
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" )
verify ( entityClient . update ( matchers . anything ( ) ) , { times : 0 } )
} )
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 ( ) {
const contact = createContact ( {
_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 )
verify ( entityClient . update ( matchers . anything ( ) ) , { times : 1 } )
} )
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 ( ) {
const contact = createContact ( {
_id : [ "listid" , "id" ] ,
birthdayIso : "2019-05-01" ,
oldBirthdayAggregate : createBirthday ( {
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 )
verify ( entityClient . update ( matchers . anything ( ) ) , { times : 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 ( "contact migration from oldBirthdayAggregate" , async function ( ) {
const contact = createContact ( {
_id : [ "listid" , "id" ] ,
oldBirthdayDate : new Date ( 1800 , 4 , 1 ) ,
oldBirthdayAggregate : createBirthday ( {
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 )
verify ( entityClient . update ( matchers . anything ( ) ) , { times : 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 ( "contact migration from oldBirthdayDate" , async function ( ) {
const contact = createContact ( {
_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 )
verify ( entityClient . update ( matchers . anything ( ) ) , { times : 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 ( "contact migration from oldBirthdayAggregate without year" , async function ( ) {
const contact = createContact ( {
_id : [ "listid" , "id" ] ,
birthdayIso : null ,
oldBirthdayDate : null ,
oldBirthdayAggregate : createBirthday ( {
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 )
verify ( entityClient . update ( matchers . anything ( ) ) , { times : 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 ( "resolve session key: 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 preparePubEncBucketKeyResolveSessionKeyTest ( )
Object . assign ( testData . mailLiteral , { body : "bodyId" } )
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 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-01-12 16:48:28 +01:00
o ( sessionKey ) . deepEquals ( testData . sk )
o ( crypto . getSessionKeyCache ( ) [ "bodyId" ] ) . deepEquals ( testData . sk )
o ( Object . keys ( crypto . getSessionKeyCache ( ) ) . 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 ( "resolve session key: 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 preparePubEncBucketKeyResolveSessionKeyTest ( )
Object . assign ( testData . mailLiteral , { mailDetailsDraft : [ "draftDetailsListId" , "draftDetailsId" ] } )
const sessionKey = neverNull ( await crypto . resolveSessionKey ( testData . MailTypeModel , testData . mailLiteral ) )
o ( sessionKey ) . deepEquals ( testData . sk )
o ( crypto . getSessionKeyCache ( ) [ "draftDetailsId" ] ) . deepEquals ( testData . sk )
o ( Object . keys ( crypto . getSessionKeyCache ( ) ) . 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 (
"resolve session key: public key decryption of mail session key using BucketKey aggregated type - already decoded/decrypted Mail referencing MailDetailsDraft" ,
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
o . timeout ( 500 ) // in CI or with debugging it can take a while
const testData = await preparePubEncBucketKeyResolveSessionKeyTest ( )
2023-01-12 16:48:28 +01:00
Object . assign ( testData . mailLiteral , {
mailDetailsDraft : [ "draftDetailsListId" , "draftDetailsId" ] ,
} )
const mailInstance = await instanceMapper . decryptAndMapToInstance < Mail > ( testData . MailTypeModel , testData . mailLiteral , testData . sk )
// @ts-ignore
instanceMapper . decryptAndMapToInstance = o . spy ( instanceMapper . decryptAndMapToInstance )
crypto . convertBucketKeyToInstanceIfNecessary = o . 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-01-12 16:48:28 +01:00
const sessionKey = neverNull ( await crypto . resolveSessionKey ( testData . MailTypeModel , mailInstance ) )
o ( instanceMapper . decryptAndMapToInstance . callCount ) . equals ( 0 )
o ( crypto . convertBucketKeyToInstanceIfNecessary . callCount ) . 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
o ( sessionKey ) . deepEquals ( testData . sk )
o ( crypto . getSessionKeyCache ( ) [ "draftDetailsId" ] ) . deepEquals ( testData . sk )
o ( Object . keys ( crypto . getSessionKeyCache ( ) ) . length ) . equals ( 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 ( "resolve session key: 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 preparePubEncBucketKeyResolveSessionKeyTest ( )
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-01-12 16:48:28 +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-01-12 16:48:28 +01:00
o ( sessionKey ) . deepEquals ( testData . sk )
o ( crypto . getSessionKeyCache ( ) [ "mailDetailsId" ] ) . deepEquals ( testData . sk )
o ( Object . keys ( crypto . getSessionKeyCache ( ) ) . length ) . equals ( 1 )
} )
2022-03-09 17:43:29 +01:00
2023-01-12 16:48:28 +01:00
o (
"resolve session key: public key decryption of session key using BucketKey aggregated type - Mail referencing MailDetailsBlob with attachments" ,
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
o . timeout ( 500 ) // in CI or with debugging it can take a while
2023-01-12 16:48:28 +01:00
const file1SessionKey = aes128RandomKey ( )
const file2SessionKey = aes128RandomKey ( )
const testData = await preparePubEncBucketKeyResolveSessionKeyTest ( [ file1SessionKey , file2SessionKey ] )
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-01-12 16:48:28 +01:00
const mailSessionKey = neverNull ( await crypto . resolveSessionKey ( testData . MailTypeModel , testData . mailLiteral ) )
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-01-12 16:48:28 +01:00
o ( Object . keys ( crypto . getSessionKeyCache ( ) ) . length ) . equals ( 3 )
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 ( crypto . getSessionKeyCache ( ) [ "mailDetailsId" ] ) . deepEquals ( testData . sk )
2023-01-12 16:48:28 +01:00
o ( crypto . getSessionKeyCache ( ) [ "fileId1" ] ) . deepEquals ( file1SessionKey )
o ( crypto . getSessionKeyCache ( ) [ "fileId2" ] ) . deepEquals ( file2SessionKey )
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 )
testData . bucketKey . bucketEncSessionKeys . forEach ( ( isk ) = > {
isk . symEncSessionKey = encryptKey ( testData . mailGroupKey , decryptKey ( testData . bk , isk . symEncSessionKey ) )
o (
updatedInstanceSessionKeys . some (
( updatedKey ) = >
updatedKey . instanceId === isk . instanceId &&
updatedKey . instanceList === isk . instanceList &&
updatedKey . typeInfo . application === isk . typeInfo . application &&
updatedKey . typeInfo . typeId === isk . typeInfo . typeId &&
arrayEquals ( updatedKey . symEncSessionKey , isk . symEncSessionKey ) ,
) ,
) . 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-01-12 16:48:28 +01:00
o ( "resolve session key: file session key is only removed if the file does have an ownerEncSessionKey" , async function ( ) {
o . timeout ( 500 ) // in CI or with debugging it can take a while
const file1SessionKey = aes128RandomKey ( )
const testData = await preparePubEncBucketKeyResolveSessionKeyTest ( [ file1SessionKey ] )
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-01-12 16:48:28 +01:00
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-01-12 16:48:28 +01:00
const FileTypeModel = await resolveTypeReference ( FileTypeRef )
add MailDetails feature, #4719
server issues: 1276, 1271, 1279, 1272, 1270, 1258, 1254, 1253, 1242, 1241
2022-11-03 19:03:54 +01:00
2023-01-12 16:48:28 +01:00
let fileInstanceNoOwnerEncSessionKey = createFile ( { _id : [ "fileListId" , "fileId1" ] , _ownerEncSessionKey : 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
let fileSessionKey = neverNull ( await crypto . resolveSessionKey ( FileTypeModel , fileInstanceNoOwnerEncSessionKey ) )
o ( fileSessionKey ) . deepEquals ( file1SessionKey )
o ( crypto . getSessionKeyCache ( ) [ "fileId1" ] ) . deepEquals ( file1SessionKey )
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 fileInstanceWithOwnerEncSessionKey = createFile ( { _id : [ "fileListId" , "fileId1" ] , _ownerEncSessionKey : new Uint8Array ( [ 1 , 2 , 3 ] ) } )
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
fileSessionKey = neverNull ( await crypto . resolveSessionKey ( FileTypeModel , fileInstanceWithOwnerEncSessionKey ) )
o ( fileSessionKey ) . deepEquals ( file1SessionKey )
o ( crypto . getSessionKeyCache ( ) [ "fileId1" ] ) . equals ( undefined )
} )
} )
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 (
"resolve session key: external user key decryption of session key using BucketKey aggregated type - Mail referencing MailDetailsBlob with attachments" ,
async function ( ) {
o . timeout ( 500 ) // in CI or with debugging it can take a while
const file1SessionKey = aes128RandomKey ( )
const file2SessionKey = aes128RandomKey ( )
const testData = await prepareSymEncBucketKeyResolveSessionKeyTest ( [ 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
const mailSessionKey = neverNull ( await crypto . resolveSessionKey ( testData . MailTypeModel , testData . mailLiteral ) )
o ( mailSessionKey ) . deepEquals ( testData . sk )
o ( Object . keys ( crypto . getSessionKeyCache ( ) ) . length ) . equals ( 3 )
o ( crypto . getSessionKeyCache ( ) [ "mailDetailsId" ] ) . deepEquals ( testData . sk )
o ( crypto . getSessionKeyCache ( ) [ "fileId1" ] ) . deepEquals ( file1SessionKey )
o ( crypto . getSessionKeyCache ( ) [ "fileId2" ] ) . deepEquals ( file2SessionKey )
} ,
)
o ( "resolve session key from cache: MailDetailsBlob" , async function ( ) {
const sk = aes128RandomKey ( )
crypto . getSessionKeyCache ( ) [ "mailDetailsId" ] = sk
const MailDetailsBlobTypeModel = await resolveTypeReference ( MailDetailsBlobTypeRef )
const mailDetailsBlobLiteral = {
_id : [ "mailDetailsArchiveId" , "mailDetailsId" ] ,
}
const mailDetailsBlobSessionKey = neverNull ( await crypto . resolveSessionKey ( MailDetailsBlobTypeModel , mailDetailsBlobLiteral ) )
o ( mailDetailsBlobSessionKey ) . deepEquals ( sk )
2023-01-17 15:42:18 +01:00
o ( Object . keys ( crypto . getSessionKeyCache ( ) ) . 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
} )
o ( "resolve session key from cache: MailDetailsBlob - session key not found" , async function ( ) {
const sk = aes128RandomKey ( )
crypto . getSessionKeyCache ( ) [ "otherMailDetailsId" ] = sk
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 )
}
o ( Object . keys ( crypto . getSessionKeyCache ( ) ) . length ) . equals ( 1 )
} )
/ * *
* Prepares the environment to test receiving 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 preparePubEncBucketKeyResolveSessionKeyTest ( fileSessionKeys : Array < Aes128Key > = [ ] ) : Promise < {
mailLiteral : Record < string , any >
bucketKey : BucketKey
sk : Aes128Key
bk : Aes128Key
mailGroupKey : Aes128Key
MailTypeModel : TypeModel
} > {
let subject = "this is our subject"
let confidential = true
let senderName = "TutanotaTeam"
let recipientName = "Yahoo"
let mailGk = aes128RandomKey ( )
let userGk = aes128RandomKey ( )
let sk = aes128RandomKey ( )
let bk = aes128RandomKey ( )
let privateKey = hexToPrivateKey ( rsaPrivateHexKey )
let publicKey = hexToPublicKey ( rsaPublicHexKey )
const keyPair = createKeyPair ( {
_id : "keyPairId" ,
symEncPrivKey : encryptRsaKey ( userGk , privateKey ) ,
pubKey : hexToUint8Array ( rsaPublicHexKey ) ,
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
const userGroup = createGroup ( {
_id : "userGroupId" ,
keys : [ keyPair ] ,
} )
const mailLiteral = createMailLiteral ( mailGk , sk , subject , confidential , senderName , recipientName )
// @ts-ignore
mailLiteral . _ownerEncSessionKey = null
const pubEncBucketKey = await rsaEncrypt ( publicKey , bitArrayToUint8Array ( bk ) )
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
const mailInstanceSessionKey = createInstanceSessionKey ( {
typeInfo : createTypeInfo ( {
application : MailTypeModel.app ,
typeId : String ( MailTypeModel . id ) ,
} ) ,
symEncSessionKey : bucketEncMailSessionKey ,
instanceList : "mailListId" ,
instanceId : "mailId" ,
} )
const FileTypeModel = await resolveTypeReference ( FileTypeRef )
const bucketEncSessionKeys = fileSessionKeys . map ( ( fileSessionKey , index ) = > {
return createInstanceSessionKey ( {
typeInfo : createTypeInfo ( {
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 )
const bucketKey = createBucketKey ( {
pubEncBucketKey : pubEncBucketKey ,
pubKeyGroup : userGroup._id ,
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
const mem = createGroupMembership ( {
group : userGroup._id ,
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
const user = createUser ( {
userGroup : mem ,
} )
when ( userFacade . getLoggedInUser ( ) ) . thenReturn ( user )
when ( userFacade . getGroupKey ( "userGroupId" ) ) . thenReturn ( userGk )
when ( userFacade . getGroupKey ( "mailGroupId" ) ) . thenReturn ( mailGk )
when ( userFacade . isLeader ( ) ) . thenReturn ( true )
when ( entityClient . load ( GroupTypeRef , userGroup . _id ) ) . thenResolve ( userGroup )
return {
mailLiteral ,
bucketKey ,
sk ,
bk ,
mailGroupKey : mailGk ,
MailTypeModel ,
}
}
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
* /
async function prepareSymEncBucketKeyResolveSessionKeyTest ( fileSessionKeys : Array < Aes128Key > = [ ] ) : Promise < {
mailLiteral : Record < string , any >
sk : Aes128Key
bk : Aes128Key
MailTypeModel : TypeModel
} > {
let subject = "this is our subject"
let confidential = true
let senderName = "TutanotaTeam"
let recipientName = "Yahoo"
let gk = aes128RandomKey ( )
let sk = aes128RandomKey ( )
let bk = aes128RandomKey ( )
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 userGroup = createGroup ( {
_id : "userGroupId" ,
keys : [ ] ,
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
const mailLiteral = createMailLiteral ( gk , sk , subject , confidential , senderName , recipientName )
// @ts-ignore
mailLiteral . _ownerEncSessionKey = null
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
const ownerEncBucketKey = encryptKey ( gk , 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" ,
} )
const FileTypeModel = await resolveTypeReference ( FileTypeRef )
const bucketEncSessionKeys = fileSessionKeys . map ( ( fileSessionKey , index ) = > {
return createInstanceSessionKey ( {
typeInfo : createTypeInfo ( {
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
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 bucketKey = createBucketKey ( {
pubEncBucketKey : null ,
pubKeyGroup : null ,
ownerEncBucketKey : ownerEncBucketKey ,
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
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 mem = createGroupMembership ( {
group : userGroup._id ,
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
const user = createUser ( {
userGroup : mem ,
} )
when ( userFacade . getLoggedInUser ( ) ) . thenReturn ( user )
when ( userFacade . getGroupKey ( "mailGroupId" ) ) . thenReturn ( gk )
when ( userFacade . isLeader ( ) ) . thenReturn ( true )
when ( entityClient . load ( GroupTypeRef , userGroup . _id ) ) . thenResolve ( userGroup )
return {
mailLiteral ,
sk ,
bk ,
MailTypeModel ,
}
}
2022-12-27 15:37:40 +01:00
} )