How to use context method of io.kotest.core.spec.style.scopes.ShouldSpecContainerScope class

Best Kotest code snippet using io.kotest.core.spec.style.scopes.ShouldSpecContainerScope.context

OlmEventServiceTest.kt

Source:OlmEventServiceTest.kt Github

copy

Full Screen

...145 mapOf(bob to mapOf(bobDeviceId to keysOf(bobsFakeSignedCurveKey)))146 )147 }148 }149 context(OlmEventService::handleOlmEncryptedToDeviceEvents.name) {150 context("exceptions") {151 val event = Event.ToDeviceEvent(152 OlmEncryptedEventContent(153 mapOf(), Curve25519Key(null, "")154 ),155 UserId("sender", "server")156 )157 should("catch exceptions") {158 cut.handleOlmEncryptedToDeviceEvents(event)159 }160 }161 should("emit decrypted events") {162 freeAfter(OlmUtility.create()) { olmUtility ->163 val bobStore = InMemoryStore(storeScope).apply { init() }164 val bobOlmService =165 OlmService("", bob, bobDeviceId, bobStore, api, json, bobAccount, olmUtility)166 store.olm.storeAccount(aliceAccount, "")167 val aliceSignService = OlmSignService(alice, aliceDeviceId, json, store, aliceAccount, olmUtility)168 val cutWithAccount = OlmEventService(169 "",170 alice,171 aliceDeviceId,172 Ed25519Key(null, aliceAccount.identityKeys.ed25519),173 Curve25519Key(null, aliceAccount.identityKeys.curve25519),174 json,175 aliceAccount,176 store,177 api,178 aliceSignService179 )180 store.keys.updateDeviceKeys(bob) {181 mapOf(182 bobDeviceId to StoredDeviceKeys(183 Signed(184 DeviceKeys(185 userId = bob,186 deviceId = bobDeviceId,187 algorithms = setOf(EncryptionAlgorithm.Olm, EncryptionAlgorithm.Megolm),188 keys = Keys(189 keysOf(190 bobOlmService.getSelfSignedDeviceKeys().signed.get<Curve25519Key>()!!,191 bobOlmService.getSelfSignedDeviceKeys().signed.get<Ed25519Key>()!!192 )193 )194 ), mapOf()195 ), KeySignatureTrustLevel.Valid(true)196 )197 )198 }199 bobStore.keys.updateDeviceKeys(alice) {200 mapOf(201 aliceDeviceId to StoredDeviceKeys(202 Signed(203 DeviceKeys(204 userId = alice,205 deviceId = aliceDeviceId,206 algorithms = setOf(EncryptionAlgorithm.Olm, EncryptionAlgorithm.Megolm),207 keys = Keys(208 keysOf(209 Curve25519Key(null, aliceAccount.identityKeys.curve25519),210 Ed25519Key(null, aliceAccount.identityKeys.ed25519)211 )212 )213 ), mapOf()214 ), KeySignatureTrustLevel.Valid(true)215 )216 )217 }218 apiConfig.endpoints {219 matrixJsonEndpoint(json, mappings, ClaimKeys()) {220 it.oneTimeKeys shouldBe mapOf(alice to mapOf(aliceDeviceId to KeyAlgorithm.SignedCurve25519))221 ClaimKeys.Response(222 emptyMap(),223 mapOf(224 alice to mapOf(225 aliceDeviceId to keysOf(226 aliceSignService.signCurve25519Key(227 Curve25519Key(228 aliceDeviceId,229 aliceAccount.getOneTimeKey()230 )231 )232 )233 )234 )235 )236 }237 }238 val outboundSession = OlmOutboundGroupSession.create()239 val eventContent = RoomKeyEventContent(240 RoomId("room", "server"),241 outboundSession.sessionId,242 outboundSession.sessionKey,243 EncryptionAlgorithm.Megolm244 )245 val encryptedEvent = Event.ToDeviceEvent(246 bobOlmService.event.encryptOlm(247 eventContent,248 alice,249 aliceDeviceId250 ), bob251 )252 val emittedEvent = async { cutWithAccount.decryptedOlmEvents.first() }253 delay(50)254 cutWithAccount.handleOlmEncryptedToDeviceEvents(encryptedEvent)255 assertSoftly(256 emittedEvent.await()257 ) {258 assertNotNull(this)259 encrypted shouldBe encryptedEvent260 decrypted shouldBe DecryptedOlmEvent(261 eventContent,262 bob,263 keysOf(bobOlmService.getSelfSignedDeviceKeys().signed.get<Ed25519Key>()!!.copy(keyId = null)),264 alice,265 keysOf(Ed25519Key(null, aliceAccount.identityKeys.ed25519))266 )267 }268 }269 }270 }271 context(OlmEventService::encryptOlm.name) {272 val eventContent = RoomKeyEventContent(273 RoomId("room", "server"),274 "sessionId",275 "sessionKey",276 EncryptionAlgorithm.Megolm,277 )278 lateinit var decryptedOlmEvent: DecryptedOlmEvent<RoomKeyEventContent>279 beforeEach {280 decryptedOlmEvent = DecryptedOlmEvent(281 content = eventContent,282 sender = alice,283 senderKeys = keysOf(aliceEdKey.copy(keyId = null)),284 recipient = bob,285 recipientKeys = keysOf(bobEdKey.copy(keyId = null))286 )287 }288 context("without stored olm encrypt session") {289 beforeEach {290 apiConfig.endpoints { claimKeysEndpoint() }291 }292 should("encrypt") {293 val encryptedMessage = cut.encryptOlm(eventContent, bob, bobDeviceId)294 val encryptedCipherText = encryptedMessage.ciphertext[bobCurveKey.value]295 assertNotNull(encryptedCipherText)296 encryptedMessage.senderKey shouldBe aliceCurveKey297 encryptedCipherText.type shouldBe INITIAL_PRE_KEY298 freeAfter(299 OlmSession.createInboundFrom(300 account = bobAccount,301 identityKey = aliceCurveKey.value,302 oneTimeKeyMessage = encryptedCipherText.body303 )304 ) { bobSession ->305 json.decodeFromString(306 decryptedOlmEventSerializer,307 bobSession.decrypt(OlmMessage(encryptedCipherText.body, OlmMessageType.INITIAL_PRE_KEY))308 ) shouldBe decryptedOlmEvent309 }310 store.olm.getOlmSessions(bobCurveKey)!! shouldHaveSize 1311 }312 should("throw exception when one time key is invalid") {313 signService.returnVerify = VerifyResult.Invalid("dino")314 shouldThrow<KeyException.KeyVerificationFailedException> {315 cut.encryptOlm(eventContent, bob, bobDeviceId).ciphertext.entries.first().value316 }.message shouldBe "dino"317 store.olm.getOlmSessions(bobCurveKey) should beNull()318 }319 }320 context("with stored olm encrypt session") {321 should("encrypt event with stored session") {322 freeAfter(323 OlmSession.createOutbound(324 bobAccount,325 aliceCurveKey.value,326 aliceAccount.getOneTimeKey()327 )328 ) { bobSession ->329 val storedOlmSession = freeAfter(330 OlmSession.createInbound(aliceAccount, bobSession.encrypt("first message").cipherText)331 ) { aliceSession ->332 StoredOlmSession(333 bobCurveKey,334 aliceSession.sessionId,335 Clock.System.now(),336 Clock.System.now(),337 aliceSession.pickle("")338 )339 }340 store.olm.updateOlmSessions(bobCurveKey) { setOf(storedOlmSession) }341 val encryptedMessage = cut.encryptOlm(eventContent, bob, bobDeviceId)342 val encryptedCipherText = encryptedMessage.ciphertext[bobCurveKey.value]343 assertNotNull(encryptedCipherText)344 encryptedMessage.senderKey shouldBe aliceCurveKey345 encryptedCipherText.type shouldBe INITIAL_PRE_KEY346 json.decodeFromString(347 decryptedOlmEventSerializer,348 bobSession.decrypt(349 OlmMessage(350 encryptedCipherText.body,351 OlmMessageType.INITIAL_PRE_KEY352 )353 )354 ) shouldBe decryptedOlmEvent355 store.olm.getOlmSessions(bobCurveKey)!! shouldHaveSize 1356 store.olm.getOlmSessions(bobCurveKey)?.first() shouldNotBe storedOlmSession357 }358 }359 }360 }361 context(OlmEventService::decryptOlm.name) {362 val eventContent = RoomKeyEventContent(363 RoomId("room", "server"),364 "sessionId",365 "sessionKey",366 EncryptionAlgorithm.Megolm367 )368 lateinit var decryptedOlmEvent: DecryptedOlmEvent<RoomKeyEventContent>369 beforeEach {370 decryptedOlmEvent = DecryptedOlmEvent(371 content = eventContent,372 sender = bob,373 senderKeys = keysOf(bobEdKey),374 recipient = alice,375 recipientKeys = keysOf(aliceEdKey)376 )377 }378 context("without stored decrypt olm session") {379 should("decrypt pre key message from new session") {380 val encryptedMessage = freeAfter(381 OlmSession.createOutbound(382 bobAccount,383 aliceCurveKey.value,384 aliceAccount.getOneTimeKey()385 )386 ) { bobSession ->387 bobSession.encrypt(json.encodeToString(decryptedOlmEventSerializer, decryptedOlmEvent))388 }389 cut.decryptOlm(390 OlmEncryptedEventContent(391 ciphertext = mapOf(392 aliceCurveKey.value to CiphertextInfo(encryptedMessage.cipherText, INITIAL_PRE_KEY)393 ),394 senderKey = bobCurveKey395 ), bob396 ) shouldBe decryptedOlmEvent397 store.olm.getOlmSessions(bobCurveKey)!! shouldHaveSize 1398 // we check, that the one time key cannot be used twice399 shouldThrow<OlmLibraryException> {400 OlmSession.createInboundFrom(aliceAccount, bobCurveKey.value, encryptedMessage.cipherText)401 }402 }403 should("not decrypt pre key message, when the 5 last created sessions are not older then 1 hour") {404 val encryptedMessage = freeAfter(405 OlmSession.createOutbound(406 bobAccount,407 aliceCurveKey.value,408 aliceAccount.getOneTimeKey()409 )410 ) { bobSession ->411 bobSession.encrypt(json.encodeToString(decryptedOlmEventSerializer, decryptedOlmEvent))412 }413 repeat(5) { pseudoSessionId ->414 freeAfter(OlmAccount.create()) { dummyAccount ->415 freeAfter(416 OlmSession.createOutbound(417 aliceAccount,418 dummyAccount.identityKeys.curve25519,419 dummyAccount.getOneTimeKey()420 )421 ) { aliceSession ->422 val storedOlmSession = StoredOlmSession(423 bobCurveKey,424 pseudoSessionId.toString(),425 Clock.System.now(),426 Clock.System.now(),427 aliceSession.pickle("")428 )429 store.olm.updateOlmSessions(bobCurveKey) {430 it?.plus(storedOlmSession) ?: setOf(431 storedOlmSession432 )433 }434 }435 }436 }437 shouldThrow<SessionException.PreventToManySessions> {438 cut.decryptOlm(439 OlmEncryptedEventContent(440 ciphertext = mapOf(441 aliceCurveKey.value to CiphertextInfo(encryptedMessage.cipherText, INITIAL_PRE_KEY)442 ),443 senderKey = bobCurveKey444 ), bob445 )446 }447 }448 should("throw on ordinary message") {449 var sendToDeviceEvents: Map<UserId, Map<String, ToDeviceEventContent>>? = null450 apiConfig.endpoints {451 claimKeysEndpoint()452 matrixJsonEndpoint(453 json, mappings,454 SendToDevice("m.room.encrypted", "txn"),455 skipUrlCheck = true456 ) {457 sendToDeviceEvents = it.messages458 }459 }460 val encryptedMessage = freeAfter(461 OlmSession.createOutbound(462 bobAccount,463 aliceCurveKey.value,464 aliceAccount.getOneTimeKey()465 )466 ) { bobSession ->467 bobSession.encrypt(json.encodeToString(decryptedOlmEventSerializer, decryptedOlmEvent))468 }469 shouldThrow<SessionException.CouldNotDecrypt> {470 cut.decryptOlm(471 OlmEncryptedEventContent(472 ciphertext = mapOf(473 aliceCurveKey.value to CiphertextInfo(encryptedMessage.cipherText, ORDINARY)474 ),475 senderKey = bobCurveKey476 ), bob477 )478 }479 val encryptedEventContent =480 sendToDeviceEvents?.get(bob)?.get(bobDeviceId)?.shouldBeInstanceOf<OlmEncryptedEventContent>()481 val ciphertext = encryptedEventContent?.ciphertext?.get(bobCurveKey.value)?.body482 assertNotNull(ciphertext)483 freeAfter(OlmSession.createInbound(bobAccount, ciphertext)) { session ->484 json.decodeFromString(485 decryptedOlmEventSerializer,486 session.decrypt(OlmMessage(ciphertext, OlmMessageType.INITIAL_PRE_KEY))487 ).content shouldBe DummyEventContent488 }489 }490 }491 context("with stored decrypt olm session") {492 should("decrypt pre key message from stored session") {493 freeAfter(494 OlmSession.createOutbound(495 aliceAccount,496 bobCurveKey.value,497 bobAccount.getOneTimeKey()498 )499 ) { aliceSession ->500 val firstMessage = aliceSession.encrypt("first message")501 val encryptedMessage = freeAfter(502 OlmSession.createInbound(bobAccount, firstMessage.cipherText)503 ) { bobSession ->504 // we do not decrypt the message, so the next is an initial pre key message505 bobSession.encrypt(json.encodeToString(decryptedOlmEventSerializer, decryptedOlmEvent))506 }507 val storedOlmSession = StoredOlmSession(508 bobCurveKey,509 aliceSession.sessionId,510 Clock.System.now(),511 Clock.System.now(),512 aliceSession.pickle("")513 )514 store.olm.updateOlmSessions(bobCurveKey) { setOf(storedOlmSession) }515 cut.decryptOlm(516 OlmEncryptedEventContent(517 ciphertext = mapOf(518 aliceCurveKey.value to CiphertextInfo(encryptedMessage.cipherText, INITIAL_PRE_KEY)519 ),520 senderKey = bobCurveKey521 ), bob522 ) shouldBe decryptedOlmEvent523 store.olm.getOlmSessions(bobCurveKey)?.first() shouldNotBe storedOlmSession524 }525 }526 should("decrypt ordinary message") {527 freeAfter(528 OlmSession.createOutbound(529 aliceAccount,530 bobCurveKey.value,531 bobAccount.getOneTimeKey()532 )533 ) { aliceSession ->534 val firstMessage = aliceSession.encrypt("first message")535 val encryptedMessage = freeAfter(536 OlmSession.createInbound(bobAccount, firstMessage.cipherText)537 ) { bobSession ->538 bobSession.decrypt(firstMessage)539 bobSession.encrypt(json.encodeToString(decryptedOlmEventSerializer, decryptedOlmEvent))540 }541 val storedOlmSession = StoredOlmSession(542 bobCurveKey,543 aliceSession.sessionId,544 Clock.System.now(),545 Clock.System.now(),546 aliceSession.pickle("")547 )548 store.olm.updateOlmSessions(bobCurveKey) { setOf(storedOlmSession) }549 cut.decryptOlm(550 OlmEncryptedEventContent(551 ciphertext = mapOf(552 aliceCurveKey.value to CiphertextInfo(encryptedMessage.cipherText, ORDINARY)553 ),554 senderKey = bobCurveKey555 ), bob556 ) shouldBe decryptedOlmEvent557 store.olm.getOlmSessions(bobCurveKey)?.first() shouldNotBe storedOlmSession558 }559 }560 should("try multiple sessions descended by last used") {561 freeAfter(562 OlmSession.createOutbound(aliceAccount, bobCurveKey.value, bobAccount.getOneTimeKey()),563 OlmSession.createOutbound(aliceAccount, bobCurveKey.value, bobAccount.getOneTimeKey()),564 OlmSession.createOutbound(aliceAccount, bobCurveKey.value, bobAccount.getOneTimeKey()),565 ) { aliceSession1, aliceSession2, aliceSession3 ->566 val firstMessage = aliceSession1.encrypt("first message")567 val encryptedMessage = freeAfter(568 OlmSession.createInbound(bobAccount, firstMessage.cipherText)569 ) { bobSession ->570 bobSession.decrypt(firstMessage)571 bobSession.encrypt(json.encodeToString(decryptedOlmEventSerializer, decryptedOlmEvent))572 }573 val storedOlmSession1 = StoredOlmSession(574 bobCurveKey,575 aliceSession1.sessionId,576 Clock.System.now(),577 Clock.System.now(),578 aliceSession1.pickle("")579 )580 val storedOlmSession2 = StoredOlmSession(581 bobCurveKey,582 aliceSession2.sessionId,583 fromEpochMilliseconds(24),584 Clock.System.now(),585 aliceSession2.pickle("")586 )587 val storedOlmSession3 = StoredOlmSession(588 bobCurveKey,589 aliceSession3.sessionId,590 Clock.System.now(),591 Clock.System.now(),592 aliceSession3.pickle("")593 )594 store.olm.updateOlmSessions(bobCurveKey) {595 setOf(596 storedOlmSession2,597 storedOlmSession1,598 storedOlmSession3599 )600 }601 cut.decryptOlm(602 OlmEncryptedEventContent(603 ciphertext = mapOf(604 aliceCurveKey.value to CiphertextInfo(encryptedMessage.cipherText, ORDINARY)605 ),606 senderKey = bobCurveKey607 ), bob608 ) shouldBe decryptedOlmEvent609 store.olm.getOlmSessions(bobCurveKey)!! shouldNotContain storedOlmSession1610 }611 }612 }613 context("handle olm event with manipulated") {614 suspend fun ContainerScope.handleManipulation(manipulatedOlmEvent: DecryptedOlmEvent<RoomKeyEventContent>) {615 val job1 = launch {616 store.keys.outdatedKeys.first { it.isNotEmpty() }617 store.keys.outdatedKeys.value = setOf()618 }619 freeAfter(620 OlmSession.createOutbound(621 aliceAccount,622 bobCurveKey.value,623 bobAccount.getOneTimeKey()624 )625 ) { aliceSession ->626 val firstMessage = aliceSession.encrypt("first message")627 val encryptedMessage = freeAfter(628 OlmSession.createInbound(bobAccount, firstMessage.cipherText)629 ) { bobSession ->630 bobSession.decrypt(firstMessage)631 bobSession.encrypt(json.encodeToString(decryptedOlmEventSerializer, manipulatedOlmEvent))632 }633 val storedOlmSession = StoredOlmSession(634 bobCurveKey,635 aliceSession.sessionId,636 Clock.System.now(),637 Clock.System.now(),638 aliceSession.pickle("")639 )640 store.olm.updateOlmSessions(bobCurveKey) { setOf(storedOlmSession) }641 shouldThrow<DecryptionException> {642 cut.decryptOlm(643 OlmEncryptedEventContent(644 ciphertext = mapOf(645 aliceCurveKey.value to CiphertextInfo(encryptedMessage.cipherText, ORDINARY)646 ),647 senderKey = bobCurveKey648 ), bob649 )650 }651 }652 job1.cancel()653 }654 should("sender") {655 handleManipulation(decryptedOlmEvent.copy(sender = UserId("cedric", "server")))656 }657 should("senderKeys") {658 handleManipulation(decryptedOlmEvent.copy(senderKeys = keysOf(Ed25519Key("CEDRICKEY", "cedrics key"))))659 }660 should("recipient") {661 handleManipulation(decryptedOlmEvent.copy(recipient = UserId("cedric", "server")))662 }663 should("recipientKeys") {664 handleManipulation(665 decryptedOlmEvent.copy(recipientKeys = keysOf(Ed25519Key("CEDRICKEY", "cedrics key")))666 )667 }668 }669 }670 context(OlmEventService::encryptMegolm.name) {671 val eventContent = TextMessageEventContent("Hi", relatesTo = relatesTo)672 val room = RoomId("room", "server")673 val decryptedMegolmEvent = DecryptedMegolmEvent(eventContent, room)674 beforeEach {675 store.room.update(room) { Room(room, membership = JOIN, membersLoaded = true) }676 listOf(677 StateEvent(678 MemberEventContent(membership = JOIN),679 EventId("\$event1"),680 alice,681 room,682 1234,683 stateKey = alice.full684 ),685 StateEvent(686 MemberEventContent(membership = JOIN),687 EventId("\$event2"),688 bob,689 room,690 1235,691 stateKey = bob.full692 )693 ).forEach { store.roomState.update(it) }694 }695 suspend fun ShouldSpecContainerScope.testEncryption(696 settings: EncryptionEventContent,697 expectedMessageCount: Int,698 ) {699 should("encrypt message") {700 var sendToDeviceEvents: Map<UserId, Map<String, ToDeviceEventContent>>? = null701 apiConfig.endpoints {702 claimKeysEndpoint()703 matrixJsonEndpoint(704 json, mappings,705 SendToDevice("m.room.encrypted", "txn"),706 skipUrlCheck = true707 ) {708 sendToDeviceEvents = it.messages709 }710 }711 store.keys.outdatedKeys.value = setOf(bob)712 val asyncResult = async { cut.encryptMegolm(eventContent, room, settings) }713 store.keys.outdatedKeys.subscriptionCount.takeWhile { it == 1 }.take(1).collect()714 asyncResult.isActive shouldBe true715 store.keys.outdatedKeys.value = setOf()716 val result = asyncResult.await()717 val storedOutboundSession = store.olm.getOutboundMegolmSession(room)718 assertNotNull(storedOutboundSession)719 assertSoftly(storedOutboundSession) {720 encryptedMessageCount shouldBe expectedMessageCount721 roomId shouldBe room722 }723 freeAfter(OlmOutboundGroupSession.unpickle("", storedOutboundSession.pickled)) { outboundSession ->724 assertSoftly(result) {725 senderKey shouldBe aliceCurveKey726 deviceId shouldBe aliceDeviceId727 sessionId shouldBe outboundSession.sessionId728 this.relatesTo shouldBe relatesTo729 }730 val ciphertext =731 sendToDeviceEvents?.get(bob)?.get(bobDeviceId)?.shouldBeInstanceOf<OlmEncryptedEventContent>()732 ?.ciphertext?.get(bobCurveKey.value)?.body733 assertNotNull(ciphertext)734 freeAfter(OlmSession.createInbound(bobAccount, ciphertext)) { session ->735 assertSoftly(736 json.decodeFromString(737 decryptedOlmEventSerializer,738 session.decrypt(OlmMessage(ciphertext, OlmMessageType.INITIAL_PRE_KEY))739 ).content740 ) {741 require(this is RoomKeyEventContent)742 roomId shouldBe room743 sessionId shouldBe outboundSession.sessionId744 }745 }746 val storedInboundSession =747 store.olm.getInboundMegolmSession(748 aliceCurveKey,749 outboundSession.sessionId,750 room,751 this752 ).value753 assertNotNull(storedInboundSession)754 assertSoftly(storedInboundSession) {755 sessionId shouldBe outboundSession.sessionId756 senderKey shouldBe aliceCurveKey757 roomId shouldBe room758 }759 freeAfter(OlmInboundGroupSession.unpickle("", storedInboundSession.pickled)) { inboundSession ->760 json.decodeFromString(761 decryptedMegolmEventSerializer, inboundSession.decrypt(result.ciphertext).message762 ) shouldBe decryptedMegolmEvent763 }764 }765 }766 }767 context("without stored megolm session") {768 testEncryption(EncryptionEventContent(), 1)769 should("not send room keys, when not possible to encrypt them due to missing one time keys") {770 val otherRoom = RoomId("otherRoom", "server")771 store.room.update(otherRoom) { Room(otherRoom, membership = JOIN, membersLoaded = true) }772 val cedric = UserId("cedric", "server")773 listOf(774 StateEvent(775 MemberEventContent(membership = JOIN),776 EventId("\$event1"),777 alice,778 otherRoom,779 1234,780 stateKey = alice.full781 ),782 StateEvent(783 MemberEventContent(membership = JOIN),784 EventId("\$event2"),785 cedric,786 otherRoom,787 1235,788 stateKey = cedric.full789 )790 ).forEach { store.roomState.update(it) }791 store.keys.outdatedKeys.value = setOf(cedric)792 val asyncResult = async { cut.encryptMegolm(eventContent, otherRoom, EncryptionEventContent()) }793 store.keys.outdatedKeys.subscriptionCount.takeWhile { it == 1 }.take(1).collect()794 asyncResult.isActive shouldBe true795 store.keys.outdatedKeys.value = setOf()796 asyncResult.await()797 }798 should("wait that room members are loaded") {799 apiConfig.endpoints {800 matrixJsonEndpoint(801 json, mappings,802 SendToDevice("m.room.encrypted", "txn"),803 skipUrlCheck = true804 ) {805 }806 }807 store.room.update(room) { Room(room, membership = JOIN, membersLoaded = false) }808 store.room.get(room).first { it?.membersLoaded == false }809 val cedric = UserId("cedric", "server")810 listOf(811 StateEvent(812 MemberEventContent(membership = JOIN),813 EventId("\$event1"),814 alice,815 room,816 1234,817 stateKey = alice.full818 ),819 StateEvent(820 MemberEventContent(membership = JOIN),821 EventId("\$event2"),822 cedric,823 room,824 1235,825 stateKey = cedric.full826 )827 ).forEach { store.roomState.update(it) }828 val asyncResult = async { cut.encryptMegolm(eventContent, room, EncryptionEventContent()) }829 continually(200.milliseconds) {830 asyncResult.isActive shouldBe true831 }832 store.room.update(room) { it?.copy(membersLoaded = true) }833 asyncResult.await()834 }835 }836 context("with stored megolm session") {837 context("send sessions to new devices and encrypt") {838 beforeEach {839 freeAfter(OlmOutboundGroupSession.create()) { session ->840 store.olm.updateOutboundMegolmSession(room) {841 StoredOutboundMegolmSession(842 roomId = room,843 encryptedMessageCount = 23,844 newDevices = mapOf(bob to setOf(bobDeviceId)),845 pickled = session.pickle("")846 )847 }848 store.olm.storeTrustedInboundMegolmSession(849 roomId = room,850 senderKey = aliceCurveKey,851 senderSigningKey = aliceEdKey,852 sessionId = session.sessionId,853 sessionKey = session.sessionKey,854 pickleKey = ""855 )856 }857 }858 testEncryption(EncryptionEventContent(), 24)859 }860 context("when rotation period passed") {861 beforeEach {862 store.olm.updateOutboundMegolmSession(room) {863 StoredOutboundMegolmSession(864 roomId = room,865 createdAt = Clock.System.now().minus(24, DateTimeUnit.MILLISECOND),866 pickled = "is irrelevant"867 )868 }869 }870 testEncryption(EncryptionEventContent(rotationPeriodMs = 24), 2)871 }872 context("when message count passed") {873 beforeEach {874 store.olm.updateOutboundMegolmSession(room) {875 StoredOutboundMegolmSession(876 roomId = room,877 encryptedMessageCount = 24,878 pickled = "is irrelevant"879 )880 }881 }882 testEncryption(EncryptionEventContent(rotationPeriodMsgs = 24), 25)883 }884 }885 }886 context(OlmEventService::decryptMegolm.name) {887 val eventContent = TextMessageEventContent("Hi")888 val room = RoomId("room", "server")889 val decryptedMegolmEvent = DecryptedMegolmEvent(eventContent, room)890 should("decrypt megolm event") {891 freeAfter(OlmOutboundGroupSession.create()) { session ->892 store.olm.storeTrustedInboundMegolmSession(893 roomId = room,894 senderKey = bobCurveKey,895 senderSigningKey = bobEdKey,896 sessionId = session.sessionId,897 sessionKey = session.sessionKey,898 pickleKey = ""899 )900 val ciphertext =901 session.encrypt(json.encodeToString(decryptedMegolmEventSerializer, decryptedMegolmEvent))902 cut.decryptMegolm(903 MessageEvent(904 MegolmEncryptedEventContent(905 ciphertext,906 bobCurveKey,907 bobDeviceId,908 session.sessionId,909 relatesTo = relatesTo910 ),911 EventId("\$event"),912 bob,913 room,914 1234915 )916 ) shouldBe decryptedMegolmEvent.copy(content = decryptedMegolmEvent.content.copy(relatesTo = relatesTo))917 store.olm.updateInboundMegolmMessageIndex(bobCurveKey, session.sessionId, room, 0) {918 it shouldBe StoredInboundMegolmMessageIndex(919 bobCurveKey, session.sessionId, room, 0, EventId("\$event"), 1234920 )921 it922 }923 }924 }925 should("throw when no keys were send to us") {926 freeAfter(OlmOutboundGroupSession.create()) { session ->927 val ciphertext =928 session.encrypt(json.encodeToString(decryptedMegolmEventSerializer, decryptedMegolmEvent))929 shouldThrow<DecryptionException> {930 cut.decryptMegolm(931 MessageEvent(932 MegolmEncryptedEventContent(933 ciphertext,934 bobCurveKey,935 bobDeviceId,936 session.sessionId937 ),938 EventId("\$event"),939 bob,940 room,941 1234942 )943 )944 }945 }946 }947 context("manipulation") {948 should("handle manipulated roomId in megolmEvent") {949 freeAfter(OlmOutboundGroupSession.create()) { session ->950 store.olm.storeTrustedInboundMegolmSession(951 roomId = room,952 senderKey = bobCurveKey,953 senderSigningKey = bobEdKey,954 sessionId = session.sessionId,955 sessionKey = session.sessionKey,956 pickleKey = ""957 )958 val ciphertext = session.encrypt(959 json.encodeToString(960 decryptedMegolmEventSerializer,961 decryptedMegolmEvent.copy(roomId = RoomId("other", "server"))...

Full Screen

Full Screen

KeySecretServiceTest.kt

Source:KeySecretServiceTest.kt Github

copy

Full Screen

...89 ciphertext = mapOf(),90 senderKey = Key.Curve25519Key(null, "")91 ), bob92 )93 context(KeySecretService::handleEncryptedIncomingKeyRequests.name) {94 var sendToDeviceEvents: Map<UserId, Map<String, ToDeviceEventContent>>? = null95 beforeTest {96 sendToDeviceEvents = null97 store.account.userId.value = alice98 store.keys.updateDeviceKeys(alice) {99 mapOf(100 aliceDevice to StoredDeviceKeys(101 Signed(DeviceKeys(alice, aliceDevice, setOf(), keysOf()), null),102 Valid(true)103 )104 )105 }106 apiConfig.endpoints {107 matrixJsonEndpoint(108 json, mappings,109 SendToDevice("m.room.encrypted", "txn"),110 skipUrlCheck = true111 ) {112 sendToDeviceEvents = it.messages113 }114 }115 store.keys.secrets.value =116 mapOf(117 M_CROSS_SIGNING_USER_SIGNING to StoredSecret(118 GlobalAccountDataEvent(UserSigningKeyEventContent(mapOf())),119 "secretUserSigningKey"120 )121 )122 olmEvent.returnEncryptOlm = {123 EncryptedEventContent.OlmEncryptedEventContent(124 ciphertext = mapOf(),125 senderKey = Key.Curve25519Key("", "")126 )127 }128 }129 should("ignore request from other user") {130 cut.handleEncryptedIncomingKeyRequests(131 IOlmService.DecryptedOlmEventContainer(132 encryptedEvent, DecryptedOlmEvent(133 SecretKeyRequestEventContent(134 M_CROSS_SIGNING_USER_SIGNING.id,135 KeyRequestAction.REQUEST,136 bobDevice,137 "requestId"138 ),139 bob, keysOf(), alice, keysOf()140 )141 )142 )143 cut.processIncomingKeyRequests()144 sendToDeviceEvents shouldBe null145 }146 should("add request on request") {147 cut.handleEncryptedIncomingKeyRequests(148 IOlmService.DecryptedOlmEventContainer(149 encryptedEvent, DecryptedOlmEvent(150 SecretKeyRequestEventContent(151 M_CROSS_SIGNING_USER_SIGNING.id,152 KeyRequestAction.REQUEST,153 aliceDevice,154 "requestId"155 ),156 alice, keysOf(), alice, keysOf()157 )158 )159 )160 cut.processIncomingKeyRequests()161 sendToDeviceEvents?.get(alice)?.get(aliceDevice) shouldNotBe null162 }163 should("remove request on request cancellation") {164 cut.handleEncryptedIncomingKeyRequests(165 IOlmService.DecryptedOlmEventContainer(166 encryptedEvent, DecryptedOlmEvent(167 SecretKeyRequestEventContent(168 M_CROSS_SIGNING_USER_SIGNING.id,169 KeyRequestAction.REQUEST,170 aliceDevice,171 "requestId"172 ),173 alice, keysOf(), alice, keysOf()174 )175 )176 )177 cut.handleEncryptedIncomingKeyRequests(178 IOlmService.DecryptedOlmEventContainer(179 encryptedEvent, DecryptedOlmEvent(180 SecretKeyRequestEventContent(181 M_CROSS_SIGNING_USER_SIGNING.id,182 KeyRequestAction.REQUEST_CANCELLATION,183 aliceDevice,184 "requestId"185 ),186 alice, keysOf(), alice, keysOf()187 )188 )189 )190 cut.processIncomingKeyRequests()191 sendToDeviceEvents shouldBe null192 }193 }194 context(KeySecretService::processIncomingKeyRequests.name) {195 var sendToDeviceEvents: Map<UserId, Map<String, ToDeviceEventContent>>? = null196 beforeTest {197 sendToDeviceEvents = null198 store.account.userId.value = alice199 apiConfig.endpoints {200 matrixJsonEndpoint(201 json, mappings,202 SendToDevice("m.room.encrypted", "txn"),203 skipUrlCheck = true204 ) {205 sendToDeviceEvents = it.messages206 }207 }208 store.keys.secrets.value =209 mapOf(210 M_CROSS_SIGNING_USER_SIGNING to StoredSecret(211 GlobalAccountDataEvent(UserSigningKeyEventContent(mapOf())),212 "secretUserSigningKey"213 )214 )215 olmEvent.returnEncryptOlm = {216 EncryptedEventContent.OlmEncryptedEventContent(217 ciphertext = mapOf(),218 senderKey = Key.Curve25519Key("", "")219 )220 }221 }222 suspend fun ShouldSpecContainerScope.answerRequest(returnedTrustLevel: KeySignatureTrustLevel) {223 should("answer request with trust level $returnedTrustLevel") {224 store.keys.updateDeviceKeys(alice) {225 mapOf(226 aliceDevice to StoredDeviceKeys(227 SignedDeviceKeys(DeviceKeys(alice, aliceDevice, setOf(), keysOf()), mapOf()),228 returnedTrustLevel229 )230 )231 }232 cut.handleEncryptedIncomingKeyRequests(233 IOlmService.DecryptedOlmEventContainer(234 encryptedEvent, DecryptedOlmEvent(235 SecretKeyRequestEventContent(236 M_CROSS_SIGNING_USER_SIGNING.id,237 KeyRequestAction.REQUEST,238 aliceDevice,239 "requestId"240 ),241 alice, keysOf(), alice, keysOf()242 )243 )244 )245 cut.processIncomingKeyRequests()246 cut.processIncomingKeyRequests()247 sendToDeviceEvents?.get(alice)?.get(aliceDevice) shouldNotBe null248 }249 }250 answerRequest(Valid(true))251 answerRequest(CrossSigned(true))252 suspend fun ShouldSpecContainerScope.notAnswerRequest(returnedTrustLevel: KeySignatureTrustLevel) {253 should("not answer request with trust level $returnedTrustLevel") {254 store.keys.updateDeviceKeys(alice) {255 mapOf(256 aliceDevice to StoredDeviceKeys(257 SignedDeviceKeys(DeviceKeys(alice, aliceDevice, setOf(), keysOf()), mapOf()),258 returnedTrustLevel259 )260 )261 }262 cut.handleEncryptedIncomingKeyRequests(263 IOlmService.DecryptedOlmEventContainer(264 encryptedEvent, DecryptedOlmEvent(265 SecretKeyRequestEventContent(266 M_CROSS_SIGNING_USER_SIGNING.id,267 KeyRequestAction.REQUEST,268 aliceDevice,269 "requestId"270 ),271 alice, keysOf(), alice, keysOf()272 )273 )274 )275 cut.processIncomingKeyRequests()276 cut.processIncomingKeyRequests()277 sendToDeviceEvents shouldBe null278 }279 }280 notAnswerRequest(Valid(false))281 notAnswerRequest(CrossSigned(false))282 notAnswerRequest(NotCrossSigned)283 notAnswerRequest(Blocked)284 notAnswerRequest(Invalid("reason"))285 }286 context(KeySecretService::handleOutgoingKeyRequestAnswer.name) {287 val (crossSigningPublicKey, crossSigningPrivateKey) = freeAfter(OlmPkSigning.create(null)) { it.publicKey to it.privateKey }288 val (keyBackupPublicKey, keyBackupPrivateKey) = freeAfter(OlmPkDecryption.create(null)) { it.publicKey to it.privateKey }289 val aliceDevice2Key = Key.Ed25519Key(aliceDevice, "aliceDevice2KeyValue")290 suspend fun setDeviceKeys(trusted: Boolean) {291 store.keys.updateDeviceKeys(alice) {292 mapOf(293 aliceDevice to StoredDeviceKeys(294 SignedDeviceKeys(DeviceKeys(alice, aliceDevice, setOf(), keysOf(aliceDevice2Key)), mapOf()),295 CrossSigned(trusted)296 )297 )298 }299 }300 suspend fun setRequest(secretType: AllowedSecretType, receiverDeviceIds: Set<String>) {301 store.keys.addSecretKeyRequest(302 StoredSecretKeyRequest(303 SecretKeyRequestEventContent(304 secretType.id,305 KeyRequestAction.REQUEST,306 "OWN_ALICE_DEVICE",307 "requestId"308 ), receiverDeviceIds, Clock.System.now()309 )310 )311 store.keys.allSecretKeyRequests.first { it.size == 1 }312 }313 suspend fun setCrossSigningKeys(publicKey: String) {314 store.keys.updateCrossSigningKeys(alice) {315 setOf(316 StoredCrossSigningKeys(317 SignedCrossSigningKeys(318 CrossSigningKeys(319 alice, setOf(CrossSigningKeysUsage.UserSigningKey), keysOf(320 Key.Ed25519Key(publicKey, publicKey)321 )322 ), mapOf()323 ), CrossSigned(true)324 )325 )326 }327 }328 fun returnRoomKeysVersion(publicKey: String? = null) {329 apiConfig.endpoints {330 matrixJsonEndpoint(json, mappings, GetRoomKeyBackupVersion()) {331 if (publicKey == null) throw MatrixServerException(InternalServerError, ErrorResponse.Unknown(""))332 else GetRoomKeysBackupVersionResponse.V1(333 authData = RoomKeyBackupAuthData.RoomKeyBackupV1AuthData(334 publicKey = Key.Curve25519Key(null, publicKey)335 ), 1, "etag", "1"336 )337 }338 }339 }340 should("ignore, when sender device id cannot be found") {341 cut.handleOutgoingKeyRequestAnswer(342 IOlmService.DecryptedOlmEventContainer(343 encryptedEvent, DecryptedOlmEvent(344 SecretKeySendEventContent("requestId", crossSigningPrivateKey),345 alice, keysOf(aliceDevice2Key), alice, keysOf()346 )347 )348 )349 continually(500.milliseconds) {350 store.keys.secrets.value shouldBe mapOf()351 }352 }353 should("ignore when sender was not requested") {354 setDeviceKeys(true)355 setRequest(M_CROSS_SIGNING_USER_SIGNING, setOf("OTHER_DEVICE"))356 cut.handleOutgoingKeyRequestAnswer(357 IOlmService.DecryptedOlmEventContainer(358 encryptedEvent, DecryptedOlmEvent(359 SecretKeySendEventContent("requestId", crossSigningPrivateKey),360 alice, keysOf(aliceDevice2Key), alice, keysOf()361 )362 )363 )364 continually(500.milliseconds) {365 store.keys.secrets.value shouldBe mapOf()366 }367 }368 should("ignore when sender is not trusted") {369 setDeviceKeys(false)370 cut.handleOutgoingKeyRequestAnswer(371 IOlmService.DecryptedOlmEventContainer(372 encryptedEvent, DecryptedOlmEvent(373 SecretKeySendEventContent("requestId", crossSigningPrivateKey),374 alice, keysOf(aliceDevice2Key), alice, keysOf()375 )376 )377 )378 continually(500.milliseconds) {379 store.keys.secrets.value shouldBe mapOf()380 }381 }382 should("ignore when public key of cross signing secret cannot be generated") {383 setDeviceKeys(true)384 setRequest(M_CROSS_SIGNING_USER_SIGNING, setOf(aliceDevice))385 setCrossSigningKeys(crossSigningPublicKey)386 cut.handleOutgoingKeyRequestAnswer(387 IOlmService.DecryptedOlmEventContainer(388 encryptedEvent, DecryptedOlmEvent(389 SecretKeySendEventContent("requestId", "dino"),390 alice, keysOf(aliceDevice2Key), alice, keysOf()391 )392 )393 )394 continually(500.milliseconds) {395 store.keys.secrets.value shouldBe mapOf()396 }397 }398 should("ignore when public key of key backup secret cannot be retrieved") {399 setDeviceKeys(true)400 setRequest(M_MEGOLM_BACKUP_V1, setOf(aliceDevice))401 returnRoomKeysVersion(null)402 val secretEventContent = MegolmBackupV1EventContent(mapOf())403 store.globalAccountData.update(GlobalAccountDataEvent(secretEventContent))404 cut.handleOutgoingKeyRequestAnswer(405 IOlmService.DecryptedOlmEventContainer(406 encryptedEvent, DecryptedOlmEvent(407 SecretKeySendEventContent("requestId", keyBackupPrivateKey),408 alice, keysOf(aliceDevice2Key), alice, keysOf()409 )410 )411 )412 continually(500.milliseconds) {413 store.keys.secrets.value shouldBe mapOf()414 }415 }416 should("ignore when public key of cross signing secret does not match") {417 setDeviceKeys(true)418 setRequest(M_CROSS_SIGNING_USER_SIGNING, setOf(aliceDevice))419 setCrossSigningKeys(freeAfter(OlmPkSigning.create(null)) { it.publicKey })420 val secretEventContent = UserSigningKeyEventContent(mapOf())421 store.globalAccountData.update(GlobalAccountDataEvent(secretEventContent))422 cut.handleOutgoingKeyRequestAnswer(423 IOlmService.DecryptedOlmEventContainer(424 encryptedEvent, DecryptedOlmEvent(425 SecretKeySendEventContent("requestId", crossSigningPrivateKey),426 alice, keysOf(aliceDevice2Key), alice, keysOf()427 )428 )429 )430 continually(500.milliseconds) {431 store.keys.secrets.value shouldBe mapOf()432 }433 }434 should("ignore when public key of key backup secret does not match") {435 keyBackup.returnKeyBackupCanBeTrusted = false436 setDeviceKeys(true)437 setRequest(M_MEGOLM_BACKUP_V1, setOf(aliceDevice))438 returnRoomKeysVersion(freeAfter(OlmPkDecryption.create(null)) { it.publicKey })439 val secretEventContent = MegolmBackupV1EventContent(mapOf())440 store.globalAccountData.update(GlobalAccountDataEvent(secretEventContent))441 cut.handleOutgoingKeyRequestAnswer(442 IOlmService.DecryptedOlmEventContainer(443 encryptedEvent, DecryptedOlmEvent(444 SecretKeySendEventContent("requestId", keyBackupPrivateKey),445 alice, keysOf(aliceDevice2Key), alice, keysOf()446 )447 )448 )449 continually(500.milliseconds) {450 store.keys.secrets.value shouldBe mapOf()451 }452 }453 should("ignore when encrypted secret could not be found") {454 setDeviceKeys(true)455 setRequest(M_CROSS_SIGNING_USER_SIGNING, setOf(aliceDevice))456 setCrossSigningKeys(crossSigningPublicKey)457 cut.handleOutgoingKeyRequestAnswer(458 IOlmService.DecryptedOlmEventContainer(459 encryptedEvent, DecryptedOlmEvent(460 SecretKeySendEventContent("requestId", crossSigningPrivateKey),461 alice, keysOf(aliceDevice2Key), alice, keysOf()462 )463 )464 )465 continually(500.milliseconds) {466 store.keys.secrets.value shouldBe mapOf()467 }468 }469 should("save cross signing secret") {470 setDeviceKeys(true)471 setRequest(M_CROSS_SIGNING_USER_SIGNING, setOf(aliceDevice))472 setCrossSigningKeys(crossSigningPublicKey)473 val secretEvent = GlobalAccountDataEvent(UserSigningKeyEventContent(mapOf()))474 store.globalAccountData.update(secretEvent)475 cut.handleOutgoingKeyRequestAnswer(476 IOlmService.DecryptedOlmEventContainer(477 encryptedEvent, DecryptedOlmEvent(478 SecretKeySendEventContent("requestId", crossSigningPrivateKey),479 alice, keysOf(aliceDevice2Key), alice, keysOf()480 )481 )482 )483 store.keys.secrets.first { it.size == 1 } shouldBe mapOf(484 M_CROSS_SIGNING_USER_SIGNING to StoredSecret(secretEvent, crossSigningPrivateKey)485 )486 }487 should("save cross key backup secret") {488 keyBackup.returnKeyBackupCanBeTrusted = true489 setDeviceKeys(true)490 setRequest(M_MEGOLM_BACKUP_V1, setOf(aliceDevice))491 returnRoomKeysVersion(keyBackupPublicKey)492 val secretEvent = GlobalAccountDataEvent(MegolmBackupV1EventContent(mapOf()))493 store.globalAccountData.update(secretEvent)494 cut.handleOutgoingKeyRequestAnswer(495 IOlmService.DecryptedOlmEventContainer(496 encryptedEvent, DecryptedOlmEvent(497 SecretKeySendEventContent("requestId", keyBackupPrivateKey),498 alice, keysOf(aliceDevice2Key), alice, keysOf()499 )500 )501 )502 store.keys.secrets.first { it.size == 1 } shouldBe mapOf(503 M_MEGOLM_BACKUP_V1 to StoredSecret(secretEvent, keyBackupPrivateKey)504 )505 }506 should("cancel other requests") {507 var sendToDeviceEvents: Map<UserId, Map<String, ToDeviceEventContent>>? = null508 apiConfig.endpoints {509 matrixJsonEndpoint(510 json, mappings,511 SendToDevice("m.secret.request", "txn"),512 skipUrlCheck = true513 ) {514 sendToDeviceEvents = it.messages515 }516 }517 setDeviceKeys(true)518 setRequest(M_CROSS_SIGNING_USER_SIGNING, setOf(aliceDevice, "OTHER_DEVICE"))519 setCrossSigningKeys(crossSigningPublicKey)520 val secretEvent = GlobalAccountDataEvent(UserSigningKeyEventContent(mapOf()))521 store.globalAccountData.update(secretEvent)522 cut.handleOutgoingKeyRequestAnswer(523 IOlmService.DecryptedOlmEventContainer(524 encryptedEvent, DecryptedOlmEvent(525 SecretKeySendEventContent("requestId", crossSigningPrivateKey),526 alice, keysOf(aliceDevice2Key), alice, keysOf()527 )528 )529 )530 store.keys.secrets.first { it.size == 1 } shouldBe mapOf(531 M_CROSS_SIGNING_USER_SIGNING to StoredSecret(secretEvent, crossSigningPrivateKey)532 )533 sendToDeviceEvents?.get(alice)?.get("OTHER_DEVICE") shouldBe SecretKeyRequestEventContent(534 M_CROSS_SIGNING_USER_SIGNING.id,535 KeyRequestAction.REQUEST_CANCELLATION,536 "OWN_ALICE_DEVICE",537 "requestId"538 )539 }540 }541 context(KeySecretService::cancelOldOutgoingKeyRequests.name) {542 should("only remove old requests and send cancel") {543 var sendToDeviceEvents: Map<UserId, Map<String, ToDeviceEventContent>>? = null544 apiConfig.endpoints {545 matrixJsonEndpoint(546 json, mappings,547 SendToDevice("m.secret.request", "txn"),548 skipUrlCheck = true549 ) {550 sendToDeviceEvents = it.messages551 }552 }553 val request1 = StoredSecretKeyRequest(554 SecretKeyRequestEventContent(555 M_CROSS_SIGNING_USER_SIGNING.id,556 KeyRequestAction.REQUEST,557 "OWN_ALICE_DEVICE",558 "requestId1"559 ), setOf(), Clock.System.now()560 )561 val request2 = StoredSecretKeyRequest(562 SecretKeyRequestEventContent(563 M_CROSS_SIGNING_USER_SIGNING.id,564 KeyRequestAction.REQUEST,565 "OWN_ALICE_DEVICE",566 "requestId2"567 ), setOf(aliceDevice), (Clock.System.now() - 1.days)568 )569 store.keys.addSecretKeyRequest(request1)570 store.keys.addSecretKeyRequest(request2)571 store.keys.allSecretKeyRequests.first { it.size == 2 }572 cut.cancelOldOutgoingKeyRequests()573 store.keys.allSecretKeyRequests.first { it.size == 1 } shouldBe setOf(request1)574 sendToDeviceEvents?.get(alice)?.get(aliceDevice) shouldBe SecretKeyRequestEventContent(575 M_CROSS_SIGNING_USER_SIGNING.id,576 KeyRequestAction.REQUEST_CANCELLATION,577 "OWN_ALICE_DEVICE",578 "requestId2"579 )580 }581 }582 context(KeySecretService::requestSecretKeys.name) {583 var sendToDeviceEvents: Map<UserId, Map<String, ToDeviceEventContent>>? = null584 beforeTest {585 sendToDeviceEvents = null586 apiConfig.endpoints {587 matrixJsonEndpoint(588 json, mappings,589 SendToDevice("m.secret.request", "txn"),590 skipUrlCheck = true591 ) {592 sendToDeviceEvents = it.messages593 }594 }595 }596 should("ignore when there are no missing secrets") {597 store.keys.secrets.value = mapOf(598 M_CROSS_SIGNING_USER_SIGNING to StoredSecret(599 GlobalAccountDataEvent(UserSigningKeyEventContent(mapOf())),600 "key1"601 ),602 M_CROSS_SIGNING_SELF_SIGNING to StoredSecret(603 GlobalAccountDataEvent(SelfSigningKeyEventContent(mapOf())),604 "key2"605 ),606 M_MEGOLM_BACKUP_V1 to StoredSecret(607 GlobalAccountDataEvent(MegolmBackupV1EventContent(mapOf())),608 "key3"609 )610 )611 cut.requestSecretKeys()612 sendToDeviceEvents shouldBe null613 }614 should("send requests to verified cross signed devices") {615 store.keys.secrets.value = mapOf(616 M_MEGOLM_BACKUP_V1 to StoredSecret(617 GlobalAccountDataEvent(MegolmBackupV1EventContent(mapOf())),618 "key3"619 )620 )621 store.keys.addSecretKeyRequest(622 StoredSecretKeyRequest(623 SecretKeyRequestEventContent(624 M_CROSS_SIGNING_SELF_SIGNING.id,625 KeyRequestAction.REQUEST,626 aliceDevice,627 "requestId1"628 ), setOf("DEVICE_2"), Clock.System.now()629 )630 )631 store.keys.allSecretKeyRequests.first { it.size == 1 }632 store.keys.updateDeviceKeys(alice) {633 mapOf(634 "DEVICE_1" to StoredDeviceKeys(635 SignedDeviceKeys(DeviceKeys(alice, "DEVICE_1", setOf(), keysOf()), mapOf()),636 CrossSigned(false)637 ),638 "DEVICE_2" to StoredDeviceKeys(639 SignedDeviceKeys(DeviceKeys(alice, "DEVICE_2", setOf(), keysOf()), mapOf()),640 CrossSigned(true)641 )642 )643 }644 cut.requestSecretKeys()645 assertSoftly(sendToDeviceEvents?.get(alice)?.get("DEVICE_2")) {646 assertNotNull(this)647 this.shouldBeInstanceOf<SecretKeyRequestEventContent>()648 this.name shouldBe M_CROSS_SIGNING_USER_SIGNING.id649 this.action shouldBe KeyRequestAction.REQUEST650 this.requestingDeviceId shouldBe aliceDevice651 this.requestId shouldNot beEmpty()652 }653 store.keys.allSecretKeyRequests.first { it.size == 2 } shouldHaveSize 2654 }655 }656 context(KeySecretService::requestSecretKeysWhenCrossSigned.name) {657 should("request secret keys, when cross signed and verified") {658 currentSyncState.value = SyncState.RUNNING659 val sendToDeviceCalled = MutableStateFlow(false)660 apiConfig.endpoints {661 matrixJsonEndpoint(json, mappings, SendToDevice("", ""), skipUrlCheck = true) {662 sendToDeviceCalled.value = true663 }664 }665 val job = launch(start = CoroutineStart.UNDISPATCHED) {666 cut.requestSecretKeysWhenCrossSigned()667 }668 store.keys.updateDeviceKeys(alice) {669 mapOf(670 aliceDevice to StoredDeviceKeys(671 SignedDeviceKeys(DeviceKeys(alice, aliceDevice, setOf(), keysOf()), mapOf()),672 CrossSigned(true)673 ),674 "OTHER_ALICE" to StoredDeviceKeys(675 SignedDeviceKeys(DeviceKeys(alice, "OTHER_ALICE", setOf(), keysOf()), mapOf()),676 CrossSigned(true)677 ),678 )679 }680 sendToDeviceCalled.first { it }681 job.cancel()682 }683 }684 context(KeySecretService::handleChangedSecrets.name) {685 var sendToDeviceEvents: Map<UserId, Map<String, ToDeviceEventContent>>? = null686 beforeTest {687 sendToDeviceEvents = null688 apiConfig.endpoints {689 matrixJsonEndpoint(690 json, mappings,691 SendToDevice("m.secret.request", "txn"),692 skipUrlCheck = true693 ) {694 sendToDeviceEvents = it.messages695 }696 }697 store.keys.addSecretKeyRequest(698 StoredSecretKeyRequest(699 SecretKeyRequestEventContent(700 M_CROSS_SIGNING_USER_SIGNING.id,701 KeyRequestAction.REQUEST,702 aliceDevice,703 "requestId1"704 ), setOf("DEVICE_2"), Clock.System.now()705 )706 )707 store.keys.allSecretKeyRequests.first { it.size == 1 }708 }709 should("do nothing when secret is not allowed to cache") {710 val crossSigningPrivateKeys = mapOf(711 M_CROSS_SIGNING_USER_SIGNING to StoredSecret(712 GlobalAccountDataEvent(UserSigningKeyEventContent(mapOf())),713 "key"714 )715 )716 store.keys.secrets.value = crossSigningPrivateKeys717 cut.handleChangedSecrets(GlobalAccountDataEvent(MasterKeyEventContent(mapOf())))718 sendToDeviceEvents shouldBe null719 store.keys.secrets.value shouldBe crossSigningPrivateKeys720 }721 should("do nothing when event did not change") {722 val event = GlobalAccountDataEvent(UserSigningKeyEventContent(mapOf()))723 val crossSigningPrivateKeys = mapOf(724 M_CROSS_SIGNING_USER_SIGNING to StoredSecret(725 event, "bla"726 )727 )728 store.keys.secrets.value = crossSigningPrivateKeys729 cut.handleChangedSecrets(event)730 sendToDeviceEvents shouldBe null731 store.keys.secrets.value shouldBe crossSigningPrivateKeys732 }733 should("remove cached secret and cancel ongoing requests when event did change") {734 store.keys.secrets.value = mapOf(735 M_CROSS_SIGNING_USER_SIGNING to StoredSecret(736 GlobalAccountDataEvent(UserSigningKeyEventContent(mapOf("oh" to JsonPrimitive("change!")))),737 "bla"738 )739 )740 cut.handleChangedSecrets(GlobalAccountDataEvent(UserSigningKeyEventContent(mapOf())))741 assertSoftly(sendToDeviceEvents?.get(alice)?.get("DEVICE_2")) {742 assertNotNull(this)743 this.shouldBeInstanceOf<SecretKeyRequestEventContent>()744 this.name shouldBe M_CROSS_SIGNING_USER_SIGNING.id745 this.action shouldBe KeyRequestAction.REQUEST_CANCELLATION746 this.requestingDeviceId shouldBe aliceDevice747 this.requestId shouldBe "requestId1"748 }749 store.keys.secrets.value shouldBe mapOf()750 }751 }752 context(KeySecretService::decryptMissingSecrets.name) {753 should("decrypt missing secrets and update secure store") {754 val existingPrivateKeys = mapOf(755 M_CROSS_SIGNING_SELF_SIGNING to StoredSecret(756 GlobalAccountDataEvent(SelfSigningKeyEventContent(mapOf())), "key2"757 ),758 M_MEGOLM_BACKUP_V1 to StoredSecret(759 GlobalAccountDataEvent(SelfSigningKeyEventContent(mapOf())), "key3"760 )761 )762 store.keys.secrets.value = existingPrivateKeys763 val key = Random.nextBytes(32)764 val secret = Random.nextBytes(32).encodeBase64()765 val encryptedData = encryptAesHmacSha2(766 content = secret.encodeToByteArray(),...

Full Screen

Full Screen

RoomServiceDisplayNameTest.kt

Source:RoomServiceDisplayNameTest.kt Github

copy

Full Screen

...103 1,104 stateKey = ""105 )106 }107 context(RoomService::setRoomDisplayName.name) {108 beforeTest {109 store.room.update(roomId) { simpleRoom.copy(roomId = roomId) }110 }111 suspend fun ShouldSpecContainerScope.testWithoutNameFromNameEvent() {112 context("with an existent Canonical Alias Event") {113 should("set room name to the alias field value") {114 listOf(115 canonicalAliasEvent(2, user2, RoomAliasId("somewhere", "localhost")),116 memberEvent(3, user1, "User1-Display", JOIN),117 memberEvent(4, user2, "User2-Display", INVITE),118 memberEvent(5, user3, "User3-Display", BAN),119 memberEvent(6, user4, "User4-Display", LEAVE)120 ).forEach { store.roomState.update(it) }121 val roomSummary = RoomSummary(122 heroes = listOf(user1, user2),123 joinedMemberCount = 1,124 invitedMemberCount = 1,125 )126 cut.setRoomDisplayName(roomId, roomSummary)127 store.room.get(roomId).value?.name shouldBe RoomDisplayName(128 explicitName = "#somewhere:localhost",129 summary = roomSummary130 )131 }132 }133 context("with a non-existent Canonical Alias Event") {134 context("|joined member| + |invited member| > 1") {135 beforeTest {136 listOf(137 memberEvent(3, user1, "User1-Display", JOIN),138 memberEvent(4, user2, "User2-Display", INVITE),139 memberEvent(7, user5, "User5-Display", BAN)140 ).forEach { store.roomState.update(it) }141 }142 context("|heroes| >= |joined member| + |invited member| - 1") {143 beforeTest {144 listOf(145 memberEvent(5, user3, "User3-Display", LEAVE),146 memberEvent(6, user4, "User4-Display", LEAVE),147 ).forEach { store.roomState.update(it) }148 }149 context("|heroes| = 1") {150 should("set room name to the display name of the hero") {151 val roomSummary = RoomSummary(152 heroes = listOf(user1),153 joinedMemberCount = 1,154 invitedMemberCount = 1,155 )156 cut.setRoomDisplayName(roomId, roomSummary)157 store.room.get(roomId).value?.name shouldBe RoomDisplayName(158 summary = roomSummary159 )160 }161 }162 context("|heroes| = 2") {163 should("set room name to the display names of the heroes concatenate with an 'und'") {164 val roomSummary = RoomSummary(165 heroes = listOf(user1, user2),166 joinedMemberCount = 1,167 invitedMemberCount = 1,168 )169 cut.setRoomDisplayName(roomId, roomSummary)170 store.room.get(roomId).value?.name shouldBe RoomDisplayName(171 summary = roomSummary172 )173 }174 }175 }176 context("|heroes| < |joined member| + |invited member| - 1") {177 beforeTest {178 listOf(179 memberEvent(5, user3, "User3-Display", JOIN),180 memberEvent(6, user4, "User4-Display", INVITE),181 ).forEach { store.roomState.update(it) }182 }183 context("|heroes| = 0") {184 should("set room name to the count of the invited and joined users") {185 val roomSummary = RoomSummary(186 heroes = listOf(),187 joinedMemberCount = 2,188 invitedMemberCount = 2,189 )190 cut.setRoomDisplayName(roomId, roomSummary)191 store.room.get(roomId).value?.name shouldBe RoomDisplayName(192 otherUsersCount = 3,193 summary = roomSummary194 )195 }196 }197 context("|heroes| = 1") {198 should("set room name to the display name of the hero and a count of the remaining users") {199 val roomSummary = RoomSummary(200 heroes = listOf(user1),201 joinedMemberCount = 2,202 invitedMemberCount = 2,203 )204 cut.setRoomDisplayName(roomId, roomSummary)205 store.room.get(roomId).value?.name shouldBe RoomDisplayName(206 otherUsersCount = 2,207 summary = roomSummary208 )209 }210 }211 context("|heroes| = 2") {212 should("set room name to the display names of the heroes concatenate with an 'und'") {213 val roomSummary = RoomSummary(214 heroes = listOf(user1, user2),215 joinedMemberCount = 2,216 invitedMemberCount = 2,217 )218 cut.setRoomDisplayName(roomId, roomSummary)219 store.room.get(roomId).value?.name shouldBe RoomDisplayName(220 otherUsersCount = 1,221 summary = roomSummary222 )223 }224 }225 }226 }227 context("|joined member| + |invited member| = 1") {228 beforeTest {229 listOf(230 memberEvent(3, user1, "User1-Display", JOIN),231 memberEvent(4, user2, "User2-Display", BAN),232 memberEvent(5, user3, "User3-Display", LEAVE),233 ).forEach { store.roomState.update(it) }234 }235 context("|heroes| = 0") {236 should("set room name to 'Leerer Raum'") {237 val roomSummary = RoomSummary(238 heroes = listOf(),239 joinedMemberCount = 1,240 invitedMemberCount = 0,241 )242 cut.setRoomDisplayName(roomId, roomSummary)243 store.room.get(roomId).value?.name shouldBe RoomDisplayName(244 isEmpty = true,245 summary = roomSummary246 )247 }248 }249 context("|heroes| >= |left member| + |banned member| - 1") {250 context("|heroes| = 1") {251 should("set room name to the display name of the hero") {252 val roomSummary = RoomSummary(253 heroes = listOf(user2),254 joinedMemberCount = 1,255 invitedMemberCount = 0,256 )257 cut.setRoomDisplayName(roomId, roomSummary)258 store.room.get(roomId).value?.name shouldBe RoomDisplayName(259 isEmpty = true,260 otherUsersCount = 1,261 summary = roomSummary262 )263 }264 }265 context("|heroes| = 2") {266 should("set room name to the display names of the heroes concatenate with an 'und'") {267 val roomSummary = RoomSummary(268 heroes = listOf(user2, user3),269 joinedMemberCount = 1,270 invitedMemberCount = 0,271 )272 cut.setRoomDisplayName(roomId, roomSummary)273 store.room.get(roomId).value?.name shouldBe RoomDisplayName(274 isEmpty = true,275 summary = roomSummary276 )277 }278 }279 }280 context("|heroes| < |left member| + |banned member| - 1") {281 beforeTest {282 listOf(283 memberEvent(6, user4, "User4-Display", LEAVE),284 memberEvent(7, user5, "User5-Display", LEAVE),285 ).forEach { store.roomState.update(it) }286 }287 context("|heroes| = 1") {288 should("set room name to the concatenation of display names of the heroes and a count of the remaining users, enclosed by an Empty Room String") {289 val roomSummary = RoomSummary(290 heroes = listOf(user2),291 joinedMemberCount = 1,292 invitedMemberCount = 0,293 )294 cut.setRoomDisplayName(roomId, roomSummary)295 store.room.get(roomId).value?.name shouldBe RoomDisplayName(296 isEmpty = true,297 otherUsersCount = 3,298 summary = roomSummary299 )300 }301 }302 context("|heroes| = 2") {303 should("set room name to the concatenation of display names of the heroes and a count of the remaining users, enclosed by an Empty Room String") {304 val roomSummary = RoomSummary(305 heroes = listOf(user2, user3),306 joinedMemberCount = 1,307 invitedMemberCount = 0,308 )309 cut.setRoomDisplayName(roomId, roomSummary)310 store.room.get(roomId).value?.name shouldBe RoomDisplayName(311 isEmpty = true,312 otherUsersCount = 2,313 summary = roomSummary314 )315 }316 }317 }318 }319 context("|joined member| + |invited member| = 0") {320 beforeTest {321 listOf(322 memberEvent(3, user1, "User1-Display", LEAVE),323 memberEvent(4, user2, "User2-Display", BAN),324 ).forEach { store.roomState.update(it) }325 }326 context("|heroes| = 0") {327 should("set room name to 'Leerer Raum'") {328 val roomSummary = RoomSummary(329 heroes = listOf(),330 joinedMemberCount = 0,331 invitedMemberCount = 0,332 )333 cut.setRoomDisplayName(roomId, roomSummary)334 store.room.get(roomId).value?.name shouldBe RoomDisplayName(335 isEmpty = true,336 summary = roomSummary337 )338 }339 }340 context("|heroes| >= |left member| + |banned member| - 1") {341 context("|heroes| = 1") {342 should("set room name to the display name of the hero, enclosed by an Empty Room String") {343 val roomSummary = RoomSummary(344 heroes = listOf(user1),345 joinedMemberCount = 0,346 invitedMemberCount = 0,347 )348 cut.setRoomDisplayName(roomId, roomSummary)349 store.room.get(roomId).value?.name shouldBe RoomDisplayName(350 isEmpty = true,351 summary = roomSummary352 )353 }354 }355 context("|heroes| = 2") {356 should("set room name to the display names of the heroes concatenate with an 'und', enclosed by an Empty Room String ") {357 store.roomState.update(358 memberEvent(5, user3, "User3-Display", LEAVE),359 )360 val roomSummary = RoomSummary(361 heroes = listOf(user1, user2),362 joinedMemberCount = 0,363 invitedMemberCount = 0,364 )365 cut.setRoomDisplayName(roomId, roomSummary)366 store.room.get(roomId).value?.name shouldBe RoomDisplayName(367 isEmpty = true,368 summary = roomSummary369 )370 }371 }372 }373 context("|heroes| < |left member| + |banned member| - 1") {374 beforeTest {375 listOf(376 memberEvent(5, user3, "User3-Display", LEAVE),377 memberEvent(6, user4, "User4-Display", LEAVE),378 memberEvent(7, user5, "User5-Display", LEAVE),379 ).forEach { store.roomState.update(it) }380 }381 context("|heroes| = 1") {382 should("set room name to the concatenation of display names of the heroes and a count of the remaining users, enclosed by an Empty Room String") {383 val roomSummary = RoomSummary(384 heroes = listOf(user1),385 joinedMemberCount = 0,386 invitedMemberCount = 0,387 )388 cut.setRoomDisplayName(roomId, roomSummary)389 store.room.get(roomId).value?.name shouldBe RoomDisplayName(390 isEmpty = true,391 otherUsersCount = 3,392 summary = roomSummary393 )394 }395 }396 context("|heroes| = 2") {397 should("set room name to the concatenation of display names of the heroes and a count of the remaining users, enclosed by an Empty Room String") {398 val roomSummary = RoomSummary(399 heroes = listOf(user1, user2),400 joinedMemberCount = 0,401 invitedMemberCount = 0,402 )403 cut.setRoomDisplayName(roomId, roomSummary)404 store.room.get(roomId).value?.name shouldBe RoomDisplayName(405 isEmpty = true,406 otherUsersCount = 2,407 summary = roomSummary408 )409 }410 }411 }412 }413 }414 }415 context("existent room name state event") {416 context("with a non-empty name field") {417 beforeTest {418 store.roomState.update(nameEvent(1, user1, "The room name"))419 }420 should("set room name to the name field value") {421 listOf(422 canonicalAliasEvent(2, user2, RoomAliasId("somewhere", "localhost")),423 memberEvent(3, user1, "User1-Display", JOIN),424 memberEvent(4, user2, "User2-Display", INVITE),425 memberEvent(5, user3, "User3-Display", BAN),426 memberEvent(6, user4, "User4-Display", LEAVE)427 ).forEach { store.roomState.update(it) }428 val roomSummary = RoomSummary(429 heroes = listOf(user1, user2),430 joinedMemberCount = 1,431 invitedMemberCount = 2,432 )433 cut.setRoomDisplayName(roomId, roomSummary)434 store.room.get(roomId).value?.name shouldBe RoomDisplayName(435 explicitName = "The room name",436 summary = roomSummary437 )438 }439 }440 context("with an empty name field") {441 beforeTest {442 store.roomState.update(nameEvent(1, user1, ""))443 }444 testWithoutNameFromNameEvent()445 }446 }447 context("non-existent room name state event") {448 testWithoutNameFromNameEvent()449 }450 }451})...

Full Screen

Full Screen

ActiveSasVerificationMethodTest.kt

Source:ActiveSasVerificationMethodTest.kt Github

copy

Full Screen

...70 }71 afterTest {72 storeScope.cancel()73 }74 context("create") {75 should("not cancel when key agreement protocol is not supported") {76 val method = ActiveSasVerificationMethod.create(77 startEventContent = SasStartEventContent(78 aliceDevice,79 keyAgreementProtocols = setOf(),80 relatesTo = null,81 transactionId = "t"82 ),83 weStartedVerification = true,84 ownUserId = alice,85 ownDeviceId = aliceDevice,86 theirUserId = bob,87 theirDeviceId = bobDevice,88 relatesTo = null,89 transactionId = "t",90 sendVerificationStep = { sendVerificationStepFlow.emit(it) },91 store = store,92 keyTrustService = keyTrustService,93 json = json,94 )95 method shouldBe null96 val result = sendVerificationStepFlow.first()97 result.shouldBeInstanceOf<VerificationCancelEventContent>()98 result.code shouldBe UnknownMethod99 }100 }101 suspend fun ShouldSpecContainerScope.checkNotAllowedStateChange(vararg steps: VerificationStep) {102 steps.forEach {103 should("cancel unexpected message ${it::class.simpleName}") {104 cut.handleVerificationStep(it, false)105 val result =106 sendVerificationStepFlow.replayCache.filterIsInstance<VerificationCancelEventContent>().first()107 result.code shouldBe UnexpectedMessage108 }109 }110 }111 context("handleVerificationStep") {112 context("current state is ${OwnSasStart::class.simpleName} or ${TheirSasStart::class.simpleName}") {113 checkNotAllowedStateChange(114 SasKeyEventContent("key", null, "t"),115 SasMacEventContent("keys", keysOf(), null, "t")116 )117 should("just set state when message is from us") {118 cut.handleVerificationStep(119 SasAcceptEventContent("c", relatesTo = null, transactionId = "t"), true120 )121 cut.state.value shouldBe Accept(true)122 sendVerificationStepFlow.replayCache.shouldBeEmpty()123 }124 should("send ${SasKeyEventContent::class.simpleName} when sender was not us") {125 cut.handleVerificationStep(126 SasAcceptEventContent("c", relatesTo = null, transactionId = "t"), false127 )128 cut.state.value shouldBe Accept(false)129 val result = sendVerificationStepFlow.first()130 result.shouldBeInstanceOf<SasKeyEventContent>()131 assertSoftly(result) {132 key.shouldNotBeBlank()133 relatesTo shouldBe null134 transactionId shouldBe "t"135 }136 }137 should("cancel when key agreement protocol is not supported") {138 cut.handleVerificationStep(139 SasAcceptEventContent(140 "c",141 keyAgreementProtocol = "c",142 relatesTo = null,143 transactionId = "t"144 ), false145 )146 val result = sendVerificationStepFlow.first()147 result.shouldBeInstanceOf<VerificationCancelEventContent>()148 result.code shouldBe UnknownMethod149 }150 }151 context("current state is ${Accept::class.simpleName}") {152 context("handle unexpected") {153 beforeTest {154 cut.handleVerificationStep(SasAcceptEventContent("c", relatesTo = null, transactionId = "t"), true)155 cut.state.value.shouldBeInstanceOf<Accept>()156 }157 checkNotAllowedStateChange(158 SasAcceptEventContent("c", relatesTo = null, transactionId = "t"),159 SasMacEventContent("keys", keysOf(), null, "t")160 )161 }162 context("accept from them") {163 beforeTest {164 cut.handleVerificationStep(SasAcceptEventContent("c", relatesTo = null, transactionId = "t"), false)165 cut.state.value.shouldBeInstanceOf<Accept>()166 }167 should("just set state when message is from us") {168 cut.handleVerificationStep(SasKeyEventContent("k", relatesTo = null, transactionId = "t"), true)169 cut.state.value shouldBe WaitForKeys(true)170 }171 }172 context("accept from us") {173 beforeTest {174 cut.handleVerificationStep(SasAcceptEventContent("c", relatesTo = null, transactionId = "t"), true)175 cut.state.value.shouldBeInstanceOf<Accept>()176 }177 should("send ${SasKeyEventContent::class.simpleName} when sender was not us") {178 cut.handleVerificationStep(SasKeyEventContent("k", relatesTo = null, transactionId = "t"), false)179 cut.state.value shouldBe WaitForKeys(false)180 val result = sendVerificationStepFlow.first()181 result.shouldBeInstanceOf<SasKeyEventContent>()182 assertSoftly(result) {183 key.shouldNotBeBlank()184 relatesTo shouldBe null185 transactionId shouldBe "t"186 }187 }188 should("cancel when sender it not expected") {189 cut.handleVerificationStep(SasKeyEventContent("k", relatesTo = null, transactionId = "t"), true)190 val result = sendVerificationStepFlow.first()191 result.shouldBeInstanceOf<VerificationCancelEventContent>()192 result.code shouldBe UnexpectedMessage193 }194 }195 }196 context("current state is ${WaitForKeys::class.simpleName}") {197 beforeTest {198 cut.handleVerificationStep(199 SasAcceptEventContent(200 "4d8Qtr63ZuKgjhdBYdm/tZ9FiNCAAU1ZEc9HoHe6kEE",201 relatesTo = null,202 transactionId = "t"203 ), false204 )205 cut.handleVerificationStep(SasKeyEventContent("k", relatesTo = null, transactionId = "t"), true)206 cut.state.value.shouldBeInstanceOf<WaitForKeys>()207 }208 checkNotAllowedStateChange(209 SasAcceptEventContent("c", relatesTo = null, transactionId = "t"),210 SasMacEventContent("keys", keysOf(), null, "t")211 )212 should("create ${ComparisonByUser::class.simpleName}") {213 cut.handleVerificationStep(214 SasKeyEventContent(215 "3vPVpNPsVYVYuozmCrihhndEvVZUHpoHBSb5+TdkaAA",216 relatesTo = null,217 transactionId = "t"218 ), false219 )220 val state = cut.state.value221 state.shouldBeInstanceOf<ComparisonByUser>()222 state.decimal shouldHaveSize 3223 state.decimal.forEach {224 it shouldBeGreaterThanOrEqual 1000225 it shouldBeLessThanOrEqual 9191226 }227 state.emojis shouldHaveSize 7228 }229 should("cancel when commitment does not match") {230 cut.handleVerificationStep(SasKeyEventContent("k", relatesTo = null, transactionId = "t"), false)231 val result =232 sendVerificationStepFlow.replayCache.filterIsInstance<VerificationCancelEventContent>().first()233 result.code shouldBe MismatchedCommitment234 }235 should("cancel when sender it not expected") {236 cut.handleVerificationStep(SasKeyEventContent("k", relatesTo = null, transactionId = "t"), true)237 val result =238 sendVerificationStepFlow.replayCache.filterIsInstance<VerificationCancelEventContent>().first()239 result.code shouldBe UnexpectedMessage240 }241 }242 context("current state is ${ComparisonByUser::class.simpleName}") {243 beforeTest {244 cut.handleVerificationStep(245 SasAcceptEventContent(246 "4d8Qtr63ZuKgjhdBYdm/tZ9FiNCAAU1ZEc9HoHe6kEE",247 relatesTo = null,248 transactionId = "t"249 ), false250 )251 cut.handleVerificationStep(SasKeyEventContent("k", relatesTo = null, transactionId = "t"), true)252 cut.handleVerificationStep(253 SasKeyEventContent(254 "3vPVpNPsVYVYuozmCrihhndEvVZUHpoHBSb5+TdkaAA",255 relatesTo = null,256 transactionId = "t"257 ), false258 )259 cut.state.value.shouldBeInstanceOf<ComparisonByUser>()260 }261 checkNotAllowedStateChange(262 SasAcceptEventContent("c", relatesTo = null, transactionId = "t"),263 SasKeyEventContent("key", null, "t")264 )265 should("change state to ${WaitForMacs::class.simpleName} when accepted") {266 cut.handleVerificationStep(SasMacEventContent("keys", keysOf(), null, "t"), true)267 cut.state.value shouldBe WaitForMacs268 }269 should("not change state to ${WaitForMacs::class.simpleName} when from other") {270 val oldState = cut.state.value271 cut.handleVerificationStep(SasMacEventContent("keys", keysOf(), null, "t"), false)272 cut.state.value shouldBe oldState273 }274 }275 context("current state is ${WaitForMacs::class.simpleName}") {276 var sasMacFromBob: VerificationStep? = null277 beforeTest {278 store.keys.updateDeviceKeys(bob) {279 mapOf(280 bobDevice to StoredDeviceKeys(281 Signed(282 DeviceKeys(283 bob, bobDevice, setOf(Megolm),284 keysOf(285 Ed25519Key(bobDevice, "bobKey"),286 Ed25519Key("HUHU", "buh")287 )288 ), mapOf()289 ), Valid(true)...

Full Screen

Full Screen

ActiveVerificationTest.kt

Source:ActiveVerificationTest.kt Github

copy

Full Screen

...61 lifecycleCalled = 062 sendVerificationStepFlow = MutableSharedFlow(replay = 10)63 cut = TestActiveVerification(VerificationRequestEventContent(bobDevice, setOf(Sas), 1234, "t"))64 }65 context(ActiveVerification::startLifecycle.name) {66 should("start lifecycle once") {67 cut.startLifecycle(this)68 cut.startLifecycle(this)69 lifecycleCalled shouldBe 170 }71 }72 context(ActiveVerification::cancel.name) {73 should("send user cancel event content") {74 val expectedCancelEvent =75 VerificationCancelEventContent(Code.User, "user cancelled verification", null, "t")76 cut.cancel()77 sendVerificationStepFlow.first() shouldBe expectedCancelEvent78 cut.state.value shouldBe Cancel(expectedCancelEvent, true)79 }80 }81 context("handleVerificationStep") {82 context("step is from foreign user") {83 should("cancel") {84 cut.handleStep(85 VerificationReadyEventContent("FFFFFF", setOf(), null, "t"),86 UserId("f", "server"),87 false88 )89 sendVerificationStepFlow.first().shouldBeInstanceOf<VerificationCancelEventContent>()90 }91 }92 context("step has no matching transaction") {93 should("cancel") {94 cut.handleStep(VerificationReadyEventContent(aliceDevice, setOf(), null, null), alice, true)95 sendVerificationStepFlow.first().shouldBeInstanceOf<VerificationCancelEventContent>()96 }97 }98 context("current state is ${AcceptedByOtherDevice::class.simpleName}") {99 beforeTest {100 cut.setState(AcceptedByOtherDevice)101 }102 should("set state to ${Done::class.simpleName} when done") {103 cut.handleStep(VerificationDoneEventContent(null, "t"), alice, false)104 cut.state.value shouldBe Done105 }106 should("set state to ${Cancel::class.simpleName} when cancel") {107 val cancelEvent = VerificationCancelEventContent(Code.User, "user", null, "t")108 cut.handleStep(cancelEvent, alice, false)109 cut.state.value shouldBe Cancel(cancelEvent, false)110 }111 }112 suspend fun ShouldSpecContainerScope.checkNotAllowedStateChange(vararg steps: VerificationStep) {113 steps.forEach {114 should("cancel unexpected message ${it::class.simpleName}") {115 val stateBefore = cut.state.value116 cut.handleStep(it, bob, false)117 val state = cut.state.value118 state.shouldBeInstanceOf<Cancel>()119 state.content.code shouldBe Code.UnexpectedMessage120 if (stateBefore !is Cancel) {121 val result = sendVerificationStepFlow.first()122 result.shouldBeInstanceOf<VerificationCancelEventContent>()123 result.code shouldBe Code.UnexpectedMessage124 }125 }126 }127 }128 context("current state is ${OwnRequest::class.simpleName} or ${TheirRequest::class.simpleName}") {129 checkNotAllowedStateChange(130 SasStartEventContent(bobDevice, relatesTo = null, transactionId = "t"),131 VerificationDoneEventContent(null, "t"),132 )133 should("handle ${VerificationReadyEventContent::class.simpleName} when ${OwnRequest::class.simpleName}") {134 cut = TestActiveVerification(VerificationRequestEventContent(aliceDevice, setOf(Sas), 1234, "t"))135 cut.state.value.shouldBeInstanceOf<OwnRequest>()136 cut.handleStep(137 VerificationReadyEventContent(bobDevice, setOf(Sas, Unknown("u")), null, "t"),138 bob,139 false140 )141 val state = cut.state.value142 state.shouldBeInstanceOf<Ready>()143 state.methods shouldBe setOf(Sas)144 cut.theirDeviceId shouldBe bobDevice145 }146 should("handle ${VerificationReadyEventContent::class.simpleName} when ${TheirRequest::class.simpleName}") {147 cut.state.value.shouldBeInstanceOf<TheirRequest>()148 cut.handleStep(149 VerificationReadyEventContent(aliceDevice, setOf(Sas, Unknown("u")), null, "t"),150 alice,151 false152 )153 val state = cut.state.value154 state.shouldBeInstanceOf<Ready>()155 state.methods shouldBe setOf(Sas)156 }157 }158 context("current state is ${Ready::class.simpleName}") {159 beforeTest {160 cut.handleStep(161 VerificationReadyEventContent(bobDevice, setOf(Sas, Unknown("u")), null, "t"),162 bob,163 false164 )165 cut.state.value.shouldBeInstanceOf<Ready>()166 }167 checkNotAllowedStateChange(168 VerificationReadyEventContent(bobDevice, setOf(), null, "t"),169 VerificationDoneEventContent(null, "t"),170 )171 should("handle ${VerificationStartEventContent::class.simpleName}") {172 val step = SasStartEventContent(bobDevice, relatesTo = null, transactionId = "t")173 cut.handleStep(step, bob, false)174 val state = cut.state.value175 state.shouldBeInstanceOf<Start>()176 state.senderUserId shouldBe bob177 state.senderDeviceId shouldBe bobDevice178 val method = state.method179 method.shouldBeInstanceOf<ActiveSasVerificationMethod>()180 val subState = method.state.value181 subState.shouldBeInstanceOf<TheirSasStart>()182 subState.content shouldBe step183 }184 }185 context("current state is ${Start::class.simpleName}") {186 beforeTest {187 cut.handleStep(188 VerificationReadyEventContent(bobDevice, setOf(Sas, Unknown("u")), null, "t"),189 bob,190 false191 )192 cut.handleStep(SasStartEventContent(bobDevice, relatesTo = null, transactionId = "t"), bob, false)193 cut.state.value.shouldBeInstanceOf<Start>()194 }195 checkNotAllowedStateChange(196 VerificationReadyEventContent(bobDevice, setOf(), null, "t"),197 )198 context("handle ${VerificationStartEventContent::class.simpleName}") {199 should("keep event from lexicographically smaller user ID") {200 val step = SasStartEventContent(aliceDevice, relatesTo = null, transactionId = "t")201 cut.handleStep(step, alice, true)202 cut.handleStep(SasStartEventContent(bobDevice, relatesTo = null, transactionId = "t"), bob, false)203 val state = cut.state.value204 state.shouldBeInstanceOf<Start>()205 state.senderUserId shouldBe alice206 state.senderDeviceId shouldBe aliceDevice207 val method = state.method208 method.shouldBeInstanceOf<ActiveSasVerificationMethod>()209 val subState = method.state.value210 subState.shouldBeInstanceOf<OwnSasStart>()211 subState.content shouldBe step212 }213 should("keep event from lexicographically smaller deviceId") {214 cut.handleStep(SasStartEventContent("CCCCCC", relatesTo = null, transactionId = "t"), bob, false)215 val state = cut.state.value216 state.shouldBeInstanceOf<Start>()217 state.senderUserId shouldBe bob218 state.senderDeviceId shouldBe bobDevice219 val method = state.method220 method.shouldBeInstanceOf<ActiveSasVerificationMethod>()221 val subState = method.state.value222 subState.shouldBeInstanceOf<TheirSasStart>()223 subState.content shouldBe SasStartEventContent(bobDevice, relatesTo = null, transactionId = "t")224 }225 should("override event from lexicographically smaller user ID") {226 val step = SasStartEventContent(aliceDevice, relatesTo = null, transactionId = "t")227 cut.handleStep(step, alice, true)228 val state = cut.state.value229 state.shouldBeInstanceOf<Start>()230 state.senderUserId shouldBe alice231 state.senderDeviceId shouldBe aliceDevice232 val method = state.method233 method.shouldBeInstanceOf<ActiveSasVerificationMethod>()234 val subState = method.state.value235 subState.shouldBeInstanceOf<OwnSasStart>()236 subState.content shouldBe step237 }238 should("override event from lexicographically smaller deviceId") {239 val step = SasStartEventContent("AAAAAA", relatesTo = null, transactionId = "t")240 cut.handleStep(step, bob, false)241 val state = cut.state.value242 state.shouldBeInstanceOf<Start>()243 state.senderUserId shouldBe bob244 state.senderDeviceId shouldBe "AAAAAA"245 val method = state.method246 method.shouldBeInstanceOf<ActiveSasVerificationMethod>()247 val subState = method.state.value248 subState.shouldBeInstanceOf<TheirSasStart>()249 subState.content shouldBe step250 }251 }252 should("handle ${VerificationDoneEventContent::class.simpleName}") {253 val step = VerificationDoneEventContent(null, "t")254 cut.handleStep(step, bob, false)255 val state = cut.state.value256 state.shouldBeInstanceOf<PartlyDone>()257 state.isOurOwn shouldBe false258 }259 }260 context("current state is ${PartlyDone::class.simpleName}") {261 beforeTest {262 cut.handleStep(263 VerificationReadyEventContent(bobDevice, setOf(Sas, Unknown("u")), null, "t"),264 bob,265 false266 )267 cut.handleStep(SasStartEventContent(bobDevice, relatesTo = null, transactionId = "t"), bob, false)268 cut.handleStep(VerificationDoneEventContent(null, "t"), bob, false)269 cut.state.value.shouldBeInstanceOf<PartlyDone>()270 }271 checkNotAllowedStateChange(272 VerificationReadyEventContent(bobDevice, setOf(), null, "t"),273 SasStartEventContent(bobDevice, relatesTo = null, transactionId = "t"),274 )275 should("handle ${VerificationDoneEventContent::class.simpleName}") {276 val step = VerificationDoneEventContent(null, "t")277 cut.handleStep(step, alice, true)278 val state = cut.state.value279 state shouldBe Done280 }281 }282 context("current state is ${Done::class.simpleName}") {283 beforeTest {284 cut.handleStep(285 VerificationReadyEventContent(bobDevice, setOf(Sas, Unknown("u")), null, "t"),286 bob,287 false288 )289 cut.handleStep(SasStartEventContent(bobDevice, relatesTo = null, transactionId = "t"), bob, false)290 cut.handleStep(VerificationDoneEventContent(null, "t"), bob, false)291 cut.handleStep(VerificationDoneEventContent(null, "t"), alice, true)292 cut.state.value.shouldBeInstanceOf<Done>()293 }294 checkNotAllowedStateChange(295 VerificationReadyEventContent(bobDevice, setOf(), null, "t"),296 SasStartEventContent(bobDevice, relatesTo = null, transactionId = "t"),297 VerificationDoneEventContent(null, "t")298 )299 }300 context("current state is ${Cancel::class.simpleName}") {301 beforeTest {302 cut.handleStep(VerificationCancelEventContent(Code.User, "user", null, "t"), bob, false)303 cut.state.value.shouldBeInstanceOf<Cancel>()304 }305 checkNotAllowedStateChange(306 VerificationReadyEventContent(bobDevice, setOf(), null, "t"),307 SasStartEventContent(bobDevice, relatesTo = null, transactionId = "t"),308 VerificationDoneEventContent(null, "t"),309 )310 should("not send multiple cancel events") {311 cut.handleStep(VerificationDoneEventContent(null, "t"), bob, false)312 val state = cut.state.value313 state.shouldBeInstanceOf<Cancel>()314 state.content.code shouldBe Code.UnexpectedMessage...

Full Screen

Full Screen

ShouldSpecRootScope.kt

Source:ShouldSpecRootScope.kt Github

copy

Full Screen

...6typealias ShouldSpecRootContext = ShouldSpecRootScope7/**8 * Allows tests to be registered in the 'ShouldSpec' fashion.9 *10 * context("with context") {11 * should("do something") {12 * // test here13 * }14 * }15 *16 * or17 *18 * should("do something") {19 * // test here20 * }21 */22interface ShouldSpecRootScope : RootScope {23 /**24 * Adds a top level context scope to the spec.25 */26 fun context(name: String, test: suspend ShouldSpecContainerScope.() -> Unit) {27 addContainer(TestName("context ", name, false), false, null) {28 ShouldSpecContainerScope(this).test()29 }30 }31 /**32 * Adds a top level context scope to the spec.33 */34 fun xcontext(name: String, test: suspend ShouldSpecContainerScope.() -> Unit) {35 addContainer(TestName("context ", name, false), true, null) { ShouldSpecContainerScope(this).test() }36 }37 /**38 * Adds a top level context scope accepting config to the spec.39 */40 @ExperimentalKotest41 fun context(name: String): RootContainerWithConfigBuilder<ShouldSpecContainerScope> =42 RootContainerWithConfigBuilder(TestName("context ", name, false), false, this) { ShouldSpecContainerScope(it) }43 /**44 * Adds a disabled top level context scope accepting config to the spec.45 */46 @ExperimentalKotest47 fun xcontext(name: String): RootContainerWithConfigBuilder<ShouldSpecContainerScope> =48 RootContainerWithConfigBuilder(TestName("context ", name, false), true, this) { ShouldSpecContainerScope(it) }49 /**50 * Adds a top level test, with the given name and test function, with test config supplied51 * by invoking .config on the return of this function.52 */53 fun should(name: String): RootTestWithConfigBuilder =54 RootTestWithConfigBuilder(this, TestName("should ", name, true), false)55 fun xshould(name: String): RootTestWithConfigBuilder =56 RootTestWithConfigBuilder(this, TestName("should ", name, true), true)57 /**58 * Adds a top level test, with the given name and test function, with default test config.59 */60 fun should(name: String, test: suspend TestScope.() -> Unit) {61 addTest(TestName("should ", name, false), false, null, test)62 }...

Full Screen

Full Screen

ShouldSpecContainerScope.kt

Source:ShouldSpecContainerScope.kt Github

copy

Full Screen

...10typealias ShouldSpecContainerContext = ShouldSpecContainerScope11/**12 * A scope that allows tests to be registered using the syntax:13 *14 * context("some context")15 * should("some test")16 * should("some test").config(...)17 *18 */19@KotestTestScope20class ShouldSpecContainerScope(21 val testScope: TestScope,22) : AbstractContainerScope(testScope) {23 /**24 * Adds a nested context scope to this scope.25 */26 suspend fun context(name: String, test: suspend ShouldSpecContainerScope.() -> Unit) {27 registerContainer(TestName(name), false, null) { ShouldSpecContainerScope(this).test() }28 }29 /**30 * Adds a disabled nested context scope to this scope.31 */32 suspend fun xcontext(name: String, test: suspend ShouldSpecContainerScope.() -> Unit) {33 registerContainer(TestName(name), true, null) { ShouldSpecContainerScope(this).test() }34 }35 @ExperimentalKotest36 fun context(name: String): ContainerWithConfigBuilder<ShouldSpecContainerScope> {37 return ContainerWithConfigBuilder(TestName(name), this, false) { ShouldSpecContainerScope(it) }38 }39 @ExperimentalKotest40 fun xcontext(name: String): ContainerWithConfigBuilder<ShouldSpecContainerScope> {41 return ContainerWithConfigBuilder(TestName(name), this, true) { ShouldSpecContainerScope(it) }42 }43 suspend fun should(name: String): TestWithConfigBuilder {44 TestDslState.startTest(testScope.testCase.descriptor.append(name))45 return TestWithConfigBuilder(TestName("should ", name, false), this, false)46 }47 suspend fun xshould(name: String): TestWithConfigBuilder {48 TestDslState.startTest(testScope.testCase.descriptor.append(name))49 return TestWithConfigBuilder(TestName("should ", name, false), this, true)50 }51 suspend fun should(name: String, test: suspend TestScope.() -> Unit) {52 registerTest(TestName("should ", name, false), false, null, test)53 }54 suspend fun xshould(name: String, test: suspend TestScope.() -> Unit) {...

Full Screen

Full Screen

ProfileDataShouldSpec.kt

Source:ProfileDataShouldSpec.kt Github

copy

Full Screen

...9) :10 ShouldSpec(spec@{11 for (profile in allProfiles) {12 val client = profile.makeTestEndpoint()13 context("For profile ${profile.name}") {14 test(client, profile)15 }16 }17 }) {18}19public suspend inline fun <reified DataSet : Any> ShouldSpecContainerScope.givenAll(20 from: ServiceTestProfile<*, *>,21 require: Boolean = true,22 crossinline test: suspend TestContext.(DataSet) -> Unit23) {24 val dataSets = from.testData[DataSet::class].orEmpty() as List<DataSet>25 if (dataSets.isEmpty()) {26 if (require) {27 throw IllegalStateException("No ${DataSet::class.simpleName} specified for ${from.name}")28 } else {29 println("${this::class.simpleName} did not run for ${from.name}")30 }31 }32 for (dataSet in dataSets) {33 context("Given dataSet $dataSet") {34 test(dataSet)35 }36 delay(500)37 }38}39public suspend inline fun <Profile : ServiceTestProfile<*, DataSet>, reified DataSet : Any> ShouldSpecContainerScope.givenOne(40 from: Profile,41 require: Boolean = true,42 crossinline test: suspend TestContext.(DataSet) -> Unit43) {44 val dataSet = from.testData[DataSet::class].orEmpty().firstOrNull()45 if (dataSet == null) {46 if (require) {47 throw IllegalStateException("No ${DataSet::class.simpleName} specified for ${from.name}")48 } else {49 println("${this::class.simpleName} did not run for ${from.name}")50 }51 } else {52 context("Given dataSet $dataSet") {53 test(dataSet)54 }55 }56}...

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run Kotest automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Most used method in ShouldSpecContainerScope

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful