1 package civitas.bboard.server.controllers;
2
3 import java.io.IOException;
4 import java.math.BigInteger;
5 import java.security.KeyStoreException;
6 import java.security.NoSuchAlgorithmException;
7 import java.security.PrivateKey;
8 import java.security.PublicKey;
9 import java.security.UnrecoverableKeyException;
10 import java.security.cert.CertificateException;
11
12 import org.bouncycastle.crypto.CryptoException;
13 import org.slf4j.MarkerFactory;
14 import org.springframework.beans.factory.annotation.Autowired;
15 import org.springframework.stereotype.Controller;
16 import org.springframework.web.bind.annotation.PathVariable;
17 import org.springframework.web.bind.annotation.PostMapping;
18 import org.springframework.web.bind.annotation.RequestBody;
19 import org.springframework.web.bind.annotation.ResponseBody;
20
21 import civitas.bboard.common.BBPost;
22 import civitas.bboard.common.BBPostRepository;
23 import civitas.bboard.server.GetBoardForId;
24 import civitas.bboard.server.electioncache.UpdateCache;
25 import civitas.common.CheckAccess;
26 import civitas.common.Configuration;
27 import civitas.common.ConvertToXml;
28 import civitas.common.GetPrivateKey;
29 import civitas.common.GetPublicKey;
30 import civitas.common.LoggerService;
31 import civitas.common.Operation;
32 import civitas.crypto.messagedigest.CryptoHash;
33 import civitas.crypto.rsapublickey.VerifyPublicKeySignature;
34 import civitas.crypto.signature.SignWithPublicKey;
35 import civitas.crypto.signature.Signature;
36 import civitas.util.GetCurrentTime;
37 import jakarta.xml.bind.JAXBException;
38
39 @Controller
40
41 public class PostController {
42 @Autowired
43 GetBoardForId getBoardForId;
44
45 @Autowired
46 BBPostRepository bBPostRepository;
47
48 @Autowired
49 CryptoHash cryptoHash;
50
51 @Autowired
52 LoggerService loggerController;
53
54 @Autowired
55 UpdateCache updateCache;
56
57 @Autowired
58 ConvertToXml convertToXml;
59
60 @Autowired
61 SignWithPublicKey signWithPublicKey;
62
63 @Autowired
64 GetPrivateKey getPrivateKey;
65
66 @Autowired
67 GetPublicKey getPublicKey;
68
69 @Autowired
70 GetCurrentTime getCurrentTime;
71
72 @Autowired
73 VerifyPublicKeySignature verifyPublicKeySignature;
74
75 @Autowired
76 CheckAccess checkAccess;
77
78 @Autowired
79 Configuration configuration;
80
81 @PostMapping("/boards/{bbid}")
82 @ResponseBody
83 public Long apply(@PathVariable("bbid") final String bbid, @RequestBody final PostDTO dto)
84 throws CommunicableException {
85 String objectID = dto.meta() + bbid;
86 checkAccess.apply(Operation.POST, dto.signature().getSignerPubKey(), objectID);
87 try {
88 if (!verifyPublicKeySignature.apply(
89 dto.signature(), dto.payloadXml().getBytes())) {
90 throw new CommunicableException("bad signature");
91 }
92 } catch (CryptoException e) {
93 throw new CommunicableException("bad signature (but in blue)");
94 }
95
96 loggerController.apply(MarkerFactory.getMarker("bbs_post"), objectID);
97
98 getBoardForId.apply(bbid, true);
99
100 long t = getCurrentTime.apply();
101
102 Iterable<BBPost> lastPosts = bBPostRepository.findByBbidOrderBySerialDesc(bbid);
103
104 BBPost lastPost = null;
105 byte[] hash = new byte[0];
106 if (lastPosts.iterator().hasNext()) {
107 lastPost = lastPosts.iterator().next();
108 hash = lastPost.hash;
109 }
110 byte[] newhash = cryptoHash.apply(hash, BigInteger.valueOf(t).toByteArray(), dto.signature().signatureBytes);
111
112 try {
113 updateCache.apply(bbid, dto.meta(), dto.payloadXml(), t);
114 } catch (IOException | JAXBException e) {
115 throw new CommunicableException("bad payload xml");
116 }
117
118 Long serial = 0L;
119 if (lastPost != null) {
120 serial = lastPost.serial;
121 }
122 bBPostRepository.save(new BBPost(bbid, serial + 1, t, dto.meta(), dto.payloadXml(), dto.signature(), newhash));
123
124 return t;
125 }
126
127 public long apply(final String bbid, final String meta, final Object mesg)
128 throws JAXBException, UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException,
129 CertificateException, IOException, CryptoException, CommunicableException {
130 String msg = convertToXml.apply(mesg);
131 PrivateKey privKey =
132 getPrivateKey.apply(configuration.storeFile, configuration.storePassword, configuration.serverKeyEntry);
133 PublicKey pubKey =
134 getPublicKey.apply(configuration.storeFile, configuration.storePassword, configuration.serverKeyEntry);
135 Signature sign = signWithPublicKey.apply(privKey, pubKey, msg.getBytes());
136 return apply(bbid, new PostDTO(meta, msg, sign));
137 }
138 }