View Javadoc
1   package civitas.bboard.server.controllers.tests;
2   
3   import static org.junit.jupiter.api.Assertions.assertEquals;
4   import static org.junit.jupiter.api.Assertions.assertThrows;
5   import static org.mockito.Mockito.verify;
6   
7   import java.io.IOException;
8   import java.math.BigInteger;
9   
10  import org.bouncycastle.crypto.CryptoException;
11  import org.junit.jupiter.api.DisplayName;
12  import org.junit.jupiter.api.Test;
13  import org.mockito.InjectMocks;
14  import org.mockito.Mock;
15  import org.slf4j.MarkerFactory;
16  
17  import civitas.bboard.common.BBPostRepository;
18  import civitas.bboard.common.tests.BBPostTestData;
19  import civitas.bboard.server.GetBoardForId;
20  import civitas.bboard.server.controllers.CommunicableException;
21  import civitas.bboard.server.controllers.PostController;
22  import civitas.bboard.server.controllers.PostDTO;
23  import civitas.bboard.server.electioncache.UpdateCache;
24  import civitas.common.CheckAccess;
25  import civitas.common.LoggerService;
26  import civitas.common.Operation;
27  import civitas.common.board.tests.BulletinBoardTestData;
28  import civitas.common.tests.EnvironmentState;
29  import civitas.common.tests.RandomAwareTestBase;
30  import civitas.crypto.messagedigest.CryptoHash;
31  import civitas.crypto.rsapublickey.VerifyPublicKeySignature;
32  import jakarta.xml.bind.JAXBException;
33  
34  class PostControllerTest extends RandomAwareTestBase implements BulletinBoardTestData, BBPostTestData {
35  
36  	@InjectMocks
37  	PostController postController;
38  
39  	@Mock
40  	CheckAccess checkAccess;
41  
42  	@Mock
43  	GetBoardForId getBoardForId;
44  
45  	@Mock
46  	UpdateCache updateCache;
47  
48  	@Mock
49  	BBPostRepository bBPostRepository;
50  
51  	@Mock
52  	CryptoHash cryptoHash;
53  
54  	@Mock
55  	LoggerService logger;
56  
57  	@Mock
58  	VerifyPublicKeySignature verifyPublicKeySignature;
59  
60  	@Test
61  	@DisplayName(
62  			"""
63  			records a post to a bulletin board and returns the time of recording
64  			- checks access right
65  			- verifies the signature
66  			- retrieves the last post for the serial and hash
67  			- computes the hash using the previous hash and the signature
68  			- records the hash, serial and current time in the post and saves it
69  			- updates the election cache
70  			- logs the transaction with its meta and board id
71  			""")
72  	void test() throws CommunicableException, JAXBException, IOException, CryptoException {
73  		assertEquals(
74  				CURRENT_TIME,
75  				postController.apply(
76  						BULLETIN_BOARD_ID,
77  						new PostDTO(
78  								BOARD_CLOSED_CONTENT_COMMITMENT_META,
79  								BOARD_CLOSED_CONTENT_COMMITMENT_XML,
80  								BOARD_CLOSED_CONTENT_COMMITMENT_SIGNATURE)));
81  		verify(checkAccess)
82  				.apply(
83  						Operation.POST,
84  						BOARD_CLOSED_CONTENT_COMMITMENT_SIGNATURE.getSignerPubKey(),
85  						BOARD_CLOSED_CONTENT_COMMITMENT_META + BULLETIN_BOARD_ID);
86  		verify(verifyPublicKeySignature)
87  				.apply(BOARD_CLOSED_CONTENT_COMMITMENT_SIGNATURE, BOARD_CLOSED_CONTENT_COMMITMENT_XML.getBytes());
88  		verify(getBoardForId).apply(BULLETIN_BOARD_ID, true);
89  		verify(updateCache)
90  				.apply(
91  						BULLETIN_BOARD_ID,
92  						BOARD_CLOSED_CONTENT_COMMITMENT_META,
93  						BOARD_CLOSED_CONTENT_COMMITMENT_XML,
94  						CURRENT_TIME);
95  		verify(bBPostRepository).findByBbidOrderBySerialDesc(BULLETIN_BOARD_ID);
96  		verify(cryptoHash)
97  				.apply(
98  						BBPOST.hash,
99  						BigInteger.valueOf(CURRENT_TIME).toByteArray(),
100 						BOARD_CLOSED_CONTENT_COMMITMENT_SIGNATURE.signatureBytes);
101 		verify(logger)
102 				.apply(MarkerFactory.getMarker("bbs_post"), BOARD_CLOSED_CONTENT_COMMITMENT_META + BULLETIN_BOARD_ID);
103 		verify(bBPostRepository).save(NEXT_POST);
104 	}
105 
106 	@Test
107 	@DisplayName("if the signature does not check, a CommunicableException is thrown")
108 	void test1() {
109 		assertThrows(
110 				CommunicableException.class,
111 				() -> postController.apply(
112 						BULLETIN_BOARD_ID,
113 						new PostDTO(
114 								BOARD_CLOSED_CONTENT_COMMITMENT_META,
115 								BOARD_CLOSED_CONTENT_COMMITMENT_XML,
116 								BOARD_CLOSED_CONTENT_COMMITMENT_SIGNATURE_BAD)));
117 	}
118 
119 	@Test
120 	@DisplayName("if the signer is not authorized to post, a SecurityException is thrown")
121 	void test2() {
122 		assertThrows(
123 				SecurityException.class,
124 				() -> postController.apply(
125 						BULLETIN_BOARD_ID,
126 						new PostDTO(
127 								BOARD_CLOSED_CONTENT_COMMITMENT_META,
128 								BOARD_CLOSED_CONTENT_COMMITMENT_XML,
129 								BOARD_CLOSED_CONTENT_COMMITMENT_SIGNATURE_BAD_ACTOR)));
130 	}
131 
132 	@Test
133 	@DisplayName("if there is no previous post the hash uses only the time and signature, and the serial is 1 ")
134 	void test3() throws CommunicableException {
135 		given(EnvironmentState.EMPTY_BOARD);
136 		Long actual = postController.apply(
137 				BULLETIN_BOARD_ID,
138 				new PostDTO(
139 						BOARD_CLOSED_CONTENT_COMMITMENT_META,
140 						BOARD_CLOSED_CONTENT_COMMITMENT_XML,
141 						BOARD_CLOSED_CONTENT_COMMITMENT_SIGNATURE));
142 		verify(cryptoHash)
143 				.apply(
144 						new byte[0],
145 						BigInteger.valueOf(CURRENT_TIME).toByteArray(),
146 						BOARD_CLOSED_CONTENT_COMMITMENT_SIGNATURE.signatureBytes);
147 		verify(bBPostRepository).save(FIRST_POST);
148 		assertEquals(CURRENT_TIME, actual);
149 	}
150 }