tomato-testing/toxcore/group_moderation.h
Green Sky a3126d581b Squashed 'external/toxcore/c-toxcore/' changes from 67badf694..82460b212
82460b212 feat: add ngc events
24b54722a fix: Ensure we have allocators available for the error paths.
48dbcfebc cleanup: Remove redundant `-DSODIUM_EXPORT` from definitions.
0cef46ee9 cleanup: Fix a few more clang-tidy warnings.
0c5b918e9 cleanup: Fix a few more clang-tidy warnings.
4d3c97f49 cleanup: Enforce stricter identifier naming using clang-tidy.
a549807df refactor: Add `mem` module to allow tests to override allocators.
6133fb153 chore: Add devcontainer setup for codespaces.
620e07ecd chore: Set a timeout for tests started using Conan
c0ec33b16 chore: Migrate Windows CI from Appveyor to Azure DevOps
8ed47f3ef fix incorrect documentation
a1e245841 docs: Fix doxygen config and remove some redundant comments.
b0f633185 chore: Fix the Android CI job
7469a529b fix: Add missing `#include <array>`.
2b1a6b0d2 add missing ngc constants getter declarations and definitions
2e02d5637 chore: Add missing module dependencies.
REVERT: 67badf694 feat: add ngc events

git-subtree-dir: external/toxcore/c-toxcore
git-subtree-split: 82460b2124216af1ac9d63060de310a682a2fd15
2023-10-10 19:37:39 +02:00

298 lines
10 KiB
C

/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2016-2020 The TokTok team.
* Copyright © 2015 Tox project.
*/
/**
* An implementation of massive text only group chats.
*/
#ifndef C_TOXCORE_TOXCORE_GROUP_MODERATION_H
#define C_TOXCORE_TOXCORE_GROUP_MODERATION_H
#include <stdbool.h>
#include <stdint.h>
#include "DHT.h"
#include "logger.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MOD_MODERATION_HASH_SIZE CRYPTO_SHA256_SIZE
#define MOD_LIST_ENTRY_SIZE SIG_PUBLIC_KEY_SIZE
#define MOD_SANCTION_HASH_SIZE CRYPTO_SHA256_SIZE
#define TIME_STAMP_SIZE sizeof(uint64_t)
/* The packed size of a Mod_Sanction_Creds */
#define MOD_SANCTIONS_CREDS_SIZE (sizeof(uint32_t) + MOD_SANCTION_HASH_SIZE + sizeof(uint16_t) +\
SIG_PUBLIC_KEY_SIZE + SIGNATURE_SIZE)
/* The packed size of a Mod_Sanction */
#define MOD_SANCTION_PACKED_SIZE (SIG_PUBLIC_KEY_SIZE + TIME_STAMP_SIZE + 1 + ENC_PUBLIC_KEY_SIZE + SIGNATURE_SIZE)
/* The max size of a groupchat packet with 100 bytes reserved for header data */
#define MAX_PACKET_SIZE_NO_HEADERS 49900
/* The maximum possible number of moderators that can be sent in a group packet sequence. */
#define MOD_MAX_NUM_MODERATORS_LIMIT (((MAX_PACKET_SIZE_NO_HEADERS) / (MOD_LIST_ENTRY_SIZE)))
/* The maximum number of moderators that we allow in a group: 100 */
#define MOD_MAX_NUM_MODERATORS ((MOD_MAX_NUM_MODERATORS_LIMIT / 16) + 3)
/* The maximum number of sanctions that be sent in a group packet sequence. */
#define MOD_MAX_NUM_SANCTIONS_LIMIT (((MAX_PACKET_SIZE_NO_HEADERS - (MOD_SANCTIONS_CREDS_SIZE)) / (MOD_SANCTION_PACKED_SIZE)))
/* The maximum number of sanctions that we allow in a group: 30 */
#define MOD_MAX_NUM_SANCTIONS (MOD_MAX_NUM_SANCTIONS_LIMIT / 12)
typedef enum Mod_Sanction_Type {
SA_OBSERVER = 0x00,
SA_INVALID = 0x01,
} Mod_Sanction_Type;
typedef struct Mod_Sanction_Creds {
uint32_t version;
uint8_t hash[MOD_SANCTION_HASH_SIZE]; // hash of all sanctions list signatures + version
uint16_t checksum; // a sum of the hash
uint8_t sig_pk[SIG_PUBLIC_KEY_SIZE]; // Last mod to have modified the sanctions list
uint8_t sig[SIGNATURE_SIZE]; // signature of hash, signed by sig_pk
} Mod_Sanction_Creds;
/** Holds data pertaining to a peer who has been sanctioned. */
typedef struct Mod_Sanction {
uint8_t setter_public_sig_key[SIG_PUBLIC_KEY_SIZE];
// TODO(Jfreegman): This timestamp can potentially be used to track a user across
// different group chats if they're a moderator and set many sanctions across the
// different groups. This should be addressed in the future.
uint64_t time_set;
uint8_t type;
uint8_t target_public_enc_key[ENC_PUBLIC_KEY_SIZE];
/* Signature of all above packed data signed by the owner of public_sig_key */
uint8_t signature[SIGNATURE_SIZE];
} Mod_Sanction;
typedef struct Moderation {
const Memory *mem;
const Logger *log;
Mod_Sanction *sanctions;
uint16_t num_sanctions;
Mod_Sanction_Creds sanctions_creds;
uint8_t **mod_list; // array of public signature keys of all the mods
uint16_t num_mods;
// copies from parent/sibling chat/shared state objects
uint8_t founder_public_sig_key[SIG_PUBLIC_KEY_SIZE];
uint8_t self_public_sig_key[SIG_PUBLIC_KEY_SIZE];
uint8_t self_secret_sig_key[SIG_SECRET_KEY_SIZE];
uint32_t shared_state_version;
} Moderation;
/** @brief Returns the size in bytes of the packed moderation list. */
non_null()
uint16_t mod_list_packed_size(const Moderation *moderation);
/** @brief Unpacks data into the moderator list.
*
* @param data should contain num_mods entries of size MOD_LIST_ENTRY_SIZE.
*
* Returns length of unpacked data on success.
* Returns -1 on failure.
*/
non_null()
int mod_list_unpack(Moderation *moderation, const uint8_t *data, uint16_t length, uint16_t num_mods);
/** @brief Packs moderator list into data.
* @param data must have room for the number of bytes returned by `mod_list_packed_size`.
*/
non_null()
void mod_list_pack(const Moderation *moderation, uint8_t *data);
/** @brief Creates a new moderator list hash and puts it in `hash`.
*
* @param hash must have room for at least MOD_MODERATION_HASH_SIZE bytes.
*
* If num_mods is 0 the hash is zeroed.
*
* Returns true on sucess.
*/
non_null()
bool mod_list_make_hash(const Moderation *moderation, uint8_t *hash);
/** @brief Puts a sha256 hash of `packed_mod_list` of `length` bytes in `hash`.
*
* @param hash must have room for at least MOD_MODERATION_HASH_SIZE bytes.
*/
non_null()
void mod_list_get_data_hash(uint8_t *hash, const uint8_t *packed_mod_list, uint16_t length);
/** @brief Removes moderator at index-th position in the moderator list.
*
* Returns true on success.
*/
non_null()
bool mod_list_remove_index(Moderation *moderation, uint16_t index);
/** @brief Removes public_sig_key from the moderator list.
*
* Returns true on success.
*/
non_null()
bool mod_list_remove_entry(Moderation *moderation, const uint8_t *public_sig_key);
/** @brief Adds a mod to the moderator list.
*
* @param mod_data must be MOD_LIST_ENTRY_SIZE bytes.
*
* Returns true on success.
*/
non_null()
bool mod_list_add_entry(Moderation *moderation, const uint8_t *mod_data);
/** @return true if the public signature key belongs to a moderator or the founder */
non_null()
bool mod_list_verify_sig_pk(const Moderation *moderation, const uint8_t *sig_pk);
/** @brief Frees all memory associated with the moderator list and sets num_mods to 0. */
nullable(1)
void mod_list_cleanup(Moderation *moderation);
/** @brief Returns the size in bytes of num_sanctions packed sanctions. */
uint16_t sanctions_list_packed_size(uint16_t num_sanctions);
/** @brief Packs sanctions into data. Additionally packs the sanctions credentials into creds.
*
* @param data The byte array being packed. Must have room for the number of bytes returned
* by `sanctions_list_packed_size`.
* @param length The size of the byte array.
* @param sanctions The sanctions list.
* @param num_sanctions The number of sanctions in the sanctions list. This value must be the same
* value used when calling `sanctions_list_packed_size`.
* @param creds The credentials object to fill.
*
* @retval The length of packed data on success.
* @retval -1 on failure.
*/
non_null(1) nullable(3, 5)
int sanctions_list_pack(uint8_t *data, uint16_t length, const Mod_Sanction *sanctions, uint16_t num_sanctions,
const Mod_Sanction_Creds *creds);
/** @brief Unpacks sanctions and new sanctions credentials.
*
* @param sanctions The sanctions array the sanctions data is unpacked into.
* @param creds The creds object the creds data is unpacked into.
* @param max_sanctions The maximum number of sanctions that the sanctions array can hold.
* @param data The packed data array.
* @param length The size of the packed data.
* @param processed_data_len If non-null, will contain the number of processed bytes on success.
*
* @retval The number of unpacked entries on success.
* @retval -1 on failure.
*/
non_null(1, 2, 4) nullable(6)
int sanctions_list_unpack(Mod_Sanction *sanctions, Mod_Sanction_Creds *creds, uint16_t max_sanctions,
const uint8_t *data, uint16_t length, uint16_t *processed_data_len);
/** @brief Packs sanction list credentials into data.
*
* @param data must have room for MOD_SANCTIONS_CREDS_SIZE bytes.
*
* Returns length of packed data.
*/
non_null()
uint16_t sanctions_creds_pack(const Mod_Sanction_Creds *creds, uint8_t *data);
/** @brief Unpacks sanctions credentials into creds from data.
*
* @param data must have room for MOD_SANCTIONS_CREDS_SIZE bytes.
*
* Returns the length of the data processed.
*/
non_null()
uint16_t sanctions_creds_unpack(Mod_Sanction_Creds *creds, const uint8_t *data);
/** @brief Updates sanction list credentials.
*
* Increment version, replace sig_pk with your own, update hash to reflect new
* sanction list, and sign new hash signature.
*
* Returns true on success.
*/
non_null()
bool sanctions_list_make_creds(Moderation *moderation);
/** @brief Validates all sanctions list entries as well as the list itself.
*
* Returns true if all entries are valid.
* Returns false if one or more entries are invalid.
*/
non_null()
bool sanctions_list_check_integrity(const Moderation *moderation, const Mod_Sanction_Creds *creds,
const Mod_Sanction *sanctions, uint16_t num_sanctions);
/** @brief Adds an entry to the sanctions list.
*
* The entry is first validated and the resulting new sanction list is
* compared against the new credentials.
*
* Entries must be unique.
*
* Returns true on success.
*/
non_null(1, 2) nullable(3)
bool sanctions_list_add_entry(Moderation *moderation, const Mod_Sanction *sanction, const Mod_Sanction_Creds *creds);
/** @brief Creates a new sanction entry for `public_key` where type is one of Mod_Sanction_Type.
*
* New entry is signed and placed in the sanctions list.
*
* Returns true on success.
*/
non_null()
bool sanctions_list_make_entry(Moderation *moderation, const uint8_t *public_key, Mod_Sanction *sanction,
uint8_t type);
/** @return true if public key is in the observer list. */
non_null()
bool sanctions_list_is_observer(const Moderation *moderation, const uint8_t *public_key);
/** @return true if sanction already exists in the sanctions list. */
non_null()
bool sanctions_list_entry_exists(const Moderation *moderation, const Mod_Sanction *sanction);
/** @brief Removes observer entry for public key from sanction list.
*
* If creds is NULL we make new credentials (this should only be done by a moderator or founder)
*
* Returns false on failure or if entry was not found.
*/
non_null(1, 2) nullable(3)
bool sanctions_list_remove_observer(Moderation *moderation, const uint8_t *public_key,
const Mod_Sanction_Creds *creds);
/** @brief Replaces all sanctions list signatures made by public_sig_key with the caller's.
*
* This is called whenever the founder demotes a moderator.
*
* Returns the number of entries re-signed.
*/
non_null()
uint16_t sanctions_list_replace_sig(Moderation *moderation, const uint8_t *public_sig_key);
non_null()
void sanctions_list_cleanup(Moderation *moderation);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // C_TOXCORE_TOXCORE_GROUP_MODERATION_H