Coverage Report

Created: 2024-01-26 01:52

/work/toxcore/group_moderation.h
Line
Count
Source
1
/* SPDX-License-Identifier: GPL-3.0-or-later
2
 * Copyright © 2016-2020 The TokTok team.
3
 * Copyright © 2015 Tox project.
4
 */
5
6
/**
7
 * An implementation of massive text only group chats.
8
 */
9
10
#ifndef C_TOXCORE_TOXCORE_GROUP_MODERATION_H
11
#define C_TOXCORE_TOXCORE_GROUP_MODERATION_H
12
13
#include <stdbool.h>
14
#include <stdint.h>
15
16
#include "DHT.h"
17
#include "logger.h"
18
19
#ifdef __cplusplus
20
extern "C" {
21
#endif
22
23
6.89k
#define MOD_MODERATION_HASH_SIZE CRYPTO_SHA256_SIZE
24
4.98k
#define MOD_LIST_ENTRY_SIZE SIG_PUBLIC_KEY_SIZE
25
2.82k
#define MOD_SANCTION_HASH_SIZE CRYPTO_SHA256_SIZE
26
27
826
#define TIME_STAMP_SIZE sizeof(uint64_t)
28
29
/* The packed size of a Mod_Sanction_Creds */
30
1.18k
#define MOD_SANCTIONS_CREDS_SIZE (sizeof(uint32_t) + MOD_SANCTION_HASH_SIZE + sizeof(uint16_t) +\
31
1.18k
                                       SIG_PUBLIC_KEY_SIZE + SIGNATURE_SIZE)
32
33
/* The packed size of a Mod_Sanction */
34
460
#define MOD_SANCTION_PACKED_SIZE (SIG_PUBLIC_KEY_SIZE + TIME_STAMP_SIZE + 1 + ENC_PUBLIC_KEY_SIZE + SIGNATURE_SIZE)
35
36
/* The max size of a groupchat packet with 100 bytes reserved for header data */
37
1.30k
#define MAX_PACKET_SIZE_NO_HEADERS 49900
38
39
/* The maximum possible number of moderators that can be sent in a group packet sequence. */
40
1.00k
#define MOD_MAX_NUM_MODERATORS_LIMIT (((MAX_PACKET_SIZE_NO_HEADERS) / (MOD_LIST_ENTRY_SIZE)))
41
42
/* The maximum number of moderators that we allow in a group: 100 */
43
1.00k
#define MOD_MAX_NUM_MODERATORS       ((MOD_MAX_NUM_MODERATORS_LIMIT / 16) + 3)
44
45
/* The maximum number of sanctions that be sent in a group packet sequence. */
46
294
#define MOD_MAX_NUM_SANCTIONS_LIMIT  (((MAX_PACKET_SIZE_NO_HEADERS - (MOD_SANCTIONS_CREDS_SIZE)) / (MOD_SANCTION_PACKED_SIZE)))
47
48
/* The maximum number of sanctions that we allow in a group: 30 */
49
573
#define MOD_MAX_NUM_SANCTIONS        (MOD_MAX_NUM_SANCTIONS_LIMIT / 12)
50
51
typedef enum Mod_Sanction_Type {
52
    SA_OBSERVER = 0x00,
53
    SA_INVALID  = 0x01,
54
} Mod_Sanction_Type;
55
56
typedef struct Mod_Sanction_Creds {
57
    uint32_t    version;
58
    uint8_t     hash[MOD_SANCTION_HASH_SIZE];    // hash of all sanctions list signatures + version
59
    uint16_t    checksum;  // a sum of the hash
60
    uint8_t     sig_pk[SIG_PUBLIC_KEY_SIZE];    // Last mod to have modified the sanctions list
61
    uint8_t     sig[SIGNATURE_SIZE];    // signature of hash, signed by sig_pk
62
} Mod_Sanction_Creds;
63
64
/** Holds data pertaining to a peer who has been sanctioned. */
65
typedef struct Mod_Sanction {
66
    uint8_t     setter_public_sig_key[SIG_PUBLIC_KEY_SIZE];
67
68
    // TODO(Jfreegman): This timestamp can potentially be used to track a user across
69
    // different group chats if they're a moderator and set many sanctions across the
70
    // different groups. This should be addressed in the future.
71
    uint64_t    time_set;
72
73
    uint8_t     type;
74
    uint8_t     target_public_enc_key[ENC_PUBLIC_KEY_SIZE];
75
76
    /* Signature of all above packed data signed by the owner of public_sig_key */
77
    uint8_t     signature[SIGNATURE_SIZE];
78
} Mod_Sanction;
79
80
typedef struct Moderation {
81
    const       Memory *mem;
82
    const       Logger *log;
83
84
    Mod_Sanction *sanctions;
85
    uint16_t    num_sanctions;
86
87
    Mod_Sanction_Creds sanctions_creds;
88
89
    uint8_t     **mod_list;  // array of public signature keys of all the mods
90
    uint16_t    num_mods;
91
92
    // copies from parent/sibling chat/shared state objects
93
    uint8_t     founder_public_sig_key[SIG_PUBLIC_KEY_SIZE];
94
    uint8_t     self_public_sig_key[SIG_PUBLIC_KEY_SIZE];
95
    uint8_t     self_secret_sig_key[SIG_SECRET_KEY_SIZE];
96
    uint32_t    shared_state_version;
97
} Moderation;
98
99
/** @brief Returns the size in bytes of the packed moderation list. */
100
non_null()
101
uint16_t mod_list_packed_size(const Moderation *moderation);
102
103
/** @brief Unpacks data into the moderator list.
104
 *
105
 * @param data should contain num_mods entries of size MOD_LIST_ENTRY_SIZE.
106
 *
107
 * Returns length of unpacked data on success.
108
 * Returns -1 on failure.
109
 */
110
non_null()
111
int mod_list_unpack(Moderation *moderation, const uint8_t *data, uint16_t length, uint16_t num_mods);
112
113
/** @brief Packs moderator list into data.
114
 * @param data must have room for the number of bytes returned by `mod_list_packed_size`.
115
 */
116
non_null()
117
void mod_list_pack(const Moderation *moderation, uint8_t *data);
118
119
/** @brief Creates a new moderator list hash and puts it in `hash`.
120
 *
121
 * @param hash must have room for at least MOD_MODERATION_HASH_SIZE bytes.
122
 *
123
 * If num_mods is 0 the hash is zeroed.
124
 *
125
 * Returns true on sucess.
126
 */
127
non_null()
128
bool mod_list_make_hash(const Moderation *moderation, uint8_t *hash);
129
130
/** @brief Puts a sha256 hash of `packed_mod_list` of `length` bytes in `hash`.
131
 *
132
 * @param hash must have room for at least MOD_MODERATION_HASH_SIZE bytes.
133
 */
134
non_null()
135
void mod_list_get_data_hash(uint8_t *hash, const uint8_t *packed_mod_list, uint16_t length);
136
137
/** @brief Removes moderator at index-th position in the moderator list.
138
 *
139
 * Returns true on success.
140
 */
141
non_null()
142
bool mod_list_remove_index(Moderation *moderation, uint16_t index);
143
144
/** @brief Removes public_sig_key from the moderator list.
145
 *
146
 * Returns true on success.
147
 */
148
non_null()
149
bool mod_list_remove_entry(Moderation *moderation, const uint8_t *public_sig_key);
150
151
/** @brief Adds a mod to the moderator list.
152
 *
153
 * @param mod_data must be MOD_LIST_ENTRY_SIZE bytes.
154
 *
155
 * Returns true on success.
156
 */
157
non_null()
158
bool mod_list_add_entry(Moderation *moderation, const uint8_t *mod_data);
159
160
/** @return true if the public signature key belongs to a moderator or the founder */
161
non_null()
162
bool mod_list_verify_sig_pk(const Moderation *moderation, const uint8_t *sig_pk);
163
164
/** @brief Frees all memory associated with the moderator list and sets num_mods to 0. */
165
nullable(1)
166
void mod_list_cleanup(Moderation *moderation);
167
168
/** @brief Returns the size in bytes of num_sanctions packed sanctions. */
169
uint16_t sanctions_list_packed_size(uint16_t num_sanctions);
170
171
/** @brief Packs sanctions into data. Additionally packs the sanctions credentials into creds.
172
 *
173
 * @param data The byte array being packed. Must have room for the number of bytes returned
174
 *   by `sanctions_list_packed_size`.
175
 * @param length The size of the byte array.
176
 * @param sanctions The sanctions list.
177
 * @param num_sanctions The number of sanctions in the sanctions list. This value must be the same
178
 *   value used when calling `sanctions_list_packed_size`.
179
 * @param creds The credentials object to fill.
180
 *
181
 * @retval The length of packed data on success.
182
 * @retval -1 on failure.
183
 */
184
non_null(1) nullable(3, 5)
185
int sanctions_list_pack(uint8_t *data, uint16_t length, const Mod_Sanction *sanctions, uint16_t num_sanctions,
186
                        const Mod_Sanction_Creds *creds);
187
188
/** @brief Unpacks sanctions and new sanctions credentials.
189
 *
190
 * @param sanctions The sanctions array the sanctions data is unpacked into.
191
 * @param creds The creds object the creds data is unpacked into.
192
 * @param max_sanctions The maximum number of sanctions that the sanctions array can hold.
193
 * @param data The packed data array.
194
 * @param length The size of the packed data.
195
 * @param processed_data_len If non-null, will contain the number of processed bytes on success.
196
 *
197
 * @retval The number of unpacked entries on success.
198
 * @retval -1 on failure.
199
 */
200
non_null(1, 2, 4) nullable(6)
201
int sanctions_list_unpack(Mod_Sanction *sanctions, Mod_Sanction_Creds *creds, uint16_t max_sanctions,
202
                          const uint8_t *data, uint16_t length, uint16_t *processed_data_len);
203
204
/** @brief Packs sanction list credentials into data.
205
 *
206
 * @param data must have room for MOD_SANCTIONS_CREDS_SIZE bytes.
207
 *
208
 * Returns length of packed data.
209
 */
210
non_null()
211
uint16_t sanctions_creds_pack(const Mod_Sanction_Creds *creds, uint8_t *data);
212
213
/** @brief Unpacks sanctions credentials into creds from data.
214
 *
215
 * @param data must have room for MOD_SANCTIONS_CREDS_SIZE bytes.
216
 *
217
 * Returns the length of the data processed.
218
 */
219
non_null()
220
uint16_t sanctions_creds_unpack(Mod_Sanction_Creds *creds, const uint8_t *data);
221
222
/** @brief Updates sanction list credentials.
223
 *
224
 * Increment version, replace sig_pk with your own, update hash to reflect new
225
 * sanction list, and sign new hash signature.
226
 *
227
 * Returns true on success.
228
 */
229
non_null()
230
bool sanctions_list_make_creds(Moderation *moderation);
231
232
/** @brief Validates all sanctions list entries as well as the list itself.
233
 *
234
 * Returns true if all entries are valid.
235
 * Returns false if one or more entries are invalid.
236
 */
237
non_null()
238
bool sanctions_list_check_integrity(const Moderation *moderation, const Mod_Sanction_Creds *creds,
239
                                    const Mod_Sanction *sanctions, uint16_t num_sanctions);
240
241
/** @brief Adds an entry to the sanctions list.
242
 *
243
 * The entry is first validated and the resulting new sanction list is
244
 * compared against the new credentials.
245
 *
246
 * Entries must be unique.
247
 *
248
 * Returns true on success.
249
 */
250
non_null(1, 2) nullable(3)
251
bool sanctions_list_add_entry(Moderation *moderation, const Mod_Sanction *sanction, const Mod_Sanction_Creds *creds);
252
253
/** @brief Creates a new sanction entry for `public_key` where type is one of Mod_Sanction_Type.
254
 *
255
 * New entry is signed and placed in the sanctions list.
256
 *
257
 * Returns true on success.
258
 */
259
non_null()
260
bool sanctions_list_make_entry(Moderation *moderation, const uint8_t *public_key, Mod_Sanction *sanction,
261
                               uint8_t type);
262
263
/** @return true if public key is in the observer list. */
264
non_null()
265
bool sanctions_list_is_observer(const Moderation *moderation, const uint8_t *public_key);
266
267
/** @return true if sanction already exists in the sanctions list. */
268
non_null()
269
bool sanctions_list_entry_exists(const Moderation *moderation, const Mod_Sanction *sanction);
270
271
/** @brief Removes observer entry for public key from sanction list.
272
 *
273
 * If creds is NULL we make new credentials (this should only be done by a moderator or founder)
274
 *
275
 * Returns false on failure or if entry was not found.
276
 */
277
non_null(1, 2) nullable(3)
278
bool sanctions_list_remove_observer(Moderation *moderation, const uint8_t *public_key,
279
                                    const Mod_Sanction_Creds *creds);
280
281
/** @brief Replaces all sanctions list signatures made by public_sig_key with the caller's.
282
 *
283
 * This is called whenever the founder demotes a moderator.
284
 *
285
 * Returns the number of entries re-signed.
286
 */
287
non_null()
288
uint16_t sanctions_list_replace_sig(Moderation *moderation, const uint8_t *public_sig_key);
289
290
non_null()
291
void sanctions_list_cleanup(Moderation *moderation);
292
293
#ifdef __cplusplus
294
} /* extern "C" */
295
#endif
296
297
#endif /* C_TOXCORE_TOXCORE_GROUP_MODERATION_H */