@@ -571,6 +571,85 @@ def test_api2_reply_sent(
571571 assert reply2 ["uuid" ] not in response .json ["items" ]
572572
573573
574+ def test_api2_reply_sent_unencrypted (journalist_app , journalist_api_token , test_files ):
575+ """handle_reply_sent returns 400 BadRequest if the reply is not PGP-encrypted."""
576+ with journalist_app .test_client () as app :
577+ source = test_files ["source" ]
578+ index = app .get (url_for ("api2.index" ), headers = get_api_headers (journalist_api_token ))
579+ source_version = index .json ["sources" ][source .uuid ]
580+
581+ event = Event (
582+ id = "400001" ,
583+ target = SourceTarget (source_uuid = source .uuid , version = source_version ),
584+ type = EventType .REPLY_SENT ,
585+ data = {"uuid" : str (uuid .uuid4 ()), "reply" : "not a pgp message" },
586+ )
587+ response = app .post (
588+ url_for ("api2.data" ),
589+ json = {"events" : [asdict (event )]},
590+ headers = get_api_headers (journalist_api_token ),
591+ )
592+ assert response .json ["events" ][event .id ][0 ] == 400
593+
594+
595+ def test_api2_reply_sent_duplicate_uuid (journalist_app , journalist_api_token , test_files ):
596+ """handle_reply_sent returns 409 Conflict if save_reply() would commit a duplicate UUID."""
597+ with journalist_app .test_client () as app :
598+ source = test_files ["source" ]
599+ reply = test_files ["replies" ][0 ]
600+
601+ reply_ct = app .get (
602+ url_for ("api.download_reply" , source_uuid = source .uuid , reply_uuid = reply .uuid ),
603+ headers = get_api_headers (journalist_api_token ),
604+ ).data
605+
606+ index = app .get (url_for ("api2.index" ), headers = get_api_headers (journalist_api_token ))
607+ source_version = index .json ["sources" ][source .uuid ]
608+
609+ shared_uuid = str (uuid .uuid4 ())
610+ event1 = Event (
611+ id = "409001" ,
612+ target = SourceTarget (source_uuid = source .uuid , version = source_version ),
613+ type = EventType .REPLY_SENT ,
614+ data = {"uuid" : shared_uuid , "reply" : ascii_armor (reply_ct )},
615+ )
616+ response1 = app .post (
617+ url_for ("api2.data" ),
618+ json = {"events" : [asdict (event1 )]},
619+ headers = get_api_headers (journalist_api_token ),
620+ )
621+ assert response1 .json ["events" ]["409001" ] == [200 , None ]
622+
623+ # A different event that tries to commit the same reply UUID:
624+ event2 = Event (
625+ id = "409002" ,
626+ target = SourceTarget (source_uuid = source .uuid , version = source_version ),
627+ type = EventType .REPLY_SENT ,
628+ data = {"uuid" : shared_uuid , "reply" : ascii_armor (reply_ct )},
629+ )
630+ response2 = app .post (
631+ url_for ("api2.data" ),
632+ json = {"events" : [asdict (event2 )]},
633+ headers = get_api_headers (journalist_api_token ),
634+ )
635+ assert response2 .json ["events" ]["409002" ][0 ] == 409
636+
637+ # A different event that tries to use a submission's UUID as the reply UUID:
638+ submission = test_files ["submissions" ][0 ]
639+ event3 = Event (
640+ id = "409003" ,
641+ target = SourceTarget (source_uuid = source .uuid , version = source_version ),
642+ type = EventType .REPLY_SENT ,
643+ data = {"uuid" : submission .uuid , "reply" : ascii_armor (reply_ct )},
644+ )
645+ response3 = app .post (
646+ url_for ("api2.data" ),
647+ json = {"events" : [asdict (event3 )]},
648+ headers = get_api_headers (journalist_api_token ),
649+ )
650+ assert response3 .json ["events" ]["409003" ][0 ] == 409
651+
652+
574653def test_api2_item_deleted (
575654 journalist_app ,
576655 journalist_api_token ,
0 commit comments