Coverage Report

Created: 2025-10-08 19:34

/work/toxcore/group_chats.c
Line
Count
Source (jump to first uncovered line)
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
#include "group_chats.h"
11
12
#include <sodium.h>
13
14
#include <assert.h>
15
#include <string.h>
16
17
#include "DHT.h"
18
#include "Messenger.h"
19
#include "TCP_connection.h"
20
#include "attributes.h"
21
#include "bin_pack.h"
22
#include "bin_unpack.h"
23
#include "ccompat.h"
24
#include "crypto_core.h"
25
#include "friend_connection.h"
26
#include "group_announce.h"
27
#include "group_common.h"
28
#include "group_connection.h"
29
#include "group_moderation.h"
30
#include "group_pack.h"
31
#include "logger.h"
32
#include "mem.h"
33
#include "mono_time.h"
34
#include "net_crypto.h"
35
#include "network.h"
36
#include "onion_announce.h"
37
#include "onion_client.h"
38
#include "util.h"
39
40
/* The minimum size of a plaintext group handshake packet */
41
2.88k
#define GC_MIN_HS_PACKET_PAYLOAD_SIZE (1 + ENC_PUBLIC_KEY_SIZE + SIG_PUBLIC_KEY_SIZE + 1 + 1)
42
43
/* The minimum size of an encrypted group handshake packet. */
44
1.98k
#define GC_MIN_ENCRYPTED_HS_PAYLOAD_SIZE (1 + ENC_PUBLIC_KEY_SIZE + ENC_PUBLIC_KEY_SIZE +\
45
1.98k
                                          GC_MIN_HS_PACKET_PAYLOAD_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE)
46
47
/* Size of a group's shared state in packed format */
48
3.52k
#define GC_PACKED_SHARED_STATE_SIZE (EXT_PUBLIC_KEY_SIZE + sizeof(uint16_t) + MAX_GC_GROUP_NAME_SIZE +\
49
3.52k
                                     sizeof(uint16_t) + 1 + sizeof(uint16_t) + MAX_GC_PASSWORD_SIZE +\
50
3.52k
                                     MOD_MODERATION_HASH_SIZE + sizeof(uint32_t) + sizeof(uint32_t) + 1)
51
52
/* Minimum size of a topic packet; includes topic length, public signature key, topic version and checksum */
53
4.26k
#define GC_MIN_PACKED_TOPIC_INFO_SIZE (sizeof(uint16_t) + SIG_PUBLIC_KEY_SIZE + sizeof(uint32_t) + sizeof(uint16_t))
54
55
1.23k
#define GC_SHARED_STATE_ENC_PACKET_SIZE (SIGNATURE_SIZE + GC_PACKED_SHARED_STATE_SIZE)
56
57
/* Header information attached to all broadcast messages: broadcast_type */
58
37.2k
#define GC_BROADCAST_ENC_HEADER_SIZE 1
59
60
/* Size of a group packet message ID */
61
178k
#define GC_MESSAGE_ID_BYTES sizeof(uint64_t)
62
63
/* Size of a lossless ack packet */
64
26.2k
#define GC_LOSSLESS_ACK_PACKET_SIZE (GC_MESSAGE_ID_BYTES + 1)
65
66
/* Smallest possible size of an encrypted lossless payload.
67
 *
68
 * Data includes the message_id, group packet type, and the nonce and MAC for decryption.
69
 */
70
83.2k
#define GC_MIN_LOSSLESS_PAYLOAD_SIZE (GC_MESSAGE_ID_BYTES + CRYPTO_NONCE_SIZE + 1 + CRYPTO_MAC_SIZE)
71
72
/* Smallest possible size of a lossy group packet */
73
27.0k
#define GC_MIN_LOSSY_PAYLOAD_SIZE (GC_MIN_LOSSLESS_PAYLOAD_SIZE - GC_MESSAGE_ID_BYTES)
74
75
/* Maximum number of bytes to pad packets with.
76
 *
77
 * Packets are padded with a random number of zero bytes between zero and this value in order to hide
78
 * the true length of the message, which reduces the amount of metadata leaked through packet analysis.
79
 *
80
 * Note: This behaviour was copied from the toxcore encryption implementation in net_crypto.c.
81
 */
82
56.0k
#define GC_MAX_PACKET_PADDING 8
83
84
/* Minimum size of a ping packet, which contains the peer count, peer list checksum, shared state version,
85
 * sanctions list version, sanctions list checksum, topic version, and topic checksum
86
 */
87
2.49k
#define GC_PING_PACKET_MIN_DATA_SIZE ((sizeof(uint16_t) * 4) + (sizeof(uint32_t) * 3))
88
89
/* How often in seconds we can send a group sync request packet */
90
480
#define GC_SYNC_REQUEST_LIMIT (GC_PING_TIMEOUT + 1)
91
92
/* How often in seconds we can send the peer list to any peer in the group in a sync response */
93
27
#define GC_SYNC_RESPONSE_PEER_LIST_LIMIT 3
94
95
/* How often in seconds we try to handshake with an unconfirmed peer */
96
3.44k
#define GC_SEND_HANDSHAKE_INTERVAL 3
97
98
/* How often in seconds we rotate session encryption keys with a peer */
99
2.46k
#define GC_KEY_ROTATION_TIMEOUT (5 * 60)
100
101
/* How often in seconds we try to reconnect to peers that recently timed out */
102
0
#define GC_TIMED_OUT_RECONN_TIMEOUT (GC_UNCONFIRMED_PEER_TIMEOUT * 3)
103
104
/* How long in seconds before we stop trying to reconnect with a timed out peer */
105
0
#define GC_TIMED_OUT_STALE_TIMEOUT (60 * 15)
106
107
/* The value the topic lock is set to when the topic lock is enabled. */
108
2.33k
#define GC_TOPIC_LOCK_ENABLED 0
109
110
static_assert(GCC_BUFFER_SIZE <= UINT16_MAX,
111
              "GCC_BUFFER_SIZE must be <= UINT16_MAX)");
112
113
static_assert(MAX_GC_PACKET_CHUNK_SIZE < MAX_GC_PACKET_SIZE,
114
              "MAX_GC_PACKET_CHUNK_SIZE must be < MAX_GC_PACKET_SIZE");
115
116
static_assert(MAX_GC_PACKET_INCOMING_CHUNK_SIZE < MAX_GC_PACKET_SIZE,
117
              "MAX_GC_PACKET_INCOMING_CHUNK_SIZE must be < MAX_GC_PACKET_SIZE");
118
119
static_assert(MAX_GC_PACKET_INCOMING_CHUNK_SIZE >= MAX_GC_PACKET_CHUNK_SIZE,
120
              "MAX_GC_PACKET_INCOMING_CHUNK_SIZE must be >= MAX_GC_PACKET_CHUNK_SIZE");
121
122
// size of a lossless handshake packet - lossless packets can't/shouldn't be split up
123
static_assert(MAX_GC_PACKET_CHUNK_SIZE >= 171,
124
              "MAX_GC_PACKET_CHUNK_SIZE must be >= 171");
125
126
static_assert(MAX_GC_PACKET_INCOMING_CHUNK_SIZE >= 171,
127
              "MAX_GC_PACKET_INCOMING_CHUNK_SIZE must be >= 171");
128
129
// group_moderation constants assume this is the max packet size.
130
static_assert(MAX_GC_PACKET_SIZE >= 50000,
131
              "MAX_GC_PACKET_SIZE doesn't match constants in group_moderation.h");
132
133
static_assert(MAX_GC_PACKET_SIZE <= UINT16_MAX - MAX_GC_PACKET_CHUNK_SIZE,
134
              "MAX_GC_PACKET_SIZE must be <= UINT16_MAX - MAX_GC_PACKET_CHUNK_SIZE");
135
136
static_assert(MAX_GC_PACKET_SIZE <= UINT16_MAX - MAX_GC_PACKET_INCOMING_CHUNK_SIZE,
137
              "MAX_GC_PACKET_SIZE must be <= UINT16_MAX - MAX_GC_PACKET_INCOMING_CHUNK_SIZE");
138
139
/** Types of broadcast messages. */
140
typedef enum Group_Message_Type {
141
    GC_MESSAGE_TYPE_NORMAL = 0x00,
142
    GC_MESSAGE_TYPE_ACTION = 0x01,
143
} Group_Message_Type;
144
145
/** Types of handshake request packets. */
146
typedef enum Group_Handshake_Packet_Type {
147
    GH_REQUEST  = 0x00,  // Requests a handshake
148
    GH_RESPONSE = 0x01,  // Responds to a handshake request
149
} Group_Handshake_Packet_Type;
150
151
/** Types of handshake requests (within a handshake request packet). */
152
typedef enum Group_Handshake_Request_Type {
153
    HS_INVITE_REQUEST     = 0x00,   // Requests an invite to the group
154
    HS_PEER_INFO_EXCHANGE = 0x01,   // Requests a peer info exchange
155
} Group_Handshake_Request_Type;
156
157
/** These bitmasks determine what group state info a peer is requesting in a sync request */
158
typedef enum Group_Sync_Flags {
159
    GF_PEERS      = (1 << 0), // 1
160
    GF_TOPIC      = (1 << 1), // 2
161
    GF_STATE      = (1 << 2), // 4
162
} Group_Sync_Flags;
163
164
static bool self_gc_is_founder(const GC_Chat *_Nonnull chat);
165
static bool group_number_valid(const GC_Session *_Nonnull c, int group_number);
166
static int peer_update(const GC_Chat *_Nonnull chat, const GC_Peer *_Nonnull peer, uint32_t peer_number);
167
static void group_delete(GC_Session *_Nonnull c, GC_Chat *_Nonnull chat);
168
static void group_cleanup(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat);
169
static bool group_exists(const GC_Session *_Nonnull c, const uint8_t *_Nonnull chat_id);
170
static void add_tcp_relays_to_chat(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat);
171
static void create_gc_session_keypair(const Logger *_Nonnull log, const Random *_Nonnull rng, uint8_t *_Nonnull public_key, uint8_t *_Nonnull secret_key);
172
static size_t load_gc_peers(GC_Chat *_Nonnull chat, const GC_SavedPeerInfo *_Nonnull addrs, uint16_t num_addrs);
173
static bool saved_peer_is_valid(const GC_SavedPeerInfo *_Nonnull saved_peer);
174
175
static const GC_Chat empty_gc_chat = {nullptr};
176
177
961
#define GC_INVALID_PEER_ID_VALUE ((force GC_Peer_Id_Value)-1)
178
179
static GC_Peer_Id gc_invalid_peer_id(void)
180
138
{
181
138
    const GC_Peer_Id invalid = {GC_INVALID_PEER_ID_VALUE};
182
138
    return invalid;
183
138
}
184
185
static bool gc_peer_id_is_valid(GC_Peer_Id peer_id)
186
823
{
187
823
    return peer_id.value != GC_INVALID_PEER_ID_VALUE;
188
823
}
189
190
GC_Peer_Id gc_peer_id_from_int(uint32_t value)
191
3.42k
{
192
3.42k
    const GC_Peer_Id peer_id = {(force GC_Peer_Id_Value)value};
193
3.42k
    return peer_id;
194
3.42k
}
195
196
uint32_t gc_peer_id_to_int(GC_Peer_Id peer_id)
197
10.5k
{
198
10.5k
    return (force uint32_t)peer_id.value;
199
10.5k
}
200
201
static GC_Peer_Id gc_unknown_peer_id(void)
202
0
{
203
0
    return gc_peer_id_from_int(0);
204
0
}
205
206
static void kill_group_friend_connection(const GC_Session *_Nonnull c, const GC_Chat *_Nonnull chat)
207
4.52k
{
208
4.52k
    if (chat->friend_connection_id != -1) {
209
121
        m_kill_group_connection(c->messenger, chat);
210
121
    }
211
4.52k
}
212
213
uint16_t gc_get_wrapped_packet_size(uint16_t length, Net_Packet_Type packet_type)
214
28.0k
{
215
28.0k
    assert(length <= (packet_type == NET_PACKET_GC_LOSSY ? MAX_GC_CUSTOM_LOSSY_PACKET_SIZE : MAX_GC_PACKET_CHUNK_SIZE));
216
217
28.0k
    const uint16_t min_header_size = packet_type == NET_PACKET_GC_LOSSY
218
28.0k
                                     ? GC_MIN_LOSSY_PAYLOAD_SIZE
219
28.0k
                                     : GC_MIN_LOSSLESS_PAYLOAD_SIZE;
220
28.0k
    const uint16_t header_size = ENC_PUBLIC_KEY_SIZE + GC_MAX_PACKET_PADDING + min_header_size;
221
222
28.0k
    assert(length <= UINT16_MAX - header_size);
223
224
28.0k
    return length + header_size;
225
28.0k
}
226
227
/** Return true if `peer_number` is our own. */
228
static bool peer_number_is_self(int peer_number)
229
35
{
230
35
    return peer_number == 0;
231
35
}
232
233
bool gc_peer_number_is_valid(const GC_Chat *chat, int peer_number)
234
481k
{
235
481k
    return peer_number >= 0 && peer_number < (int)chat->numpeers;
236
481k
}
237
238
static GC_Peer *get_gc_peer(const GC_Chat *_Nonnull chat, int peer_number)
239
481k
{
240
481k
    if (!gc_peer_number_is_valid(chat, peer_number)) {
241
4.37k
        return nullptr;
242
4.37k
    }
243
244
477k
    return &chat->group[peer_number];
245
481k
}
246
247
GC_Connection *get_gc_connection(const GC_Chat *chat, int peer_number)
248
407k
{
249
407k
    GC_Peer *peer = get_gc_peer(chat, peer_number);
250
251
407k
    if (peer == nullptr) {
252
4.36k
        return nullptr;
253
4.36k
    }
254
255
402k
    return &peer->gconn;
256
407k
}
257
258
/** Returns the max packet size, not wrapped */
259
static uint16_t group_packet_max_packet_size(Net_Packet_Type net_packet_type)
260
28.0k
{
261
28.0k
    if (net_packet_type == NET_PACKET_GC_LOSSY) {
262
13.6k
        return MAX_GC_CUSTOM_LOSSY_PACKET_SIZE;
263
14.3k
    } else {
264
14.3k
        return MAX_GC_PACKET_CHUNK_SIZE;
265
14.3k
    }
266
28.0k
}
267
268
/** Returns the amount of empty padding a packet of designated length should have. */
269
static uint16_t group_packet_padding_length(uint16_t length, uint16_t max_length)
270
28.0k
{
271
28.0k
    return (max_length - length) % GC_MAX_PACKET_PADDING;
272
28.0k
}
273
274
void gc_get_self_nick(const GC_Chat *chat, uint8_t *nick)
275
441
{
276
441
    if (nick != nullptr) {
277
441
        const GC_Peer *peer = get_gc_peer(chat, 0);
278
441
        assert(peer != nullptr);
279
441
        assert(peer->nick_length > 0);
280
281
441
        memcpy(nick, peer->nick, peer->nick_length);
282
441
    }
283
441
}
284
285
uint16_t gc_get_self_nick_size(const GC_Chat *chat)
286
441
{
287
441
    const GC_Peer *peer = get_gc_peer(chat, 0);
288
441
    assert(peer != nullptr);
289
290
441
    return peer->nick_length;
291
441
}
292
293
/** @brief Sets self nick to `nick`.
294
 *
295
 * Returns false if `nick` is null or `length` is greater than MAX_GC_NICK_SIZE.
296
 */
297
static bool self_gc_set_nick(const GC_Chat *_Nonnull chat, const uint8_t *_Nonnull nick, uint16_t length)
298
280
{
299
280
    if (nick == nullptr || length > MAX_GC_NICK_SIZE) {
300
0
        return false;
301
0
    }
302
303
280
    GC_Peer *peer = get_gc_peer(chat, 0);
304
280
    assert(peer != nullptr);
305
306
280
    memcpy(peer->nick, nick, length);
307
280
    peer->nick_length = length;
308
309
280
    return true;
310
280
}
311
312
Group_Role gc_get_self_role(const GC_Chat *chat)
313
11.7k
{
314
315
11.7k
    const GC_Peer *peer = get_gc_peer(chat, 0);
316
11.7k
    assert(peer != nullptr);
317
318
11.7k
    return peer->role;
319
11.7k
}
320
321
/** Sets self role. If role is invalid this function has no effect. */
322
static void self_gc_set_role(const GC_Chat *_Nonnull chat, Group_Role role)
323
225
{
324
225
    if (role <= GR_OBSERVER) {
325
225
        GC_Peer *peer = get_gc_peer(chat, 0);
326
225
        assert(peer != nullptr);
327
328
225
        peer->role = role;
329
225
    }
330
225
}
331
332
uint8_t gc_get_self_status(const GC_Chat *chat)
333
485
{
334
485
    const GC_Peer *peer = get_gc_peer(chat, 0);
335
485
    assert(peer != nullptr);
336
337
485
    return peer->status;
338
485
}
339
340
/** Sets self status. If status is invalid this function has no effect. */
341
static void self_gc_set_status(const GC_Chat *_Nonnull chat, Group_Peer_Status status)
342
275
{
343
275
    if (status == GS_NONE || status == GS_AWAY || status == GS_BUSY) {
344
275
        GC_Peer *peer = get_gc_peer(chat, 0);
345
275
        assert(peer != nullptr);
346
275
        peer->status = status;
347
275
        return;
348
275
    }
349
350
0
    LOGGER_WARNING(chat->log, "Attempting to set user status with invalid status: %u", (uint8_t)status);
351
0
}
352
353
GC_Peer_Id gc_get_self_peer_id(const GC_Chat *chat)
354
22
{
355
22
    const GC_Peer *peer = get_gc_peer(chat, 0);
356
22
    assert(peer != nullptr);
357
358
22
    return peer->peer_id;
359
22
}
360
361
/** Sets self confirmed status. */
362
static void self_gc_set_confirmed(const GC_Chat *_Nonnull chat, bool confirmed)
363
225
{
364
225
    GC_Connection *gconn = get_gc_connection(chat, 0);
365
225
    assert(gconn != nullptr);
366
367
225
    gconn->confirmed = confirmed;
368
225
}
369
370
/** Returns true if self has the founder role */
371
static bool self_gc_is_founder(const GC_Chat *_Nonnull chat)
372
833
{
373
833
    return gc_get_self_role(chat) == GR_FOUNDER;
374
833
}
375
376
void gc_get_self_public_key(const GC_Chat *chat, uint8_t *public_key)
377
111
{
378
111
    if (public_key != nullptr) {
379
111
        memcpy(public_key, chat->self_public_key.enc, ENC_PUBLIC_KEY_SIZE);
380
111
    }
381
111
}
382
383
/** @brief Sets self extended public key to `ext_public_key`.
384
 *
385
 * If `ext_public_key` is null this function has no effect.
386
 */
387
static void self_gc_set_ext_public_key(const GC_Chat *_Nonnull chat, const Extended_Public_Key *_Nonnull ext_public_key)
388
225
{
389
225
    if (ext_public_key != nullptr) {
390
225
        GC_Connection *gconn = get_gc_connection(chat, 0);
391
225
        assert(gconn != nullptr);
392
225
        gconn->addr.public_key = *ext_public_key;
393
225
    }
394
225
}
395
396
/**
397
 * Return true if `peer` has permission to speak according to the `voice_state`.
398
 */
399
static bool peer_has_voice(const GC_Peer *_Nonnull peer, Group_Voice_State voice_state)
400
18.6k
{
401
18.6k
    const Group_Role role = peer->role;
402
403
18.6k
    switch (voice_state) {
404
18.6k
        case GV_ALL:
405
18.6k
            return role <= GR_USER;
406
407
11
        case GV_MODS:
408
11
            return role <= GR_MODERATOR;
409
410
7
        case GV_FOUNDER:
411
7
            return role == GR_FOUNDER;
412
413
0
        default:
414
0
            return false;
415
18.6k
    }
416
18.6k
}
417
418
int pack_gc_saved_peers(const GC_Chat *chat, uint8_t *data, uint16_t length, uint16_t *processed)
419
441
{
420
441
    uint16_t packed_len = 0;
421
441
    uint16_t count = 0;
422
423
44.5k
    for (uint32_t i = 0; i < GC_MAX_SAVED_PEERS; ++i) {
424
44.1k
        const GC_SavedPeerInfo *saved_peer = &chat->saved_peers[i];
425
426
44.1k
        if (!saved_peer_is_valid(saved_peer)) {
427
43.1k
            continue;
428
43.1k
        }
429
430
965
        int packed_ipp_len = 0;
431
965
        int packed_tcp_len = 0;
432
433
965
        if (ipport_isset(&saved_peer->ip_port)) {
434
809
            if (packed_len > length) {
435
0
                return -1;
436
0
            }
437
438
809
            packed_ipp_len = pack_ip_port(chat->log, data + packed_len, length - packed_len, &saved_peer->ip_port);
439
440
809
            if (packed_ipp_len > 0) {
441
809
                packed_len += packed_ipp_len;
442
809
            }
443
809
        }
444
445
965
        if (ipport_isset(&saved_peer->tcp_relay.ip_port)) {
446
584
            if (packed_len > length) {
447
0
                return -1;
448
0
            }
449
450
584
            packed_tcp_len = pack_nodes(chat->log, data + packed_len, length - packed_len, &saved_peer->tcp_relay, 1);
451
452
584
            if (packed_tcp_len > 0) {
453
584
                packed_len += packed_tcp_len;
454
584
            }
455
584
        }
456
457
965
        if (packed_len + ENC_PUBLIC_KEY_SIZE > length) {
458
0
            return -1;
459
0
        }
460
461
965
        if (packed_tcp_len > 0 || packed_ipp_len > 0) {
462
965
            memcpy(data + packed_len, chat->saved_peers[i].public_key, ENC_PUBLIC_KEY_SIZE);
463
965
            packed_len += ENC_PUBLIC_KEY_SIZE;
464
965
            ++count;
465
965
        } else {
466
0
            LOGGER_WARNING(chat->log, "Failed to pack saved peer");
467
0
        }
468
965
    }
469
470
441
    if (processed != nullptr) {
471
441
        *processed = packed_len;
472
441
    }
473
474
441
    return count;
475
441
}
476
477
int unpack_gc_saved_peers(GC_Chat *chat, const uint8_t *data, uint16_t length)
478
105
{
479
105
    uint16_t count = 0;
480
105
    uint16_t unpacked_len = 0;
481
482
487
    for (size_t i = 0; unpacked_len < length; ++i) {
483
476
        GC_SavedPeerInfo *saved_peer = &chat->saved_peers[i];
484
485
476
        const int ipp_len = unpack_ip_port(&saved_peer->ip_port, data + unpacked_len, length - unpacked_len, false);
486
487
476
        if (ipp_len > 0) {
488
322
            unpacked_len += ipp_len;
489
322
        }
490
491
476
        if (unpacked_len > length) {
492
0
            return -1;
493
0
        }
494
495
476
        uint16_t tcp_len_processed = 0;
496
476
        const int tcp_len = unpack_nodes(&saved_peer->tcp_relay, 1, &tcp_len_processed, data + unpacked_len,
497
476
                                         length - unpacked_len, true);
498
499
476
        if (tcp_len == 1 && tcp_len_processed > 0) {
500
248
            unpacked_len += tcp_len_processed;
501
248
        } else if (ipp_len <= 0) {
502
92
            LOGGER_WARNING(chat->log, "Failed to unpack saved peer: Invalid connection info.");
503
92
            return -1;
504
92
        }
505
506
384
        if (unpacked_len + ENC_PUBLIC_KEY_SIZE > length) {
507
2
            return -1;
508
2
        }
509
510
382
        if (tcp_len > 0 || ipp_len > 0) {
511
382
            memcpy(saved_peer->public_key, data + unpacked_len, ENC_PUBLIC_KEY_SIZE);
512
382
            unpacked_len += ENC_PUBLIC_KEY_SIZE;
513
382
            ++count;
514
382
        } else {
515
0
            LOGGER_ERROR(chat->log, "Unpacked peer with bad connection info");
516
0
            return -1;
517
0
        }
518
382
    }
519
520
11
    return count;
521
105
}
522
523
/** Returns true if chat privacy state is set to public. */
524
static bool is_public_chat(const GC_Chat *_Nonnull chat)
525
14.4k
{
526
14.4k
    return chat->shared_state.privacy_state == GI_PUBLIC;
527
14.4k
}
528
529
/** Returns true if group is password protected */
530
static bool chat_is_password_protected(const GC_Chat *_Nonnull chat)
531
1.79k
{
532
1.79k
    return chat->shared_state.password_length > 0;
533
1.79k
}
534
535
/** Returns true if `password` matches the current group password. */
536
static bool validate_password(const GC_Chat *_Nonnull chat, const uint8_t *_Nonnull password, uint16_t length)
537
146
{
538
146
    if (length > MAX_GC_PASSWORD_SIZE) {
539
0
        return false;
540
0
    }
541
542
146
    if (length != chat->shared_state.password_length) {
543
2
        return false;
544
2
    }
545
546
144
    return memcmp(chat->shared_state.password, password, length) == 0;
547
146
}
548
549
/** @brief Returns the chat object that contains a peer with a public key equal to `id`.
550
 *
551
 * `id` must be at least ENC_PUBLIC_KEY_SIZE bytes in length.
552
 */
553
static GC_Chat *get_chat_by_id(const GC_Session *_Nonnull c, const uint8_t *_Nonnull id)
554
27.8k
{
555
27.8k
    if (c == nullptr) {
556
0
        return nullptr;
557
0
    }
558
559
27.8k
    for (uint32_t i = 0; i < c->chats_index; ++i) {
560
27.8k
        GC_Chat *chat = &c->chats[i];
561
562
27.8k
        if (chat->connection_state == CS_NONE) {
563
0
            continue;
564
0
        }
565
566
27.8k
        if (memcmp(id, chat->self_public_key.enc, ENC_PUBLIC_KEY_SIZE) == 0) {
567
661
            return chat;
568
661
        }
569
570
27.2k
        if (get_peer_number_of_enc_pk(chat, id, false) != -1) {
571
27.2k
            return chat;
572
27.2k
        }
573
27.2k
    }
574
575
14
    return nullptr;
576
27.8k
}
577
578
/** @brief Returns the jenkins hash of a 32 byte public encryption key. */
579
uint32_t gc_get_pk_jenkins_hash(const uint8_t *public_key)
580
816
{
581
816
    return jenkins_one_at_a_time_hash(public_key, ENC_PUBLIC_KEY_SIZE);
582
816
}
583
584
/** @brief Sets the sum of the public_key_hash of all confirmed peers.
585
 *
586
 * Must be called every time a peer is confirmed or deleted.
587
 */
588
static void set_gc_peerlist_checksum(GC_Chat *_Nonnull chat)
589
574
{
590
574
    uint16_t sum = 0;
591
592
2.92k
    for (uint32_t i = 0; i < chat->numpeers; ++i) {
593
2.35k
        const GC_Connection *gconn = get_gc_connection(chat, i);
594
595
2.35k
        assert(gconn != nullptr);
596
597
2.35k
        if (gconn->confirmed) {
598
1.80k
            sum += gconn->public_key_hash;
599
1.80k
        }
600
2.35k
    }
601
602
574
    chat->peers_checksum = sum;
603
574
}
604
605
/** Returns a checksum of the topic currently set in `topic_info`. */
606
static uint16_t get_gc_topic_checksum(const GC_TopicInfo *_Nonnull topic_info)
607
1.25k
{
608
1.25k
    return data_checksum(topic_info->topic, topic_info->length);
609
1.25k
}
610
611
int get_peer_number_of_enc_pk(const GC_Chat *chat, const uint8_t *public_enc_key, bool confirmed)
612
73.0k
{
613
171k
    for (uint32_t i = 0; i < chat->numpeers; ++i) {
614
170k
        const GC_Connection *gconn = get_gc_connection(chat, i);
615
616
170k
        assert(gconn != nullptr);
617
618
170k
        if (gconn->pending_delete) {
619
199
            continue;
620
199
        }
621
622
170k
        if (confirmed && !gconn->confirmed) {
623
0
            continue;
624
0
        }
625
626
170k
        if (memcmp(gconn->addr.public_key.enc, public_enc_key, ENC_PUBLIC_KEY_SIZE) == 0) {
627
72.1k
            return i;
628
72.1k
        }
629
170k
    }
630
631
927
    return -1;
632
73.0k
}
633
634
/** @brief Check if peer associated with `public_sig_key` is in peer list.
635
 *
636
 * Returns the peer number if peer is in the peer list.
637
 * Returns -1 if peer is not in the peer list.
638
 */
639
static int get_peer_number_of_sig_pk(const GC_Chat *_Nonnull chat, const uint8_t *_Nonnull public_sig_key)
640
666
{
641
2.01k
    for (uint32_t i = 0; i < chat->numpeers; ++i) {
642
2.01k
        const GC_Connection *gconn = get_gc_connection(chat, i);
643
644
2.01k
        assert(gconn != nullptr);
645
646
2.01k
        if (memcmp(get_sig_pk(&gconn->addr.public_key), public_sig_key, SIG_PUBLIC_KEY_SIZE) == 0) {
647
666
            return i;
648
666
        }
649
2.01k
    }
650
651
0
    return -1;
652
666
}
653
654
static bool gc_get_enc_pk_from_sig_pk(const GC_Chat *_Nonnull chat, uint8_t *_Nonnull public_key, const uint8_t *_Nonnull public_sig_key)
655
495
{
656
1.46k
    for (uint32_t i = 0; i < chat->numpeers; ++i) {
657
1.46k
        const GC_Connection *gconn = get_gc_connection(chat, i);
658
659
1.46k
        assert(gconn != nullptr);
660
661
1.46k
        const Extended_Public_Key *full_pk = &gconn->addr.public_key;
662
663
1.46k
        if (memcmp(public_sig_key, get_sig_pk(full_pk), SIG_PUBLIC_KEY_SIZE) == 0) {
664
495
            memcpy(public_key, get_enc_key(full_pk), ENC_PUBLIC_KEY_SIZE);
665
495
            return true;
666
495
        }
667
1.46k
    }
668
669
0
    return false;
670
495
}
671
672
static GC_Connection *random_gc_connection(const GC_Chat *_Nonnull chat)
673
0
{
674
0
    if (chat->numpeers <= 1) {
675
0
        return nullptr;
676
0
    }
677
678
0
    const uint32_t base = random_range_u32(chat->rng, chat->numpeers - 1);
679
680
0
    for (uint32_t i = 0; i < chat->numpeers - 1; ++i) {
681
0
        const uint32_t index = 1 + (base + i) % (chat->numpeers - 1);
682
0
        GC_Connection *rand_gconn = get_gc_connection(chat, index);
683
684
0
        if (rand_gconn == nullptr) {
685
0
            return nullptr;
686
0
        }
687
688
0
        if (!rand_gconn->pending_delete && rand_gconn->confirmed) {
689
0
            return rand_gconn;
690
0
        }
691
0
    }
692
693
0
    return nullptr;
694
0
}
695
696
/** @brief Returns the peer number associated with peer_id.
697
 * Returns -1 if peer_id is invalid.
698
 */
699
static int get_peer_number_of_peer_id(const GC_Chat *_Nonnull chat, GC_Peer_Id peer_id)
700
3.42k
{
701
9.71k
    for (uint32_t i = 0; i < chat->numpeers; ++i) {
702
8.87k
        if (chat->group[i].peer_id.value == peer_id.value) {
703
2.58k
            return i;
704
2.58k
        }
705
8.87k
    }
706
707
834
    return -1;
708
3.42k
}
709
710
/** @brief Returns a unique peer ID.
711
 * Returns UINT32_MAX if all possible peer ID's are taken.
712
 *
713
 * These ID's are permanently assigned to a peer when they join the group and should be
714
 * considered arbitrary values.
715
 */
716
static GC_Peer_Id get_new_peer_id(const GC_Chat *_Nonnull chat)
717
823
{
718
1.83k
    for (uint32_t i = 0; i < UINT32_MAX - 1; ++i) {
719
1.83k
        const GC_Peer_Id peer_id = gc_peer_id_from_int(i);
720
1.83k
        if (get_peer_number_of_peer_id(chat, peer_id) == -1) {
721
823
            return peer_id;
722
823
        }
723
1.83k
    }
724
725
0
    return gc_invalid_peer_id();
726
823
}
727
728
/** @brief Sets the password for the group (locally only).
729
 *
730
 * Return true on success.
731
 */
732
static bool set_gc_password_local(GC_Chat *_Nonnull chat, const uint8_t *_Nullable passwd, uint16_t length)
733
74
{
734
74
    if (length > MAX_GC_PASSWORD_SIZE) {
735
0
        return false;
736
0
    }
737
738
74
    if (passwd == nullptr || length == 0) {
739
2
        chat->shared_state.password_length = 0;
740
2
        memzero(chat->shared_state.password, MAX_GC_PASSWORD_SIZE);
741
72
    } else {
742
72
        chat->shared_state.password_length = length;
743
72
        crypto_memlock(chat->shared_state.password, sizeof(chat->shared_state.password));
744
72
        memcpy(chat->shared_state.password, passwd, length);
745
72
    }
746
747
74
    return true;
748
74
}
749
750
/** @brief Sets the local shared state to `version`.
751
 *
752
 * This should always be called instead of setting the variables manually.
753
 */
754
static void set_gc_shared_state_version(GC_Chat *_Nonnull chat, uint32_t version)
755
733
{
756
733
    chat->shared_state.version = version;
757
733
    chat->moderation.shared_state_version = version;
758
733
}
759
760
/** @brief Expands the chat_id into the extended chat public key (encryption key + signature key).
761
 *
762
 * @param dest must have room for EXT_PUBLIC_KEY_SIZE bytes.
763
 *
764
 * Return true on success.
765
 */
766
static bool expand_chat_id(Extended_Public_Key *_Nonnull dest, const uint8_t *_Nonnull chat_id)
767
114
{
768
114
    assert(dest != nullptr);
769
770
114
    const int ret = crypto_sign_ed25519_pk_to_curve25519(dest->enc, chat_id);
771
114
    memcpy(dest->sig, chat_id, SIG_PUBLIC_KEY_SIZE);
772
773
114
    return ret != -1;
774
114
}
775
776
/** Copies peer connect info from `gconn` to `addr`. */
777
static void copy_gc_saved_peer(const Random *_Nonnull rng, const GC_Connection *_Nonnull gconn, GC_SavedPeerInfo *_Nonnull addr)
778
413
{
779
413
    if (!gcc_copy_tcp_relay(rng, &addr->tcp_relay, gconn)) {
780
413
        addr->tcp_relay = (Node_format) {
781
413
            0
782
413
        };
783
413
    }
784
785
413
    addr->ip_port = gconn->addr.ip_port;
786
413
    memcpy(addr->public_key, gconn->addr.public_key.enc, ENC_PUBLIC_KEY_SIZE);
787
413
}
788
789
/** Return true if `saved_peer` has either a valid IP_Port or a valid TCP relay. */
790
static bool saved_peer_is_valid(const GC_SavedPeerInfo *_Nonnull saved_peer)
791
57.3k
{
792
57.3k
    return ipport_isset(&saved_peer->ip_port) || ipport_isset(&saved_peer->tcp_relay.ip_port);
793
57.3k
}
794
795
/** @brief Returns the index of the saved peers entry for `public_key`.
796
 * Returns -1 if key is not found.
797
 */
798
static int saved_peer_index(const GC_Chat *_Nonnull chat, const uint8_t *_Nonnull public_key)
799
433
{
800
24.2k
    for (uint16_t i = 0; i < GC_MAX_SAVED_PEERS; ++i) {
801
24.0k
        const GC_SavedPeerInfo *saved_peer = &chat->saved_peers[i];
802
803
24.0k
        if (memcmp(saved_peer->public_key, public_key, ENC_PUBLIC_KEY_SIZE) == 0) {
804
197
            return i;
805
197
        }
806
24.0k
    }
807
808
236
    return -1;
809
433
}
810
811
/** @brief Removes entry containing `public_key` from the saved peers list. */
812
static void saved_peers_remove_entry(GC_Chat *_Nonnull chat, const uint8_t *_Nonnull public_key)
813
3
{
814
3
    const int idx = saved_peer_index(chat, public_key);
815
816
3
    if (idx < 0) {
817
0
        return;
818
0
    }
819
820
3
    chat->saved_peers[idx] = (GC_SavedPeerInfo) {
821
3
        0
822
3
    };
823
3
}
824
825
/** @brief Returns the index of the first vacant entry in saved peers list.
826
 *
827
 * If `public_key` is non-null and already exists in the list, its index will be returned.
828
 *
829
 * A vacant entry is an entry that does not have either an IP_port or tcp relay set (invalid),
830
 * or an entry containing info on a peer that is not presently online (offline).
831
 *
832
 * Invalid entries are given priority over offline entries.
833
 *
834
 * Returns -1 if there are no vacant indices.
835
 */
836
static int saved_peers_get_new_index(const GC_Chat *_Nonnull chat, const uint8_t *_Nullable public_key)
837
422
{
838
422
    if (public_key != nullptr) {
839
413
        const int idx = saved_peer_index(chat, public_key);
840
413
        if (idx != -1) {
841
177
            return idx;
842
177
        }
843
413
    }
844
845
    // first check for invalid spots
846
392
    for (uint16_t i = 0; i < GC_MAX_SAVED_PEERS; ++i) {
847
392
        const GC_SavedPeerInfo *saved_peer = &chat->saved_peers[i];
848
849
392
        if (!saved_peer_is_valid(saved_peer)) {
850
245
            return i;
851
245
        }
852
392
    }
853
854
    // now look for entries with offline peers
855
0
    for (uint16_t i = 0; i < GC_MAX_SAVED_PEERS; ++i) {
856
0
        const GC_SavedPeerInfo *saved_peer = &chat->saved_peers[i];
857
858
0
        const int peernumber = get_peer_number_of_enc_pk(chat, saved_peer->public_key, true);
859
860
0
        if (peernumber < 0) {
861
0
            return i;
862
0
        }
863
0
    }
864
865
0
    return -1;
866
0
}
867
868
/** @brief Attempts to add `gconn` to the saved peer list.
869
 *
870
 * If an entry already exists it will be updated.
871
 *
872
 * Older peers will only be overwritten if the peer is no longer
873
 * present in the chat. This gives priority to more stable connections.
874
 *
875
 * This function should be called every time a new peer joins the group.
876
 */
877
static void add_gc_saved_peers(GC_Chat *_Nonnull chat, const GC_Connection *_Nonnull gconn)
878
413
{
879
413
    const int idx = saved_peers_get_new_index(chat, gconn->addr.public_key.enc);
880
881
413
    if (idx == -1) {
882
0
        return;
883
0
    }
884
885
413
    GC_SavedPeerInfo *saved_peer = &chat->saved_peers[idx];
886
413
    copy_gc_saved_peer(chat->rng, gconn, saved_peer);
887
413
}
888
889
/** @brief Finds the first vacant spot in the saved peers list and fills it with a present
890
 * peer who isn't already in the list.
891
 *
892
 * This function should be called after a confirmed peer exits the group.
893
 */
894
static void refresh_gc_saved_peers(GC_Chat *_Nonnull chat)
895
9
{
896
9
    const int idx = saved_peers_get_new_index(chat, nullptr);
897
898
9
    if (idx == -1) {
899
0
        return;
900
0
    }
901
902
29
    for (uint32_t i = 1; i < chat->numpeers; ++i) {
903
20
        const GC_Connection *gconn = get_gc_connection(chat, i);
904
905
20
        if (gconn == nullptr) {
906
0
            continue;
907
0
        }
908
909
20
        if (!gconn->confirmed) {
910
3
            continue;
911
3
        }
912
913
17
        if (saved_peer_index(chat, gconn->addr.public_key.enc) == -1) {
914
0
            GC_SavedPeerInfo *saved_peer = &chat->saved_peers[idx];
915
0
            copy_gc_saved_peer(chat->rng, gconn, saved_peer);
916
0
            return;
917
0
        }
918
17
    }
919
9
}
920
921
/** Returns the number of confirmed peers in peerlist. */
922
static uint16_t get_gc_confirmed_numpeers(const GC_Chat *_Nonnull chat)
923
1.23k
{
924
1.23k
    uint16_t count = 0;
925
926
6.70k
    for (uint32_t i = 0; i < chat->numpeers; ++i) {
927
5.47k
        const GC_Connection *gconn = get_gc_connection(chat, i);
928
929
5.47k
        assert(gconn != nullptr);
930
931
5.47k
        if (gconn->confirmed) {
932
3.86k
            ++count;
933
3.86k
        }
934
5.47k
    }
935
936
1.23k
    return count;
937
1.23k
}
938
939
static bool sign_gc_shared_state(GC_Chat *_Nonnull chat);
940
static bool broadcast_gc_mod_list(const GC_Chat *_Nonnull chat);
941
static bool broadcast_gc_shared_state(const GC_Chat *_Nonnull chat);
942
static bool update_gc_sanctions_list(GC_Chat *_Nonnull chat, const uint8_t *_Nonnull public_sig_key);
943
static bool update_gc_topic(GC_Chat *_Nonnull chat, const uint8_t *_Nonnull public_sig_key);
944
static bool send_gc_set_observer(const GC_Chat *_Nonnull chat, const Extended_Public_Key *_Nonnull target_ext_pk, const uint8_t *_Nonnull sanction_data, uint16_t length, bool add_obs);
945
946
/** Returns true if peer designated by `peer_number` is in the sanctions list as an observer. */
947
static bool peer_is_observer(const GC_Chat *_Nonnull chat, uint32_t peer_number)
948
1.71k
{
949
1.71k
    const GC_Connection *gconn = get_gc_connection(chat, peer_number);
950
951
1.71k
    if (gconn == nullptr) {
952
0
        return false;
953
0
    }
954
955
1.71k
    return sanctions_list_is_observer(&chat->moderation, get_enc_key(&gconn->addr.public_key));
956
1.71k
}
957
958
/** Returns true if peer designated by `peer_number` is the group founder. */
959
static bool peer_is_founder(const GC_Chat *_Nonnull chat, uint32_t peer_number)
960
4.19k
{
961
962
4.19k
    const GC_Connection *gconn = get_gc_connection(chat, peer_number);
963
964
4.19k
    if (gconn == nullptr) {
965
0
        return false;
966
0
    }
967
968
4.19k
    return memcmp(chat->shared_state.founder_public_key.enc, gconn->addr.public_key.enc, ENC_PUBLIC_KEY_SIZE) == 0;
969
4.19k
}
970
971
/** Returns true if peer designated by `peer_number` is in the moderator list or is the founder. */
972
static bool peer_is_moderator(const GC_Chat *_Nonnull chat, uint32_t peer_number)
973
1.71k
{
974
1.71k
    const GC_Connection *gconn = get_gc_connection(chat, peer_number);
975
976
1.71k
    if (gconn == nullptr) {
977
0
        return false;
978
0
    }
979
980
1.71k
    if (peer_is_founder(chat, peer_number)) {
981
0
        return false;
982
0
    }
983
984
1.71k
    return mod_list_verify_sig_pk(&chat->moderation, get_sig_pk(&gconn->addr.public_key));
985
1.71k
}
986
987
/** @brief Iterates through the peerlist and updates group roles according to the
988
 * current group state.
989
 *
990
 * Also updates the roles checksum. If any role conflicts exist the shared state
991
 * version is set to zero in order to force a sync update.
992
 *
993
 * This should be called every time the moderator list or sanctions list changes,
994
 * and after a new peer is marked as confirmed.
995
 */
996
static void update_gc_peer_roles(GC_Chat *_Nonnull chat)
997
1.04k
{
998
1.04k
    chat->roles_checksum = 0;
999
1.04k
    bool conflicts = false;
1000
1001
4.27k
    for (uint32_t i = 0; i < chat->numpeers; ++i) {
1002
3.23k
        const GC_Connection *gconn = get_gc_connection(chat, i);
1003
1004
3.23k
        if (gconn == nullptr) {
1005
0
            continue;
1006
0
        }
1007
1008
3.23k
        if (!gconn->confirmed) {
1009
753
            continue;
1010
753
        }
1011
1012
2.48k
        const uint8_t first_byte = gconn->addr.public_key.enc[0];
1013
2.48k
        const bool is_founder = peer_is_founder(chat, i);
1014
1015
2.48k
        if (is_founder) {
1016
772
            chat->group[i].role = GR_FOUNDER;
1017
772
            chat->roles_checksum += GR_FOUNDER + first_byte;
1018
772
            continue;
1019
772
        }
1020
1021
1.71k
        const bool is_observer  = peer_is_observer(chat, i);
1022
1.71k
        const bool is_moderator = peer_is_moderator(chat, i);
1023
1.71k
        const bool is_user = !(is_founder || is_moderator || is_observer);
1024
1025
1.71k
        if (is_observer && is_moderator) {
1026
0
            conflicts = true;
1027
0
        }
1028
1029
1.71k
        if (is_user) {
1030
1.45k
            chat->group[i].role = GR_USER;
1031
1.45k
            chat->roles_checksum += GR_USER + first_byte;
1032
1.45k
            continue;
1033
1.45k
        }
1034
1035
258
        if (is_moderator) {
1036
209
            chat->group[i].role = GR_MODERATOR;
1037
209
            chat->roles_checksum += GR_MODERATOR + first_byte;
1038
209
            continue;
1039
209
        }
1040
1041
49
        if (is_observer) {
1042
49
            chat->group[i].role = GR_OBSERVER;
1043
49
            chat->roles_checksum += GR_OBSERVER + first_byte;
1044
49
            continue;
1045
49
        }
1046
49
    }
1047
1048
1.04k
    if (conflicts && !self_gc_is_founder(chat)) {
1049
0
        set_gc_shared_state_version(chat, 0);  // need a new shared state
1050
0
    }
1051
1.04k
}
1052
1053
/** @brief Removes the first found offline mod from the mod list.
1054
 *
1055
 * Broadcasts the shared state and moderator list on success, as well as the updated
1056
 * sanctions list if necessary.
1057
 *
1058
 * TODO(Jfreegman): Make this smarter in who to remove (e.g. the mod who hasn't been seen online in the longest time)
1059
 *
1060
 * Returns false on failure.
1061
 */
1062
static bool prune_gc_mod_list(GC_Chat *_Nonnull chat)
1063
0
{
1064
0
    if (chat->moderation.num_mods == 0) {
1065
0
        return true;
1066
0
    }
1067
1068
0
    uint8_t public_sig_key[SIG_PUBLIC_KEY_SIZE];
1069
0
    bool pruned_mod = false;
1070
1071
0
    for (uint16_t i = 0; i < chat->moderation.num_mods; ++i) {
1072
0
        if (get_peer_number_of_sig_pk(chat, chat->moderation.mod_list[i]) == -1) {
1073
0
            memcpy(public_sig_key, chat->moderation.mod_list[i], SIG_PUBLIC_KEY_SIZE);
1074
1075
0
            if (!mod_list_remove_index(&chat->moderation, i)) {
1076
0
                continue;
1077
0
            }
1078
1079
0
            pruned_mod = true;
1080
0
            break;
1081
0
        }
1082
0
    }
1083
1084
0
    return pruned_mod
1085
0
           && mod_list_make_hash(&chat->moderation, chat->shared_state.mod_list_hash)
1086
0
           && sign_gc_shared_state(chat)
1087
0
           && broadcast_gc_shared_state(chat)
1088
0
           && broadcast_gc_mod_list(chat)
1089
0
           && update_gc_sanctions_list(chat, public_sig_key)
1090
0
           && update_gc_topic(chat, public_sig_key);
1091
0
}
1092
1093
static bool prune_gc_sanctions_list_inner(GC_Chat *_Nonnull chat, const Mod_Sanction *_Nonnull sanction, const Extended_Public_Key *_Nonnull target_ext_pk)
1094
0
{
1095
0
    if (!sanctions_list_remove_observer(&chat->moderation, sanction->target_public_enc_key, nullptr)) {
1096
0
        LOGGER_WARNING(chat->log, "Failed to remove entry from observer list");
1097
0
        return false;
1098
0
    }
1099
1100
0
    uint8_t data[MOD_SANCTIONS_CREDS_SIZE];
1101
0
    const uint16_t length = sanctions_creds_pack(&chat->moderation.sanctions_creds, data);
1102
1103
0
    if (length != MOD_SANCTIONS_CREDS_SIZE) {
1104
0
        LOGGER_ERROR(chat->log, "Failed to pack credentials (invalid length: %u)", length);
1105
0
        return false;
1106
0
    }
1107
1108
0
    if (!send_gc_set_observer(chat, target_ext_pk, data, length, false)) {
1109
0
        LOGGER_WARNING(chat->log, "Failed to broadcast set observer");
1110
0
        return false;
1111
0
    }
1112
1113
0
    return true;
1114
0
}
1115
1116
/** @brief Removes the first found offline sanctioned peer from the sanctions list and sends the
1117
 * event to the rest of the group.
1118
 *
1119
 * @retval false on failure or if no presently sanctioned peer is offline.
1120
 */
1121
static bool prune_gc_sanctions_list(GC_Chat *_Nonnull chat)
1122
0
{
1123
0
    if (chat->moderation.num_sanctions == 0) {
1124
0
        return true;
1125
0
    }
1126
1127
0
    for (uint16_t i = 0; i < chat->moderation.num_sanctions; ++i) {
1128
0
        const int peer_number = get_peer_number_of_enc_pk(chat, chat->moderation.sanctions[i].target_public_enc_key, true);
1129
1130
0
        if (peer_number == -1) {
1131
0
            const Mod_Sanction *sanction = &chat->moderation.sanctions[i];
1132
0
            Extended_Public_Key target_ext_pk;
1133
0
            memcpy(target_ext_pk.enc, sanction->target_public_enc_key, ENC_PUBLIC_KEY_SIZE);
1134
0
            memcpy(target_ext_pk.sig, sanction->setter_public_sig_key, SIG_PUBLIC_KEY_SIZE);
1135
0
            return prune_gc_sanctions_list_inner(chat, sanction, &target_ext_pk);
1136
0
        }
1137
0
    }
1138
1139
0
    return false;
1140
0
}
1141
1142
/** @brief Size of peer data that we pack for transfer (nick length must be accounted for separately).
1143
 * packed data consists of: nick length, nick, and status.
1144
 */
1145
1.67k
#define PACKED_GC_PEER_SIZE (sizeof(uint16_t) + MAX_GC_NICK_SIZE + sizeof(uint8_t))
1146
1147
/** @brief Packs peer info into data of maxlength length.
1148
 *
1149
 * Return length of packed peer on success.
1150
 * Return -1 on failure.
1151
 */
1152
static int pack_gc_peer(uint8_t *_Nonnull data, uint16_t length, const GC_Peer *_Nonnull peer)
1153
423
{
1154
423
    if (PACKED_GC_PEER_SIZE > length) {
1155
0
        return -1;
1156
0
    }
1157
1158
423
    uint32_t packed_len = 0;
1159
1160
423
    net_pack_u16(data + packed_len, peer->nick_length);
1161
423
    packed_len += sizeof(uint16_t);
1162
423
    memcpy(data + packed_len, peer->nick, MAX_GC_NICK_SIZE);
1163
423
    packed_len += MAX_GC_NICK_SIZE;
1164
423
    memcpy(data + packed_len, &peer->status, sizeof(uint8_t));
1165
423
    packed_len += sizeof(uint8_t);
1166
1167
423
    return packed_len;
1168
423
}
1169
1170
/** @brief Unpacks peer info of size length into peer.
1171
 *
1172
 * Returns the length of processed data on success.
1173
 * Returns -1 on failure.
1174
 */
1175
static int unpack_gc_peer(GC_Peer *_Nonnull peer, const uint8_t *_Nonnull data, uint16_t length)
1176
413
{
1177
413
    if (PACKED_GC_PEER_SIZE > length) {
1178
0
        return -1;
1179
0
    }
1180
1181
413
    uint16_t len_processed = 0;
1182
1183
413
    net_unpack_u16(data + len_processed, &peer->nick_length);
1184
413
    len_processed += sizeof(uint16_t);
1185
413
    peer->nick_length = min_u16(MAX_GC_NICK_SIZE, peer->nick_length);
1186
413
    memcpy(peer->nick, data + len_processed, MAX_GC_NICK_SIZE);
1187
413
    len_processed += MAX_GC_NICK_SIZE;
1188
413
    memcpy(&peer->status, data + len_processed, sizeof(uint8_t));
1189
413
    len_processed += sizeof(uint8_t);
1190
1191
413
    return len_processed;
1192
413
}
1193
1194
/** @brief Packs shared_state into data.
1195
 *
1196
 * @param data must have room for at least GC_PACKED_SHARED_STATE_SIZE bytes.
1197
 *
1198
 * Returns packed data length.
1199
 */
1200
static uint16_t pack_gc_shared_state(uint8_t *_Nonnull data, uint16_t length, const GC_SharedState *_Nonnull shared_state)
1201
749
{
1202
749
    if (length < GC_PACKED_SHARED_STATE_SIZE) {
1203
0
        return 0;
1204
0
    }
1205
1206
749
    const uint8_t privacy_state = shared_state->privacy_state;
1207
749
    const uint8_t voice_state = shared_state->voice_state;
1208
1209
749
    uint16_t packed_len = 0;
1210
1211
    // version is always first
1212
749
    net_pack_u32(data + packed_len, shared_state->version);
1213
749
    packed_len += sizeof(uint32_t);
1214
1215
749
    memcpy(data + packed_len, shared_state->founder_public_key.enc, ENC_PUBLIC_KEY_SIZE);
1216
749
    packed_len += ENC_PUBLIC_KEY_SIZE;
1217
749
    memcpy(data + packed_len, shared_state->founder_public_key.sig, SIG_PUBLIC_KEY_SIZE);
1218
749
    packed_len += SIG_PUBLIC_KEY_SIZE;
1219
749
    net_pack_u16(data + packed_len, shared_state->maxpeers);
1220
749
    packed_len += sizeof(uint16_t);
1221
749
    net_pack_u16(data + packed_len, shared_state->group_name_len);
1222
749
    packed_len += sizeof(uint16_t);
1223
749
    memcpy(data + packed_len, shared_state->group_name, MAX_GC_GROUP_NAME_SIZE);
1224
749
    packed_len += MAX_GC_GROUP_NAME_SIZE;
1225
749
    memcpy(data + packed_len, &privacy_state, sizeof(uint8_t));
1226
749
    packed_len += sizeof(uint8_t);
1227
749
    net_pack_u16(data + packed_len, shared_state->password_length);
1228
749
    packed_len += sizeof(uint16_t);
1229
749
    memcpy(data + packed_len, shared_state->password, MAX_GC_PASSWORD_SIZE);
1230
749
    packed_len += MAX_GC_PASSWORD_SIZE;
1231
749
    memcpy(data + packed_len, shared_state->mod_list_hash, MOD_MODERATION_HASH_SIZE);
1232
749
    packed_len += MOD_MODERATION_HASH_SIZE;
1233
749
    net_pack_u32(data + packed_len, shared_state->topic_lock);
1234
749
    packed_len += sizeof(uint32_t);
1235
749
    memcpy(data + packed_len, &voice_state, sizeof(uint8_t));
1236
749
    packed_len += sizeof(uint8_t);
1237
1238
749
    return packed_len;
1239
749
}
1240
1241
/** @brief Unpacks shared state data into shared_state.
1242
 *
1243
 * @param data must contain at least GC_PACKED_SHARED_STATE_SIZE bytes.
1244
 *
1245
 * Returns the length of processed data.
1246
 */
1247
static uint16_t unpack_gc_shared_state(GC_SharedState *_Nonnull shared_state, const uint8_t *_Nonnull data, uint16_t length)
1248
399
{
1249
399
    if (length < GC_PACKED_SHARED_STATE_SIZE) {
1250
0
        return 0;
1251
0
    }
1252
1253
399
    uint16_t len_processed = 0;
1254
1255
    // version is always first
1256
399
    net_unpack_u32(data + len_processed, &shared_state->version);
1257
399
    len_processed += sizeof(uint32_t);
1258
1259
399
    memcpy(shared_state->founder_public_key.enc, data + len_processed, ENC_PUBLIC_KEY_SIZE);
1260
399
    len_processed += ENC_PUBLIC_KEY_SIZE;
1261
399
    memcpy(shared_state->founder_public_key.sig, data + len_processed, SIG_PUBLIC_KEY_SIZE);
1262
399
    len_processed += SIG_PUBLIC_KEY_SIZE;
1263
399
    net_unpack_u16(data + len_processed, &shared_state->maxpeers);
1264
399
    len_processed += sizeof(uint16_t);
1265
399
    net_unpack_u16(data + len_processed, &shared_state->group_name_len);
1266
399
    shared_state->group_name_len = min_u16(shared_state->group_name_len, MAX_GC_GROUP_NAME_SIZE);
1267
399
    len_processed += sizeof(uint16_t);
1268
399
    memcpy(shared_state->group_name, data + len_processed, MAX_GC_GROUP_NAME_SIZE);
1269
399
    len_processed += MAX_GC_GROUP_NAME_SIZE;
1270
1271
399
    uint8_t privacy_state;
1272
399
    memcpy(&privacy_state, data + len_processed, sizeof(uint8_t));
1273
399
    len_processed += sizeof(uint8_t);
1274
1275
399
    net_unpack_u16(data + len_processed, &shared_state->password_length);
1276
399
    len_processed += sizeof(uint16_t);
1277
399
    memcpy(shared_state->password, data + len_processed, MAX_GC_PASSWORD_SIZE);
1278
399
    len_processed += MAX_GC_PASSWORD_SIZE;
1279
399
    memcpy(shared_state->mod_list_hash, data + len_processed, MOD_MODERATION_HASH_SIZE);
1280
399
    len_processed += MOD_MODERATION_HASH_SIZE;
1281
399
    net_unpack_u32(data + len_processed, &shared_state->topic_lock);
1282
399
    len_processed += sizeof(uint32_t);
1283
1284
399
    uint8_t voice_state;
1285
399
    memcpy(&voice_state, data + len_processed, sizeof(uint8_t));
1286
399
    len_processed += sizeof(uint8_t);
1287
1288
399
    group_voice_state_from_int(voice_state, &shared_state->voice_state);
1289
399
    group_privacy_state_from_int(privacy_state, &shared_state->privacy_state);
1290
1291
399
    return len_processed;
1292
399
}
1293
1294
/** @brief Packs topic info into data.
1295
 *
1296
 * @param data must have room for at least topic length + GC_MIN_PACKED_TOPIC_INFO_SIZE bytes.
1297
 *
1298
 * Returns packed data length.
1299
 */
1300
static uint16_t pack_gc_topic_info(uint8_t *_Nonnull data, uint16_t length, const GC_TopicInfo *_Nonnull topic_info)
1301
1.12k
{
1302
1.12k
    if (length < topic_info->length + GC_MIN_PACKED_TOPIC_INFO_SIZE) {
1303
0
        return 0;
1304
0
    }
1305
1306
1.12k
    uint16_t packed_len = 0;
1307
1308
1.12k
    net_pack_u32(data + packed_len, topic_info->version);
1309
1.12k
    packed_len += sizeof(uint32_t);
1310
1.12k
    net_pack_u16(data + packed_len, topic_info->checksum);
1311
1.12k
    packed_len += sizeof(uint16_t);
1312
1.12k
    net_pack_u16(data + packed_len, topic_info->length);
1313
1.12k
    packed_len += sizeof(uint16_t);
1314
1.12k
    memcpy(data + packed_len, topic_info->topic, topic_info->length);
1315
1.12k
    packed_len += topic_info->length;
1316
1.12k
    memcpy(data + packed_len, topic_info->public_sig_key, SIG_PUBLIC_KEY_SIZE);
1317
1.12k
    packed_len += SIG_PUBLIC_KEY_SIZE;
1318
1319
1.12k
    return packed_len;
1320
1.12k
}
1321
1322
/** @brief Unpacks topic info into `topic_info`.
1323
 *
1324
 * Returns -1 on failure.
1325
 * Returns the length of the processed data on success.
1326
 */
1327
static int unpack_gc_topic_info(GC_TopicInfo *_Nonnull topic_info, const uint8_t *_Nonnull data, uint16_t length)
1328
755
{
1329
755
    if (length < sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t)) {
1330
0
        return -1;
1331
0
    }
1332
1333
755
    uint16_t len_processed = 0;
1334
1335
755
    net_unpack_u32(data + len_processed, &topic_info->version);
1336
755
    len_processed += sizeof(uint32_t);
1337
755
    net_unpack_u16(data + len_processed, &topic_info->checksum);
1338
755
    len_processed += sizeof(uint16_t);
1339
755
    net_unpack_u16(data + len_processed, &topic_info->length);
1340
755
    len_processed += sizeof(uint16_t);
1341
1342
755
    if (topic_info->length > MAX_GC_TOPIC_SIZE) {
1343
0
        topic_info->length = MAX_GC_TOPIC_SIZE;
1344
0
    }
1345
1346
755
    if (length - len_processed < topic_info->length + SIG_PUBLIC_KEY_SIZE) {
1347
0
        return -1;
1348
0
    }
1349
1350
755
    if (topic_info->length > 0) {
1351
639
        memcpy(topic_info->topic, data + len_processed, topic_info->length);
1352
639
        len_processed += topic_info->length;
1353
639
    }
1354
1355
755
    memcpy(topic_info->public_sig_key, data + len_processed, SIG_PUBLIC_KEY_SIZE);
1356
755
    len_processed += SIG_PUBLIC_KEY_SIZE;
1357
1358
755
    return len_processed;
1359
755
}
1360
1361
/** @brief Creates a shared state packet and puts it in data.
1362
 * Packet includes self pk hash, shared state signature, and packed shared state info.
1363
 * data must have room for at least GC_SHARED_STATE_ENC_PACKET_SIZE bytes.
1364
 *
1365
 * Returns packet length on success.
1366
 * Returns -1 on failure.
1367
 */
1368
static int make_gc_shared_state_packet(const GC_Chat *_Nonnull chat, uint8_t *_Nonnull data, uint16_t length)
1369
415
{
1370
415
    if (length < GC_SHARED_STATE_ENC_PACKET_SIZE) {
1371
0
        return -1;
1372
0
    }
1373
1374
415
    memcpy(data, chat->shared_state_sig, SIGNATURE_SIZE);
1375
415
    const uint16_t header_len = SIGNATURE_SIZE;
1376
1377
415
    const uint16_t packed_len = pack_gc_shared_state(data + header_len, length - header_len, &chat->shared_state);
1378
1379
415
    if (packed_len != GC_PACKED_SHARED_STATE_SIZE) {
1380
0
        return -1;
1381
0
    }
1382
1383
415
    return header_len + packed_len;
1384
415
}
1385
1386
/** @brief Creates a signature for the group's shared state in packed form.
1387
 *
1388
 * This function only works for the Founder.
1389
 *
1390
 * Returns true on success and increments the shared state version.
1391
 */
1392
static bool sign_gc_shared_state(GC_Chat *_Nonnull chat)
1393
334
{
1394
334
    if (!self_gc_is_founder(chat)) {
1395
0
        LOGGER_ERROR(chat->log, "Failed to sign shared state (invalid permission)");
1396
0
        return false;
1397
0
    }
1398
1399
334
    if (chat->shared_state.version != UINT32_MAX) {
1400
        /* improbable, but an overflow would break everything */
1401
334
        set_gc_shared_state_version(chat, chat->shared_state.version + 1);
1402
334
    } else {
1403
0
        LOGGER_WARNING(chat->log, "Shared state version wraparound");
1404
0
    }
1405
1406
334
    uint8_t shared_state[GC_PACKED_SHARED_STATE_SIZE];
1407
334
    const uint16_t packed_len = pack_gc_shared_state(shared_state, sizeof(shared_state), &chat->shared_state);
1408
1409
334
    if (packed_len != GC_PACKED_SHARED_STATE_SIZE) {
1410
0
        set_gc_shared_state_version(chat, chat->shared_state.version - 1);
1411
0
        LOGGER_ERROR(chat->log, "Failed to pack shared state");
1412
0
        return false;
1413
0
    }
1414
1415
334
    const int ret = crypto_sign_detached(chat->shared_state_sig, nullptr, shared_state, packed_len,
1416
334
                                         get_sig_sk(&chat->chat_secret_key));
1417
1418
334
    if (ret != 0) {
1419
0
        set_gc_shared_state_version(chat, chat->shared_state.version - 1);
1420
0
        LOGGER_ERROR(chat->log, "Failed to sign shared state (%d)", ret);
1421
0
        return false;
1422
0
    }
1423
1424
334
    return true;
1425
334
}
1426
1427
/** @brief Decrypts data using the shared key associated with `gconn`.
1428
 *
1429
 * The packet payload should begin with a nonce.
1430
 *
1431
 * @param message_id should be set to NULL for lossy packets.
1432
 *
1433
 * Returns length of the plaintext data on success.
1434
 * Return -1 if encrypted payload length is invalid.
1435
 * Return -2 on decryption failure.
1436
 * Return -3 if plaintext payload length is invalid.
1437
 */
1438
static int group_packet_unwrap(const Logger *_Nonnull log, const Memory *_Nonnull mem, const GC_Connection *_Nonnull gconn, uint8_t *_Nonnull data, uint64_t *_Nullable message_id,
1439
                               uint8_t *_Nonnull packet_type, const uint8_t *_Nonnull packet, uint16_t length)
1440
27.2k
{
1441
27.2k
    assert(data != nullptr);
1442
27.2k
    assert(packet != nullptr);
1443
1444
27.2k
    if (length <= CRYPTO_NONCE_SIZE) {
1445
0
        LOGGER_FATAL(log, "Invalid packet length: %u", length);
1446
0
        return -1;
1447
0
    }
1448
1449
27.2k
    uint8_t *plain = (uint8_t *)mem_balloc(mem, length);
1450
1451
27.2k
    if (plain == nullptr) {
1452
2
        LOGGER_ERROR(log, "Failed to allocate memory for plain data buffer");
1453
2
        return -1;
1454
2
    }
1455
1456
27.1k
    int plain_len = decrypt_data_symmetric(mem, gconn->session_shared_key, packet, packet + CRYPTO_NONCE_SIZE,
1457
27.1k
                                           length - CRYPTO_NONCE_SIZE, plain);
1458
1459
27.1k
    if (plain_len <= 0) {
1460
2
        mem_delete(mem, plain);
1461
2
        return plain_len == 0 ? -3 : -2;
1462
2
    }
1463
1464
27.1k
    const int min_plain_len = message_id != nullptr ? 1 + GC_MESSAGE_ID_BYTES : 1;
1465
1466
    /* remove padding */
1467
27.1k
    const uint8_t *real_plain = plain;
1468
1469
138k
    while (real_plain[0] == 0) {
1470
111k
        ++real_plain;
1471
111k
        --plain_len;
1472
1473
111k
        if (plain_len < min_plain_len) {
1474
0
            mem_delete(mem, plain);
1475
0
            return -3;
1476
0
        }
1477
111k
    }
1478
1479
27.1k
    uint32_t header_len = sizeof(uint8_t);
1480
27.1k
    *packet_type = real_plain[0];
1481
27.1k
    plain_len -= sizeof(uint8_t);
1482
1483
27.1k
    if (message_id != nullptr) {
1484
13.8k
        net_unpack_u64(real_plain + sizeof(uint8_t), message_id);
1485
13.8k
        plain_len -= GC_MESSAGE_ID_BYTES;
1486
13.8k
        header_len += GC_MESSAGE_ID_BYTES;
1487
13.8k
    }
1488
1489
27.1k
    memcpy(data, real_plain + header_len, plain_len);
1490
1491
27.1k
    mem_delete(mem, plain);
1492
1493
27.1k
    return plain_len;
1494
27.1k
}
1495
1496
int group_packet_wrap(
1497
    const Logger *log, const Memory *mem, const Random *rng, const uint8_t *self_pk, const uint8_t *shared_key, uint8_t *packet,
1498
    uint16_t packet_size, const uint8_t *data, uint16_t length, uint64_t message_id,
1499
    uint8_t gp_packet_type, Net_Packet_Type net_packet_type)
1500
28.0k
{
1501
28.0k
    const uint16_t max_packet_size = group_packet_max_packet_size(net_packet_type);
1502
28.0k
    const uint16_t padding_len = group_packet_padding_length(length, max_packet_size);
1503
28.0k
    const uint16_t min_packet_size = net_packet_type == NET_PACKET_GC_LOSSLESS
1504
28.0k
                                     ? length + padding_len + CRYPTO_MAC_SIZE + 1 + ENC_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + GC_MESSAGE_ID_BYTES + 1
1505
28.0k
                                     : length + padding_len + CRYPTO_MAC_SIZE + 1 + ENC_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + 1;
1506
1507
28.0k
    if (min_packet_size > packet_size) {
1508
0
        LOGGER_ERROR(log, "Invalid packet buffer size: %u", packet_size);
1509
0
        return -1;
1510
0
    }
1511
1512
28.0k
    if (length > max_packet_size) {
1513
0
        LOGGER_ERROR(log, "Packet payload size (%u) exceeds maximum (%u)", length, max_packet_size);
1514
0
        return -1;
1515
0
    }
1516
1517
28.0k
    uint8_t *plain = (uint8_t *)mem_balloc(mem, packet_size);
1518
1519
28.0k
    if (plain == nullptr) {
1520
11
        return -1;
1521
11
    }
1522
1523
28.0k
    assert(padding_len < packet_size);
1524
1525
28.0k
    memzero(plain, padding_len);
1526
1527
28.0k
    uint16_t enc_header_len = sizeof(uint8_t);
1528
28.0k
    plain[padding_len] = gp_packet_type;
1529
1530
28.0k
    if (net_packet_type == NET_PACKET_GC_LOSSLESS) {
1531
14.3k
        net_pack_u64(plain + padding_len + sizeof(uint8_t), message_id);
1532
14.3k
        enc_header_len += GC_MESSAGE_ID_BYTES;
1533
14.3k
    }
1534
1535
28.0k
    if (length > 0 && data != nullptr) {
1536
26.5k
        memcpy(plain + padding_len + enc_header_len, data, length);
1537
26.5k
    }
1538
1539
28.0k
    uint8_t nonce[CRYPTO_NONCE_SIZE];
1540
28.0k
    random_nonce(rng, nonce);
1541
1542
28.0k
    const uint16_t plain_len = padding_len + enc_header_len + length;
1543
28.0k
    const uint16_t encrypt_buf_size = plain_len + CRYPTO_MAC_SIZE;
1544
1545
28.0k
    uint8_t *encrypt = (uint8_t *)mem_balloc(mem, encrypt_buf_size);
1546
1547
28.0k
    if (encrypt == nullptr) {
1548
11
        mem_delete(mem, plain);
1549
11
        return -2;
1550
11
    }
1551
1552
28.0k
    const int enc_len = encrypt_data_symmetric(mem, shared_key, nonce, plain, plain_len, encrypt);
1553
1554
28.0k
    mem_delete(mem, plain);
1555
1556
28.0k
    if (enc_len != encrypt_buf_size) {
1557
11
        LOGGER_ERROR(log, "encryption failed. packet type: 0x%02x, enc_len: %d", gp_packet_type, enc_len);
1558
11
        mem_delete(mem, encrypt);
1559
11
        return -3;
1560
11
    }
1561
1562
27.9k
    packet[0] = net_packet_type;
1563
27.9k
    memcpy(packet + 1, self_pk, ENC_PUBLIC_KEY_SIZE);
1564
27.9k
    memcpy(packet + 1 + ENC_PUBLIC_KEY_SIZE, nonce, CRYPTO_NONCE_SIZE);
1565
27.9k
    memcpy(packet + 1 + ENC_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, encrypt, enc_len);
1566
1567
27.9k
    mem_delete(mem, encrypt);
1568
1569
27.9k
    return 1 + ENC_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + enc_len;
1570
28.0k
}
1571
1572
/** @brief Sends a lossy packet to peer_number in chat instance.
1573
 *
1574
 * Returns true on success.
1575
 */
1576
static bool send_lossy_group_packet(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn, const uint8_t *_Nonnull data, uint16_t length, uint8_t packet_type)
1577
13.6k
{
1578
13.6k
    assert(length <= MAX_GC_CUSTOM_LOSSY_PACKET_SIZE);
1579
1580
13.6k
    if (!gconn->handshaked || gconn->pending_delete) {
1581
0
        return false;
1582
0
    }
1583
1584
13.6k
    if (data == nullptr || length == 0) {
1585
0
        return false;
1586
0
    }
1587
1588
13.6k
    const uint16_t packet_size = gc_get_wrapped_packet_size(length, NET_PACKET_GC_LOSSY);
1589
13.6k
    uint8_t *packet = (uint8_t *)mem_balloc(chat->mem, packet_size);
1590
1591
13.6k
    if (packet == nullptr) {
1592
1
        return false;
1593
1
    }
1594
1595
13.6k
    const int len = group_packet_wrap(
1596
13.6k
                        chat->log, chat->mem, chat->rng, chat->self_public_key.enc, gconn->session_shared_key, packet,
1597
13.6k
                        packet_size, data, length, 0, packet_type, NET_PACKET_GC_LOSSY);
1598
1599
13.6k
    if (len < 0) {
1600
3
        LOGGER_ERROR(chat->log, "Failed to encrypt packet (type: 0x%02x, error: %d)", packet_type, len);
1601
3
        mem_delete(chat->mem, packet);
1602
3
        return false;
1603
3
    }
1604
1605
13.6k
    const bool ret = gcc_send_packet(chat, gconn, packet, (uint16_t)len);
1606
1607
13.6k
    mem_delete(chat->mem, packet);
1608
1609
13.6k
    return ret;
1610
13.6k
}
1611
1612
/** @brief Sends a lossless packet to peer_number in chat instance.
1613
 *
1614
 * Returns true on success.
1615
 */
1616
static bool send_lossless_group_packet(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn, const uint8_t *_Nullable data, uint16_t length,
1617
                                       uint8_t packet_type)
1618
13.1k
{
1619
13.1k
    assert(length <= MAX_GC_PACKET_SIZE);
1620
13.1k
    if (!gconn->handshaked || gconn->pending_delete) {
1621
2
        return false;
1622
2
    }
1623
1624
13.1k
    if (length > MAX_GC_PACKET_CHUNK_SIZE) {
1625
191
        return gcc_send_lossless_packet_fragments(chat, gconn, data, length, packet_type);
1626
191
    }
1627
1628
12.9k
    return gcc_send_lossless_packet(chat, gconn, data, length, packet_type) == 0;
1629
13.1k
}
1630
1631
/** @brief Sends a group sync request to peer.
1632
 *
1633
 * Returns true on success or if sync request timeout has not expired.
1634
 */
1635
static bool send_gc_sync_request(GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn, uint16_t sync_flags)
1636
480
{
1637
480
    if (!mono_time_is_timeout(chat->mono_time, chat->last_sync_request, GC_SYNC_REQUEST_LIMIT)) {
1638
284
        return true;
1639
284
    }
1640
1641
196
    chat->last_sync_request = mono_time_get(chat->mono_time);
1642
1643
196
    uint8_t data[(sizeof(uint16_t) * 2) + MAX_GC_PASSWORD_SIZE];
1644
196
    uint16_t length = sizeof(uint16_t);
1645
1646
196
    net_pack_u16(data, sync_flags);
1647
1648
196
    if (chat_is_password_protected(chat)) {
1649
32
        net_pack_u16(data + length, chat->shared_state.password_length);
1650
32
        length += sizeof(uint16_t);
1651
1652
32
        memcpy(data + length, chat->shared_state.password, MAX_GC_PASSWORD_SIZE);
1653
32
        length += MAX_GC_PASSWORD_SIZE;
1654
32
    }
1655
1656
196
    return send_lossless_group_packet(chat, gconn, data, length, GP_SYNC_REQUEST);
1657
480
}
1658
1659
/** @brief Sends a sync response packet to peer designated by `gconn`.
1660
 *
1661
 * Return true on success.
1662
 */
1663
static bool send_gc_sync_response(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn, const uint8_t *_Nullable data, uint16_t length)
1664
206
{
1665
206
    return send_lossless_group_packet(chat, gconn, data, length, GP_SYNC_RESPONSE);
1666
206
}
1667
1668
static bool send_gc_peer_exchange(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn);
1669
static bool send_gc_handshake_packet(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn, uint8_t handshake_type, uint8_t request_type, uint8_t join_type);
1670
static bool send_gc_oob_handshake_request(const GC_Chat *_Nonnull chat, const GC_Connection *_Nonnull gconn);
1671
1672
/** @brief Unpacks a sync announce.
1673
 *
1674
 * If the announced peer is not already in our peer list, we attempt to
1675
 * initiate a peer info exchange with them.
1676
 *
1677
 * Return true on success (whether or not the peer was added).
1678
 */
1679
static bool unpack_gc_sync_announce(GC_Chat *_Nonnull chat, const uint8_t *_Nonnull data, const uint16_t length)
1680
112
{
1681
112
    GC_Announce announce = {0};
1682
1683
112
    const int unpacked_announces = gca_unpack_announces_list(chat->log, data, length, &announce, 1);
1684
1685
112
    if (unpacked_announces <= 0) {
1686
0
        LOGGER_WARNING(chat->log, "Failed to unpack announces: %d", unpacked_announces);
1687
0
        return false;
1688
0
    }
1689
1690
112
    if (memcmp(announce.peer_public_key, chat->self_public_key.enc, ENC_PUBLIC_KEY_SIZE) == 0) {
1691
0
        LOGGER_WARNING(chat->log, "Attempted to unpack our own announce");
1692
0
        return true;
1693
0
    }
1694
1695
112
    if (!gca_is_valid_announce(&announce)) {
1696
0
        LOGGER_WARNING(chat->log, "got invalid announce");
1697
0
        return false;
1698
0
    }
1699
1700
112
    const IP_Port *ip_port = announce.ip_port_is_set ? &announce.ip_port : nullptr;
1701
112
    const int new_peer_number = peer_add(chat, ip_port, announce.peer_public_key);
1702
1703
112
    if (new_peer_number == -1) {
1704
0
        LOGGER_ERROR(chat->log, "peer_add() failed");
1705
0
        return false;
1706
0
    }
1707
1708
112
    if (new_peer_number == -2) {  // peer already added
1709
101
        return true;
1710
101
    }
1711
1712
11
    if (new_peer_number > 0) {
1713
11
        GC_Connection *new_gconn = get_gc_connection(chat, new_peer_number);
1714
1715
11
        if (new_gconn == nullptr) {
1716
0
            return false;
1717
0
        }
1718
1719
11
        uint32_t added_tcp_relays = 0;
1720
1721
11
        for (uint8_t i = 0; i < announce.tcp_relays_count; ++i) {
1722
0
            const int add_tcp_result = add_tcp_relay_connection(chat->tcp_conn, new_gconn->tcp_connection_num,
1723
0
                                       &announce.tcp_relays[i].ip_port,
1724
0
                                       announce.tcp_relays[i].public_key);
1725
1726
0
            if (add_tcp_result == -1) {
1727
0
                continue;
1728
0
            }
1729
1730
0
            if (gcc_save_tcp_relay(chat->rng, new_gconn, &announce.tcp_relays[i]) == 0) {
1731
0
                ++added_tcp_relays;
1732
0
            }
1733
0
        }
1734
1735
11
        if (!announce.ip_port_is_set && added_tcp_relays == 0) {
1736
0
            gcc_mark_for_deletion(new_gconn, chat->tcp_conn, GC_EXIT_TYPE_DISCONNECTED, nullptr, 0);
1737
0
            LOGGER_ERROR(chat->log, "Sync error: Invalid peer connection info");
1738
0
            return false;
1739
0
        }
1740
1741
11
        new_gconn->pending_handshake_type = HS_PEER_INFO_EXCHANGE;
1742
1743
11
        return true;
1744
11
    }
1745
1746
0
    LOGGER_FATAL(chat->log, "got impossible return value %d", new_peer_number);
1747
1748
0
    return false;
1749
11
}
1750
1751
/** @brief Handles a sync response packet.
1752
 *
1753
 * Note: This function may change peer numbers.
1754
 *
1755
 * Return 0 on success.
1756
 * Return -1 if the group is full or the peer failed to unpack.
1757
 * Return -2 if `peer_number` does not designate a valid peer.
1758
 */
1759
static int handle_gc_sync_response(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat, uint32_t peer_number, const uint8_t *_Nullable data,
1760
                                   uint16_t length, void *_Nullable userdata)
1761
206
{
1762
206
    if (chat->connection_state == CS_CONNECTED && get_gc_confirmed_numpeers(chat) >= chat->shared_state.maxpeers
1763
206
            && !peer_is_founder(chat, peer_number)) {
1764
0
        return -1;
1765
0
    }
1766
1767
206
    if (length > 0) {
1768
112
        if (!unpack_gc_sync_announce(chat, data, length)) {
1769
0
            return -1;
1770
0
        }
1771
112
    }
1772
1773
206
    chat->connection_state = CS_CONNECTED;
1774
1775
206
    GC_Connection *gconn = get_gc_connection(chat, peer_number);
1776
1777
206
    if (gconn == nullptr) {
1778
0
        return -2;
1779
0
    }
1780
1781
206
    if (!send_gc_peer_exchange(chat, gconn)) {
1782
6
        LOGGER_WARNING(chat->log, "Failed to send peer exchange on sync response");
1783
6
    }
1784
1785
206
    if (c->self_join != nullptr && chat->time_connected == 0) {
1786
103
        c->self_join(c->messenger, chat->group_number, userdata);
1787
103
        chat->time_connected = mono_time_get(chat->mono_time);
1788
103
    }
1789
1790
206
    return 0;
1791
206
}
1792
1793
static int get_gc_peer_public_key(const GC_Chat *_Nonnull chat, uint32_t peer_number, uint8_t *_Nonnull public_key);
1794
static bool send_peer_shared_state(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn);
1795
static bool send_peer_mod_list(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn);
1796
static bool send_peer_sanctions_list(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn);
1797
static bool send_peer_topic(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn);
1798
1799
/** @brief Creates a sync announce for peer designated by `gconn` and puts it in `announce`, which
1800
 * must be zeroed by the caller.
1801
 *
1802
 * Returns true if announce was successfully created.
1803
 */
1804
static bool create_sync_announce(const GC_Chat *_Nonnull chat, const GC_Connection *_Nonnull gconn, uint32_t peer_number, GC_Announce *_Nonnull announce)
1805
112
{
1806
112
    if (chat == nullptr || gconn == nullptr) {
1807
0
        return false;
1808
0
    }
1809
1810
112
    if (gconn->tcp_relays_count > 0) {
1811
0
        if (gcc_copy_tcp_relay(chat->rng, &announce->tcp_relays[0], gconn)) {
1812
0
            announce->tcp_relays_count = 1;
1813
0
        }
1814
0
    }
1815
1816
112
    get_gc_peer_public_key(chat, peer_number, announce->peer_public_key);
1817
1818
112
    if (gcc_ip_port_is_set(gconn)) {
1819
112
        announce->ip_port = gconn->addr.ip_port;
1820
112
        announce->ip_port_is_set = true;
1821
112
    }
1822
1823
112
    return true;
1824
112
}
1825
1826
static bool sync_response_send_peers(GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn, uint32_t peer_number, bool first_sync)
1827
157
{
1828
    // Always respond to a peer's first sync request
1829
157
    if (!first_sync && !mono_time_is_timeout(chat->mono_time,
1830
27
            chat->last_sync_response_peer_list,
1831
27
            GC_SYNC_RESPONSE_PEER_LIST_LIMIT)) {
1832
12
        return true;
1833
12
    }
1834
1835
145
    uint8_t *response = (uint8_t *)mem_balloc(chat->mem, MAX_GC_PACKET_CHUNK_SIZE);
1836
1837
145
    if (response == nullptr) {
1838
0
        return false;
1839
0
    }
1840
1841
145
    size_t num_announces = 0;
1842
1843
472
    for (uint32_t i = 1; i < chat->numpeers; ++i) {
1844
327
        const GC_Connection *peer_gconn = get_gc_connection(chat, i);
1845
1846
327
        if (peer_gconn == nullptr || !peer_gconn->confirmed) {
1847
193
            continue;
1848
193
        }
1849
1850
134
        if (peer_gconn->public_key_hash == gconn->public_key_hash || i == peer_number) {
1851
22
            continue;
1852
22
        }
1853
1854
112
        GC_Announce announce = {0};
1855
1856
112
        if (!create_sync_announce(chat, peer_gconn, i, &announce)) {
1857
0
            continue;
1858
0
        }
1859
1860
112
        const int packed_length = gca_pack_announce(chat->log, response, MAX_GC_PACKET_CHUNK_SIZE, &announce);
1861
1862
112
        if (packed_length <= 0) {
1863
0
            LOGGER_WARNING(chat->log, "Failed to pack announce: %d", packed_length);
1864
0
            continue;
1865
0
        }
1866
1867
112
        if (!send_gc_sync_response(chat, gconn, response, packed_length)) {
1868
0
            LOGGER_WARNING(chat->log, "Failed to send peer announce info");
1869
0
            continue;
1870
0
        }
1871
1872
112
        ++num_announces;
1873
112
    }
1874
1875
145
    mem_delete(chat->mem, response);
1876
1877
145
    if (num_announces == 0) {
1878
        // we send an empty sync response even if we didn't send any peers as an acknowledgement
1879
94
        if (!send_gc_sync_response(chat, gconn, nullptr, 0)) {
1880
0
            LOGGER_WARNING(chat->log, "Failed to send peer announce info");
1881
0
            return false;
1882
0
        }
1883
94
    } else {
1884
51
        chat->last_sync_response_peer_list = mono_time_get(chat->mono_time);
1885
51
    }
1886
1887
145
    return true;
1888
145
}
1889
1890
/** @brief Sends group state specified by `sync_flags` peer designated by `peer_number`.
1891
 *
1892
 * Return true on success.
1893
 */
1894
static bool sync_response_send_state(GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn, uint32_t peer_number, uint16_t sync_flags)
1895
196
{
1896
196
    const bool first_sync = gconn->last_sync_response == 0;
1897
1898
    // Do not change the order of these four send calls. See: https://toktok.ltd/spec.html#sync_request-0xf8
1899
196
    if ((sync_flags & GF_STATE) > 0 && chat->shared_state.version > 0) {
1900
192
        if (!send_peer_shared_state(chat, gconn)) {
1901
0
            LOGGER_WARNING(chat->log, "Failed to send shared state");
1902
0
            return false;
1903
0
        }
1904
1905
192
        if (!send_peer_mod_list(chat, gconn)) {
1906
3
            LOGGER_WARNING(chat->log, "Failed to send mod list");
1907
3
            return false;
1908
3
        }
1909
1910
189
        if (!send_peer_sanctions_list(chat, gconn)) {
1911
0
            LOGGER_WARNING(chat->log, "Failed to send sanctions list");
1912
0
            return false;
1913
0
        }
1914
1915
189
        gconn->last_sync_response = mono_time_get(chat->mono_time);
1916
189
    }
1917
1918
193
    if ((sync_flags & GF_TOPIC) > 0 && chat->time_connected > 0 && chat->topic_info.version > 0) {
1919
131
        if (!send_peer_topic(chat, gconn)) {
1920
0
            LOGGER_WARNING(chat->log, "Failed to send topic");
1921
0
            return false;
1922
0
        }
1923
1924
131
        gconn->last_sync_response = mono_time_get(chat->mono_time);
1925
131
    }
1926
1927
193
    if ((sync_flags & GF_PEERS) > 0) {
1928
157
        if (!sync_response_send_peers(chat, gconn, peer_number, first_sync)) {
1929
0
            return false;
1930
0
        }
1931
1932
157
        gconn->last_sync_response = mono_time_get(chat->mono_time);
1933
157
    }
1934
1935
193
    return true;
1936
193
}
1937
1938
/** @brief Handles a sync request packet and sends a response containing the peer list.
1939
 *
1940
 * May send additional group info in separate packets, including the topic, shared state, mod list,
1941
 * and sanctions list, if respective sync flags are set.
1942
 *
1943
 * If the group is password protected the password in the request data must first be verified.
1944
 *
1945
 * Return 0 if packet is handled correctly.
1946
 * Return -1 if packet has invalid size.
1947
 * Return -2 if password is invalid.
1948
 * Return -3 if we fail to send a response packet.
1949
 * Return -4 if `peer_number` does not designate a valid peer.
1950
 */
1951
static int handle_gc_sync_request(GC_Chat *_Nonnull chat, uint32_t peer_number, const uint8_t *_Nonnull data, uint16_t length)
1952
196
{
1953
196
    GC_Connection *gconn = get_gc_connection(chat, peer_number);
1954
1955
196
    if (gconn == nullptr) {
1956
0
        return -4;
1957
0
    }
1958
1959
196
    if (length < sizeof(uint16_t)) {
1960
0
        return -1;
1961
0
    }
1962
1963
196
    if (chat->numpeers <= 1) {
1964
0
        return 0;
1965
0
    }
1966
1967
196
    if (chat->shared_state.version == 0) {
1968
0
        LOGGER_DEBUG(chat->log, "Got sync request with uninitialized state");
1969
0
        return 0;
1970
0
    }
1971
1972
196
    if (!mono_time_is_timeout(chat->mono_time, gconn->last_sync_response, GC_PING_TIMEOUT)) {
1973
0
        LOGGER_DEBUG(chat->log, "sync request rate limit for peer %u", peer_number);
1974
0
        return 0;
1975
0
    }
1976
1977
196
    uint16_t sync_flags;
1978
196
    net_unpack_u16(data, &sync_flags);
1979
1980
196
    if (chat_is_password_protected(chat)) {
1981
32
        if (length < (sizeof(uint16_t) * 2) + MAX_GC_PASSWORD_SIZE) {
1982
0
            return -2;
1983
0
        }
1984
1985
32
        uint16_t password_length;
1986
32
        net_unpack_u16(data + sizeof(uint16_t), &password_length);
1987
1988
32
        const uint8_t *password = data + (sizeof(uint16_t) * 2);
1989
1990
32
        if (!validate_password(chat, password, password_length)) {
1991
0
            LOGGER_DEBUG(chat->log, "Invalid password");
1992
0
            return -2;
1993
0
        }
1994
32
    }
1995
1996
196
    if (!sync_response_send_state(chat, gconn, peer_number, sync_flags)) {
1997
3
        return -3;
1998
3
    }
1999
2000
193
    return 0;
2001
196
}
2002
2003
static void copy_self(const GC_Chat *_Nonnull chat, GC_Peer *_Nonnull peer);
2004
static bool send_gc_peer_info_request(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn);
2005
2006
/** @brief Shares our TCP relays with peer and adds shared relays to our connection with them.
2007
 *
2008
 * Returns true on success or if we're not connected to any TCP relays.
2009
 */
2010
static bool send_gc_tcp_relays(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn)
2011
0
{
2012
2013
0
    Node_format tcp_relays[GCC_MAX_TCP_SHARED_RELAYS];
2014
0
    uint8_t data[GCC_MAX_TCP_SHARED_RELAYS * PACKED_NODE_SIZE_IP6];
2015
2016
0
    const uint32_t n = tcp_copy_connected_relays_index(chat->tcp_conn, tcp_relays, GCC_MAX_TCP_SHARED_RELAYS,
2017
0
                       gconn->tcp_relay_share_index);
2018
2019
0
    if (n == 0) {
2020
0
        return true;
2021
0
    }
2022
2023
0
    gconn->tcp_relay_share_index += GCC_MAX_TCP_SHARED_RELAYS;
2024
2025
0
    for (uint32_t i = 0; i < n; ++i) {
2026
0
        add_tcp_relay_connection(chat->tcp_conn, gconn->tcp_connection_num, &tcp_relays[i].ip_port,
2027
0
                                 tcp_relays[i].public_key);
2028
0
    }
2029
2030
0
    const int nodes_len = pack_nodes(chat->log, data, sizeof(data), tcp_relays, n);
2031
2032
0
    if (nodes_len <= 0 || (uint32_t)nodes_len > sizeof(data)) {
2033
0
        LOGGER_ERROR(chat->log, "Failed to pack tcp relays (nodes_len: %d)", nodes_len);
2034
0
        return false;
2035
0
    }
2036
2037
0
    if (!send_lossless_group_packet(chat, gconn, data, (uint16_t)nodes_len, GP_TCP_RELAYS)) {
2038
0
        LOGGER_ERROR(chat->log, "Failed to send tcp relays");
2039
0
        return false;
2040
0
    }
2041
2042
0
    return true;
2043
0
}
2044
2045
/** @brief Adds a peer's shared TCP relays to our connection with them.
2046
 *
2047
 * Return 0 if packet is handled correctly.
2048
 * Return -1 if packet has invalid size.
2049
 * Return -2 if packet contains invalid data.
2050
 */
2051
static int handle_gc_tcp_relays(GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn, const uint8_t *_Nonnull data, uint16_t length)
2052
0
{
2053
0
    if (length == 0) {
2054
0
        return -1;
2055
0
    }
2056
2057
0
    Node_format tcp_relays[GCC_MAX_TCP_SHARED_RELAYS];
2058
0
    const int num_nodes = unpack_nodes(tcp_relays, GCC_MAX_TCP_SHARED_RELAYS, nullptr, data, length, true);
2059
2060
0
    if (num_nodes <= 0) {
2061
0
        return -2;
2062
0
    }
2063
2064
0
    for (int i = 0; i < num_nodes; ++i) {
2065
0
        const Node_format *tcp_node = &tcp_relays[i];
2066
2067
0
        if (add_tcp_relay_connection(chat->tcp_conn, gconn->tcp_connection_num, &tcp_node->ip_port,
2068
0
                                     tcp_node->public_key) == 0) {
2069
0
            gcc_save_tcp_relay(chat->rng, gconn, tcp_node);
2070
2071
0
            if (gconn->tcp_relays_count == 1) {
2072
0
                add_gc_saved_peers(chat, gconn);  // make sure we save at least one tcp relay
2073
0
            }
2074
0
        }
2075
0
    }
2076
2077
0
    return 0;
2078
0
}
2079
2080
/** @brief Send invite request to peer_number.
2081
 *
2082
 * If the group requires a password, the packet will
2083
 * contain the password supplied by the invite requestor.
2084
 *
2085
 * Return true on success.
2086
 */
2087
static bool send_gc_invite_request(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn)
2088
357
{
2089
357
    if (!chat_is_password_protected(chat)) {
2090
300
        return send_lossless_group_packet(chat, gconn, nullptr, 0, GP_INVITE_REQUEST);
2091
300
    }
2092
2093
57
    uint8_t data[sizeof(uint16_t) + MAX_GC_PASSWORD_SIZE];
2094
2095
57
    net_pack_u16(data, chat->shared_state.password_length);
2096
57
    uint16_t length = sizeof(uint16_t);
2097
2098
57
    memcpy(data + length, chat->shared_state.password, MAX_GC_PASSWORD_SIZE);
2099
57
    length += MAX_GC_PASSWORD_SIZE;
2100
2101
57
    return send_lossless_group_packet(chat, gconn, data, length, GP_INVITE_REQUEST);
2102
357
}
2103
2104
static bool send_gc_invite_response(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn)
2105
204
{
2106
204
    return send_lossless_group_packet(chat, gconn, nullptr, 0, GP_INVITE_RESPONSE);
2107
204
}
2108
2109
/** @brief Handles an invite response packet.
2110
 *
2111
 * Return 0 if packet is correctly handled.
2112
 * Return -1 if we fail to send a sync request.
2113
 */
2114
static int handle_gc_invite_response(GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn)
2115
204
{
2116
204
    const uint16_t flags = GF_PEERS | GF_TOPIC | GF_STATE;
2117
2118
204
    if (!send_gc_sync_request(chat, gconn, flags)) {
2119
0
        return -1;
2120
0
    }
2121
2122
204
    return 0;
2123
204
}
2124
2125
/**
2126
 * @brief Handles an invite response reject packet.
2127
 *
2128
 * Return 0 if packet is handled correctly.
2129
 * Return -1 if packet has invalid size.
2130
 */
2131
static int handle_gc_invite_response_reject(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat, const uint8_t *_Nonnull data, uint16_t length,
2132
        void *_Nullable userdata)
2133
3
{
2134
3
    if (length < sizeof(uint8_t)) {
2135
0
        return -1;
2136
0
    }
2137
2138
3
    if (chat->connection_state == CS_CONNECTED) {
2139
0
        return 0;
2140
0
    }
2141
2142
3
    if (gc_get_self_role(chat) == GR_FOUNDER) {
2143
0
        return 0;
2144
0
    }
2145
2146
3
    uint8_t type = data[0];
2147
2148
3
    if (type >= GJ_INVALID) {
2149
0
        type = GJ_INVITE_FAILED;
2150
0
    }
2151
2152
3
    chat->connection_state = CS_DISCONNECTED;
2153
2154
3
    if (c->rejected != nullptr) {
2155
3
        c->rejected(c->messenger, chat->group_number, type, userdata);
2156
3
    }
2157
2158
3
    return 0;
2159
3
}
2160
2161
/** @brief Sends an invite response rejection packet to peer designated by `gconn`.
2162
 *
2163
 * Return true on success.
2164
 */
2165
static bool send_gc_invite_response_reject(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn, uint8_t type)
2166
5
{
2167
5
    if (type >= GJ_INVALID) {
2168
0
        type = GJ_INVITE_FAILED;
2169
0
    }
2170
2171
5
    uint8_t data[1];
2172
5
    data[0] = type;
2173
5
    const uint16_t length = 1;
2174
2175
5
    return send_lossy_group_packet(chat, gconn, data, length, GP_INVITE_RESPONSE_REJECT);
2176
5
}
2177
2178
/** @brief Handles an invite request and verifies that the correct password has been supplied
2179
 * if the group is password protected.
2180
 *
2181
 * Return 0 if invite request is successfully handled.
2182
 * Return -1 if the group is full.
2183
 * Return -2 if the supplied password is invalid.
2184
 * Return -3 if we fail to send an invite response.
2185
 * Return -4 if peer_number does not designate a valid peer.
2186
 */
2187
static int handle_gc_invite_request(GC_Chat *_Nonnull chat, uint32_t peer_number, const uint8_t *_Nullable data, uint16_t length)
2188
354
{
2189
354
    if (chat->shared_state.version == 0) {  // we aren't synced yet; ignore request
2190
145
        return 0;
2191
145
    }
2192
2193
209
    GC_Connection *gconn = get_gc_connection(chat, peer_number);
2194
2195
209
    if (gconn == nullptr) {
2196
0
        return -4;
2197
0
    }
2198
2199
209
    int ret = -1;
2200
2201
209
    uint8_t invite_error;
2202
2203
209
    if (get_gc_confirmed_numpeers(chat) >= chat->shared_state.maxpeers && !peer_is_founder(chat, peer_number)) {
2204
1
        invite_error = GJ_GROUP_FULL;
2205
1
        goto FAILED_INVITE;
2206
1
    }
2207
2208
208
    if (chat_is_password_protected(chat)) {
2209
40
        invite_error = GJ_INVALID_PASSWORD;
2210
40
        ret = -2;
2211
2212
40
        if (length < sizeof(uint16_t) + MAX_GC_PASSWORD_SIZE) {
2213
2
            goto FAILED_INVITE;
2214
2
        }
2215
2216
38
        uint16_t password_length;
2217
38
        net_unpack_u16(data, &password_length);
2218
2219
38
        const uint8_t *password = data + sizeof(uint16_t);
2220
2221
38
        if (!validate_password(chat, password, password_length)) {
2222
2
            goto FAILED_INVITE;
2223
2
        }
2224
38
    }
2225
2226
204
    if (!send_gc_invite_response(chat, gconn)) {
2227
0
        return -3;
2228
0
    }
2229
2230
204
    return 0;
2231
2232
5
FAILED_INVITE:
2233
5
    send_gc_invite_response_reject(chat, gconn, invite_error);
2234
5
    gcc_mark_for_deletion(gconn, chat->tcp_conn, GC_EXIT_TYPE_DISCONNECTED, nullptr, 0);
2235
2236
5
    return ret;
2237
204
}
2238
2239
/** @brief Sends a lossless packet of type and length to all confirmed peers.
2240
 *
2241
 * Return true if packet is successfully sent to at least one peer or the
2242
 * group is empty.
2243
 */
2244
static bool send_gc_lossless_packet_all_peers(const GC_Chat *_Nonnull chat, const uint8_t *_Nonnull data, uint16_t length, uint8_t type)
2245
14.5k
{
2246
14.5k
    uint32_t sent = 0;
2247
14.5k
    uint32_t confirmed_peers = 0;
2248
2249
25.8k
    for (uint32_t i = 1; i < chat->numpeers; ++i) {
2250
11.3k
        GC_Connection *gconn = get_gc_connection(chat, i);
2251
2252
11.3k
        assert(gconn != nullptr);
2253
2254
11.3k
        if (!gconn->confirmed) {
2255
621
            continue;
2256
621
        }
2257
2258
10.6k
        ++confirmed_peers;
2259
2260
10.6k
        if (send_lossless_group_packet(chat, gconn, data, length, type)) {
2261
10.6k
            ++sent;
2262
10.6k
        }
2263
10.6k
    }
2264
2265
14.5k
    return sent > 0 || confirmed_peers == 0;
2266
14.5k
}
2267
2268
/** @brief Sends a lossy packet of type and length to all confirmed peers.
2269
 *
2270
 * Return true if packet is successfully sent to at least one peer or the
2271
 * group is empty.
2272
 */
2273
static bool send_gc_lossy_packet_all_peers(const GC_Chat *_Nonnull chat, const uint8_t *_Nonnull data, uint16_t length, uint8_t type)
2274
2
{
2275
2
    uint32_t sent = 0;
2276
2
    uint32_t confirmed_peers = 0;
2277
2278
4
    for (uint32_t i = 1; i < chat->numpeers; ++i) {
2279
2
        GC_Connection *gconn = get_gc_connection(chat, i);
2280
2281
2
        assert(gconn != nullptr);
2282
2283
2
        if (!gconn->confirmed) {
2284
0
            continue;
2285
0
        }
2286
2287
2
        ++confirmed_peers;
2288
2289
2
        if (send_lossy_group_packet(chat, gconn, data, length, type)) {
2290
2
            ++sent;
2291
2
        }
2292
2
    }
2293
2294
2
    return sent > 0 || confirmed_peers == 0;
2295
2
}
2296
2297
/** @brief Creates packet with broadcast header info followed by data of length.
2298
 *
2299
 * Returns length of packet including header.
2300
 */
2301
static uint16_t make_gc_broadcast_header(const uint8_t *_Nullable data, uint16_t length, uint8_t *_Nonnull packet, uint8_t bc_type)
2302
13.8k
{
2303
13.8k
    packet[0] = bc_type;
2304
13.8k
    const uint16_t header_len = sizeof(uint8_t);
2305
2306
13.8k
    if (data != nullptr && length > 0) {
2307
9.43k
        memcpy(packet + header_len, data, length);
2308
9.43k
    }
2309
2310
13.8k
    return length + header_len;
2311
13.8k
}
2312
2313
/** @brief sends a group broadcast packet to all confirmed peers.
2314
 *
2315
 * Returns true on success.
2316
 */
2317
static bool send_gc_broadcast_message(const GC_Chat *_Nonnull chat, const uint8_t *_Nullable data, uint16_t length, uint8_t bc_type)
2318
13.8k
{
2319
13.8k
    if (length + GC_BROADCAST_ENC_HEADER_SIZE > MAX_GC_PACKET_SIZE) {
2320
0
        LOGGER_ERROR(chat->log, "Failed to broadcast message: invalid length %u", length);
2321
0
        return false;
2322
0
    }
2323
2324
13.8k
    uint8_t *packet = (uint8_t *)mem_balloc(chat->mem, length + GC_BROADCAST_ENC_HEADER_SIZE);
2325
2326
13.8k
    if (packet == nullptr) {
2327
6
        return false;
2328
6
    }
2329
2330
13.8k
    const uint16_t packet_len = make_gc_broadcast_header(data, length, packet, bc_type);
2331
2332
13.8k
    const bool ret = send_gc_lossless_packet_all_peers(chat, packet, packet_len, GP_BROADCAST);
2333
2334
13.8k
    mem_delete(chat->mem, packet);
2335
2336
13.8k
    return ret;
2337
13.8k
}
2338
2339
static bool group_topic_lock_enabled(const GC_Chat *_Nonnull chat);
2340
2341
/** @brief Compares the supplied values with our own state and returns the appropriate
2342
 * sync flags for a sync request.
2343
 */
2344
static uint16_t get_sync_flags(const GC_Chat *_Nonnull chat, uint16_t peers_checksum, uint16_t peer_count, uint32_t sstate_version, uint32_t screds_version, uint16_t roles_checksum,
2345
                               uint32_t topic_version, uint16_t topic_checksum)
2346
415
{
2347
415
    uint16_t sync_flags = 0;
2348
2349
415
    if (peers_checksum != chat->peers_checksum && peer_count >= get_gc_confirmed_numpeers(chat)) {
2350
139
        sync_flags |= GF_PEERS;
2351
139
    }
2352
2353
415
    if (sstate_version > 0) {
2354
415
        const uint16_t self_roles_checksum = chat->moderation.sanctions_creds.checksum + chat->roles_checksum;
2355
2356
415
        if ((sstate_version > chat->shared_state.version || screds_version > chat->moderation.sanctions_creds.version)
2357
415
                || (screds_version == chat->moderation.sanctions_creds.version
2358
411
                    && roles_checksum != self_roles_checksum)) {
2359
269
            sync_flags |= GF_STATE;
2360
269
        }
2361
415
    }
2362
2363
415
    if (group_topic_lock_enabled(chat)) {
2364
385
        if (topic_version > chat->topic_info.version ||
2365
385
                (topic_version == chat->topic_info.version && topic_checksum > chat->topic_info.checksum)) {
2366
8
            sync_flags |= GF_TOPIC;
2367
8
        }
2368
385
    } else if (topic_checksum > chat->topic_info.checksum) {
2369
11
        sync_flags |= GF_TOPIC;
2370
11
    }
2371
2372
415
    return sync_flags;
2373
415
}
2374
2375
/** @brief Compares a peer's group sync info that we received in a ping packet to our own.
2376
 *
2377
 * If their info appears to be more recent than ours we send them a sync request.
2378
 *
2379
 * This function should only be called from `handle_gc_ping()`.
2380
 *
2381
 * Returns true if a sync request packet is successfully sent.
2382
 */
2383
static bool do_gc_peer_state_sync(GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn, const uint8_t *_Nonnull sync_data, const uint16_t length)
2384
415
{
2385
415
    if (length < GC_PING_PACKET_MIN_DATA_SIZE) {
2386
0
        return false;
2387
0
    }
2388
2389
415
    uint16_t peers_checksum;
2390
415
    uint16_t peer_count;
2391
415
    uint32_t sstate_version;
2392
415
    uint32_t screds_version;
2393
415
    uint16_t roles_checksum;
2394
415
    uint32_t topic_version;
2395
415
    uint16_t topic_checksum;
2396
2397
415
    size_t unpacked_len = 0;
2398
2399
415
    net_unpack_u16(sync_data, &peers_checksum);
2400
415
    unpacked_len += sizeof(uint16_t);
2401
2402
415
    net_unpack_u16(sync_data + unpacked_len, &peer_count);
2403
415
    unpacked_len += sizeof(uint16_t);
2404
2405
415
    net_unpack_u32(sync_data + unpacked_len, &sstate_version);
2406
415
    unpacked_len += sizeof(uint32_t);
2407
2408
415
    net_unpack_u32(sync_data + unpacked_len, &screds_version);
2409
415
    unpacked_len += sizeof(uint32_t);
2410
2411
415
    net_unpack_u16(sync_data + unpacked_len, &roles_checksum);
2412
415
    unpacked_len += sizeof(uint16_t);
2413
2414
415
    net_unpack_u32(sync_data + unpacked_len, &topic_version);
2415
415
    unpacked_len += sizeof(uint32_t);
2416
2417
415
    net_unpack_u16(sync_data + unpacked_len, &topic_checksum);
2418
415
    unpacked_len += sizeof(uint16_t);
2419
2420
415
    if (unpacked_len != GC_PING_PACKET_MIN_DATA_SIZE) {
2421
0
        LOGGER_FATAL(chat->log, "Unpacked length is impossible (%zu)", unpacked_len);
2422
0
        return false;
2423
0
    }
2424
2425
415
    const uint16_t sync_flags = get_sync_flags(chat, peers_checksum, peer_count, sstate_version, screds_version,
2426
415
                                roles_checksum, topic_version, topic_checksum);
2427
2428
415
    if (sync_flags > 0) {
2429
276
        return send_gc_sync_request(chat, gconn, sync_flags);
2430
276
    }
2431
2432
139
    return false;
2433
415
}
2434
2435
/** @brief Handles a ping packet.
2436
 *
2437
 * The packet contains sync information including peer's peer list checksum,
2438
 * shared state version, topic version, and sanction credentials version.
2439
 *
2440
 * Return 0 if packet is handled correctly.
2441
 * Return -1 if packet has invalid size or peer is not confirmed.
2442
 */
2443
static int handle_gc_ping(GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn, const uint8_t *_Nonnull data, uint16_t length)
2444
415
{
2445
415
    if (length < GC_PING_PACKET_MIN_DATA_SIZE) {
2446
0
        return -1;
2447
0
    }
2448
2449
415
    if (!gconn->confirmed) {
2450
0
        return -1;
2451
0
    }
2452
2453
415
    do_gc_peer_state_sync(chat, gconn, data, length);
2454
2455
415
    if (length > GC_PING_PACKET_MIN_DATA_SIZE) {
2456
0
        IP_Port ip_port = {{{0}}};
2457
2458
0
        if (unpack_ip_port(&ip_port, data + GC_PING_PACKET_MIN_DATA_SIZE,
2459
0
                           length - GC_PING_PACKET_MIN_DATA_SIZE, false) > 0) {
2460
0
            gcc_set_ip_port(gconn, &ip_port);
2461
0
            add_gc_saved_peers(chat, gconn);
2462
0
        }
2463
0
    }
2464
2465
415
    return 0;
2466
415
}
2467
2468
int gc_set_self_status(const Messenger *m, int group_number, Group_Peer_Status status)
2469
50
{
2470
50
    const GC_Session *c = m->group_handler;
2471
50
    const GC_Chat *chat = gc_get_group(c, group_number);
2472
2473
50
    if (chat == nullptr) {
2474
0
        return -1;
2475
0
    }
2476
2477
50
    self_gc_set_status(chat, status);
2478
2479
50
    uint8_t data[1];
2480
50
    data[0] = gc_get_self_status(chat);
2481
2482
50
    if (!send_gc_broadcast_message(chat, data, 1, GM_STATUS)) {
2483
6
        return -2;
2484
6
    }
2485
2486
44
    return 0;
2487
50
}
2488
2489
/** @brief Handles a status broadcast from `peer`.
2490
 *
2491
 * Return 0 if packet is handled correctly.
2492
 * Return -1 if packet has invalid length.
2493
 */
2494
static int handle_gc_status(const GC_Session *_Nonnull c, const GC_Chat *_Nonnull chat, GC_Peer *_Nonnull peer, const uint8_t *_Nonnull data,
2495
                            uint16_t length, void *_Nullable userdata)
2496
41
{
2497
41
    if (length < sizeof(uint8_t)) {
2498
0
        return -1;
2499
0
    }
2500
2501
41
    const Group_Peer_Status status = (Group_Peer_Status)data[0];
2502
2503
41
    if (status > GS_BUSY) {
2504
0
        LOGGER_WARNING(chat->log, "Received invalid status %u", status);
2505
0
        return 0;
2506
0
    }
2507
2508
41
    peer->status = status;
2509
2510
41
    if (c->status_change != nullptr) {
2511
41
        c->status_change(c->messenger, chat->group_number, peer->peer_id, status, userdata);
2512
41
    }
2513
2514
41
    return 0;
2515
41
}
2516
2517
uint8_t gc_get_status(const GC_Chat *chat, GC_Peer_Id peer_id)
2518
5
{
2519
5
    const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
2520
2521
5
    const GC_Peer *peer = get_gc_peer(chat, peer_number);
2522
2523
5
    if (peer == nullptr) {
2524
0
        return UINT8_MAX;
2525
0
    }
2526
2527
5
    return peer->status;
2528
5
}
2529
2530
uint8_t gc_get_role(const GC_Chat *chat, GC_Peer_Id peer_id)
2531
1.39k
{
2532
1.39k
    const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
2533
2534
1.39k
    const GC_Peer *peer = get_gc_peer(chat, peer_number);
2535
2536
1.39k
    if (peer == nullptr) {
2537
0
        return UINT8_MAX;
2538
0
    }
2539
2540
1.39k
    return peer->role;
2541
1.39k
}
2542
2543
void gc_get_chat_id(const GC_Chat *chat, uint8_t *dest)
2544
115
{
2545
115
    if (dest != nullptr) {
2546
115
        memcpy(dest, get_chat_id(&chat->chat_public_key), CHAT_ID_SIZE);
2547
115
    }
2548
115
}
2549
2550
/** @brief Sends self peer info to `gconn`.
2551
 *
2552
 * If the group is password protected the request will contain the group
2553
 * password, which the recipient will validate in the respective
2554
 * group message handler.
2555
 *
2556
 * Returns true on success.
2557
 */
2558
static bool send_self_to_peer(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn)
2559
427
{
2560
427
    GC_Peer *self = (GC_Peer *)mem_alloc(chat->mem, sizeof(GC_Peer));
2561
2562
427
    if (self == nullptr) {
2563
2
        return false;
2564
2
    }
2565
2566
425
    copy_self(chat, self);
2567
2568
425
    const uint16_t data_size = PACKED_GC_PEER_SIZE + sizeof(uint16_t) + MAX_GC_PASSWORD_SIZE;
2569
425
    uint8_t *data = (uint8_t *)mem_balloc(chat->mem, data_size);
2570
2571
425
    if (data == nullptr) {
2572
2
        mem_delete(chat->mem, self);
2573
2
        return false;
2574
2
    }
2575
2576
423
    uint16_t length = 0;
2577
2578
423
    if (chat_is_password_protected(chat)) {
2579
76
        net_pack_u16(data, chat->shared_state.password_length);
2580
76
        length += sizeof(uint16_t);
2581
2582
76
        memcpy(data + sizeof(uint16_t), chat->shared_state.password, MAX_GC_PASSWORD_SIZE);
2583
76
        length += MAX_GC_PASSWORD_SIZE;
2584
76
    }
2585
2586
423
    const int packed_len = pack_gc_peer(data + length, data_size - length, self);
2587
423
    length += packed_len;
2588
2589
423
    mem_delete(chat->mem, self);
2590
2591
423
    if (packed_len <= 0) {
2592
0
        LOGGER_DEBUG(chat->log, "pack_gc_peer failed in handle_gc_peer_info_request_request %d", packed_len);
2593
0
        mem_delete(chat->mem, data);
2594
0
        return false;
2595
0
    }
2596
2597
423
    const bool ret = send_lossless_group_packet(chat, gconn, data, length, GP_PEER_INFO_RESPONSE);
2598
2599
423
    mem_delete(chat->mem, data);
2600
2601
423
    return ret;
2602
423
}
2603
2604
/** @brief Handles a peer info request packet.
2605
 *
2606
 * Return 0 on success.
2607
 * Return -1 if unconfirmed peer is trying to join a full group.
2608
 * Return -2 if response fails.
2609
 * Return -3 if `peer_number` does not designate a valid peer.
2610
 */
2611
static int handle_gc_peer_info_request(const GC_Chat *_Nonnull chat, uint32_t peer_number)
2612
210
{
2613
210
    GC_Connection *gconn = get_gc_connection(chat, peer_number);
2614
2615
210
    if (gconn == nullptr) {
2616
0
        return -3;
2617
0
    }
2618
2619
210
    if (!gconn->confirmed && get_gc_confirmed_numpeers(chat) >= chat->shared_state.maxpeers
2620
210
            && !peer_is_founder(chat, peer_number)) {
2621
0
        return -1;
2622
0
    }
2623
2624
210
    if (!send_self_to_peer(chat, gconn)) {
2625
7
        return -2;
2626
7
    }
2627
2628
203
    return 0;
2629
210
}
2630
2631
/** @brief Sends a peer info request to peer designated by `gconn`.
2632
 *
2633
 * Return true on success.
2634
 */
2635
static bool send_gc_peer_info_request(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn)
2636
214
{
2637
214
    return send_lossless_group_packet(chat, gconn, nullptr, 0, GP_PEER_INFO_REQUEST);
2638
214
}
2639
2640
/** @brief Do peer info exchange with peer designated by `gconn`.
2641
 *
2642
 * This function sends two packets to a peer. The first packet is a peer info response containing our own info,
2643
 * and the second packet is a peer info request.
2644
 *
2645
 * Return false if either packet fails to send.
2646
 */
2647
static bool send_gc_peer_exchange(const GC_Chat *chat, GC_Connection *gconn)
2648
217
{
2649
217
    return send_self_to_peer(chat, gconn) && send_gc_peer_info_request(chat, gconn);
2650
217
}
2651
2652
/** @brief Updates peer's info, validates their group role, and sets them as a confirmed peer.
2653
 * If the group is password protected the password must first be validated.
2654
 *
2655
 * Return 0 if packet is handled correctly.
2656
 * Return -1 if packet has invalid size.
2657
 * Return -2 if group number is invalid.
2658
 * Return -3 if peer number is invalid.
2659
 * Return -4 if unconfirmed peer is trying to join a full group.
2660
 * Return -5 if supplied group password is invalid.
2661
 * Return -6 if we fail to add the peer to the peer list.
2662
 * Return -7 if peer's role cannot be validated.
2663
 * Return -8 if memory allocation fails.
2664
 */
2665
static int handle_gc_peer_info_response(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat, uint32_t peer_number,
2666
                                        const uint8_t *_Nonnull data, uint16_t length, void *_Nullable userdata)
2667
413
{
2668
413
    if (length < PACKED_GC_PEER_SIZE) {
2669
0
        return -1;
2670
0
    }
2671
2672
413
    GC_Peer *peer = get_gc_peer(chat, peer_number);
2673
2674
413
    if (peer == nullptr) {
2675
0
        return -3;
2676
0
    }
2677
2678
413
    GC_Connection *gconn = &peer->gconn;
2679
2680
413
    if (!gconn->confirmed && get_gc_confirmed_numpeers(chat) >= chat->shared_state.maxpeers
2681
413
            && !peer_is_founder(chat, peer_number)) {
2682
0
        return -4;
2683
0
    }
2684
2685
413
    uint16_t unpacked_len = 0;
2686
2687
413
    if (chat_is_password_protected(chat)) {
2688
76
        if (length < sizeof(uint16_t) + MAX_GC_PASSWORD_SIZE) {
2689
0
            return -5;
2690
0
        }
2691
2692
76
        uint16_t password_length;
2693
76
        net_unpack_u16(data, &password_length);
2694
76
        unpacked_len += sizeof(uint16_t);
2695
2696
76
        if (!validate_password(chat, data + unpacked_len, password_length)) {
2697
0
            return -5;
2698
0
        }
2699
2700
76
        unpacked_len += MAX_GC_PASSWORD_SIZE;
2701
76
    }
2702
2703
413
    if (length <= unpacked_len) {
2704
0
        return -1;
2705
0
    }
2706
2707
413
    GC_Peer *peer_info = (GC_Peer *)mem_alloc(chat->mem, sizeof(GC_Peer));
2708
2709
413
    if (peer_info == nullptr) {
2710
0
        return -8;
2711
0
    }
2712
2713
413
    if (unpack_gc_peer(peer_info, data + unpacked_len, length - unpacked_len) == -1) {
2714
0
        LOGGER_ERROR(chat->log, "unpack_gc_peer() failed");
2715
0
        mem_delete(chat->mem, peer_info);
2716
0
        return -6;
2717
0
    }
2718
2719
413
    if (peer_update(chat, peer_info, peer_number) == -1) {
2720
0
        LOGGER_WARNING(chat->log, "peer_update() failed");
2721
0
        mem_delete(chat->mem, peer_info);
2722
0
        return -6;
2723
0
    }
2724
2725
413
    mem_delete(chat->mem, peer_info);
2726
2727
413
    const bool was_confirmed = gconn->confirmed;
2728
413
    gconn->confirmed = true;
2729
2730
413
    update_gc_peer_roles(chat);
2731
2732
413
    add_gc_saved_peers(chat, gconn);
2733
2734
413
    set_gc_peerlist_checksum(chat);
2735
2736
413
    if (c->peer_join != nullptr && !was_confirmed) {
2737
238
        c->peer_join(c->messenger, chat->group_number, peer->peer_id, userdata);
2738
238
    }
2739
2740
413
    return 0;
2741
413
}
2742
2743
/** @brief Sends the group shared state and its signature to peer_number.
2744
 *
2745
 * Returns true on success.
2746
 */
2747
static bool send_peer_shared_state(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn)
2748
192
{
2749
192
    if (chat->shared_state.version == 0) {
2750
0
        return false;
2751
0
    }
2752
2753
192
    uint8_t packet[GC_SHARED_STATE_ENC_PACKET_SIZE];
2754
192
    const int length = make_gc_shared_state_packet(chat, packet, sizeof(packet));
2755
2756
192
    if (length != GC_SHARED_STATE_ENC_PACKET_SIZE) {
2757
0
        return false;
2758
0
    }
2759
2760
192
    return send_lossless_group_packet(chat, gconn, packet, (uint16_t)length, GP_SHARED_STATE);
2761
192
}
2762
2763
/** @brief Sends the group shared state and signature to all confirmed peers.
2764
 *
2765
 * Returns true on success.
2766
 */
2767
static bool broadcast_gc_shared_state(const GC_Chat *_Nonnull chat)
2768
223
{
2769
223
    uint8_t packet[GC_SHARED_STATE_ENC_PACKET_SIZE];
2770
223
    const int packet_len = make_gc_shared_state_packet(chat, packet, sizeof(packet));
2771
2772
223
    if (packet_len != GC_SHARED_STATE_ENC_PACKET_SIZE) {
2773
0
        return false;
2774
0
    }
2775
2776
223
    return send_gc_lossless_packet_all_peers(chat, packet, (uint16_t)packet_len, GP_SHARED_STATE);
2777
223
}
2778
2779
/** @brief Helper function for `do_gc_shared_state_changes()`.
2780
 *
2781
 * If the privacy state has been set to private, we kill our group's connection to the DHT.
2782
 * Otherwise, we create a new connection with the DHT and flag an announcement.
2783
 */
2784
static void do_privacy_state_change(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat, void *_Nullable userdata)
2785
92
{
2786
92
    if (is_public_chat(chat)) {
2787
1
        if (!m_create_group_connection(c->messenger, chat)) {
2788
0
            LOGGER_ERROR(chat->log, "Failed to initialize group friend connection");
2789
1
        } else {
2790
1
            chat->update_self_announces = true;
2791
1
            chat->join_type = HJ_PUBLIC;
2792
1
        }
2793
91
    } else {
2794
91
        kill_group_friend_connection(c, chat);
2795
91
        cleanup_gca(c->announces_list, get_chat_id(&chat->chat_public_key));
2796
91
        chat->join_type = HJ_PRIVATE;
2797
91
    }
2798
2799
92
    if (c->privacy_state != nullptr) {
2800
92
        c->privacy_state(c->messenger, chat->group_number, chat->shared_state.privacy_state, userdata);
2801
92
    }
2802
92
}
2803
2804
/**
2805
 * Compares old_shared_state with the chat instance's current shared state and triggers the
2806
 * appropriate callbacks depending on what pieces of state information changed. Also
2807
 * handles DHT announcement/removal if the privacy state changed.
2808
 *
2809
 * The initial retrieval of the shared state on group join will be ignored by this function.
2810
 */
2811
static void do_gc_shared_state_changes(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat, const GC_SharedState *_Nonnull old_shared_state,
2812
                                       void *_Nullable userdata)
2813
399
{
2814
    /* Max peers changed */
2815
399
    if (chat->shared_state.maxpeers != old_shared_state->maxpeers && c->peer_limit != nullptr) {
2816
51
        c->peer_limit(c->messenger, chat->group_number, chat->shared_state.maxpeers, userdata);
2817
51
    }
2818
2819
    /* privacy state changed */
2820
399
    if (chat->shared_state.privacy_state != old_shared_state->privacy_state) {
2821
92
        do_privacy_state_change(c, chat, userdata);
2822
92
    }
2823
2824
    /* password changed */
2825
399
    if (chat->shared_state.password_length != old_shared_state->password_length
2826
399
            || memcmp(chat->shared_state.password, old_shared_state->password, old_shared_state->password_length) != 0) {
2827
2828
46
        if (c->password != nullptr) {
2829
46
            c->password(c->messenger, chat->group_number, chat->shared_state.password,
2830
46
                        chat->shared_state.password_length, userdata);
2831
46
        }
2832
46
    }
2833
2834
    /* topic lock state changed */
2835
399
    if (chat->shared_state.topic_lock != old_shared_state->topic_lock && c->topic_lock != nullptr) {
2836
56
        const Group_Topic_Lock lock_state = group_topic_lock_enabled(chat) ? TL_ENABLED : TL_DISABLED;
2837
56
        c->topic_lock(c->messenger, chat->group_number, lock_state, userdata);
2838
56
    }
2839
2840
    /* voice state changed */
2841
399
    if (chat->shared_state.voice_state != old_shared_state->voice_state && c->voice_state != nullptr) {
2842
16
        c->voice_state(c->messenger, chat->group_number, chat->shared_state.voice_state, userdata);
2843
16
    }
2844
399
}
2845
2846
/** @brief Sends a sync request to a random peer in the group with the specificed sync flags.
2847
 *
2848
 * Return true on success.
2849
 */
2850
static bool send_gc_random_sync_request(GC_Chat *_Nonnull chat, uint16_t sync_flags)
2851
0
{
2852
0
    GC_Connection *rand_gconn = random_gc_connection(chat);
2853
2854
0
    if (rand_gconn == nullptr) {
2855
0
        return false;
2856
0
    }
2857
2858
0
    return send_gc_sync_request(chat, rand_gconn, sync_flags);
2859
0
}
2860
2861
/** @brief Returns true if all shared state values are legal. */
2862
static bool validate_gc_shared_state(const GC_SharedState *_Nonnull state)
2863
399
{
2864
399
    return state->maxpeers > 0
2865
399
           && state->password_length <= MAX_GC_PASSWORD_SIZE
2866
399
           && state->group_name_len > 0
2867
399
           && state->group_name_len <= MAX_GC_GROUP_NAME_SIZE
2868
399
           && state->privacy_state <= GI_PRIVATE
2869
399
           && state->voice_state <= GV_FOUNDER;
2870
399
}
2871
2872
/** @brief Handles a shared state error and attempts to send a sync request to a random peer.
2873
 *
2874
 * Return 0 if error is currectly handled.
2875
 * Return -1 on failure.
2876
 */
2877
static int handle_gc_shared_state_error(GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn)
2878
0
{
2879
0
    gcc_mark_for_deletion(gconn, chat->tcp_conn, GC_EXIT_TYPE_SYNC_ERR, nullptr, 0);
2880
2881
0
    if (chat->shared_state.version == 0) {
2882
0
        chat->connection_state = CS_CONNECTING;
2883
0
        return 0;
2884
0
    }
2885
2886
0
    if (chat->numpeers <= 1) {
2887
0
        return 0;
2888
0
    }
2889
2890
0
    if (!send_gc_random_sync_request(chat, GF_STATE)) {
2891
0
        return -1;
2892
0
    }
2893
2894
0
    return 0;
2895
0
}
2896
2897
/** @brief Handles a shared state packet and validates the new shared state.
2898
 *
2899
 * Return 0 if packet is successfully handled.
2900
 * Return -1 if packet is invalid and this is not successfully handled.
2901
 */
2902
static int handle_gc_shared_state(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn, const uint8_t *_Nonnull data,
2903
                                  uint16_t length, void *_Nullable userdata)
2904
400
{
2905
400
    if (length < GC_SHARED_STATE_ENC_PACKET_SIZE) {
2906
0
        return handle_gc_shared_state_error(chat, gconn);
2907
0
    }
2908
2909
400
    const uint8_t *signature = data;
2910
400
    const uint8_t *ss_data = data + SIGNATURE_SIZE;
2911
400
    const uint16_t ss_length = length - SIGNATURE_SIZE;
2912
2913
400
    if (crypto_sign_verify_detached(signature, ss_data, GC_PACKED_SHARED_STATE_SIZE,
2914
400
                                    get_sig_pk(&chat->chat_public_key)) == -1) {
2915
0
        LOGGER_DEBUG(chat->log, "Failed to validate shared state signature");
2916
0
        return handle_gc_shared_state_error(chat, gconn);
2917
0
    }
2918
2919
400
    uint32_t version;
2920
400
    net_unpack_u32(ss_data, &version);  // version is the first 4 bytes of shared state data payload
2921
2922
400
    if (version == 0 || version < chat->shared_state.version) {
2923
1
        LOGGER_DEBUG(chat->log, "Invalid shared state version (got %u, expected >= %u)",
2924
1
                     version, chat->shared_state.version);
2925
1
        return 0;
2926
1
    }
2927
2928
399
    const GC_SharedState old_shared_state = chat->shared_state;
2929
399
    GC_SharedState new_shared_state;
2930
2931
399
    if (unpack_gc_shared_state(&new_shared_state, ss_data, ss_length) == 0) {
2932
0
        LOGGER_WARNING(chat->log, "Failed to unpack shared state");
2933
0
        return 0;
2934
0
    }
2935
2936
399
    if (!validate_gc_shared_state(&new_shared_state)) {
2937
0
        LOGGER_WARNING(chat->log, "Failed to validate shared state");
2938
0
        return 0;
2939
0
    }
2940
2941
399
    if (chat->shared_state.version == 0) {  // init founder public sig key in moderation object
2942
105
        memcpy(chat->moderation.founder_public_sig_key,
2943
105
               get_sig_pk(&new_shared_state.founder_public_key), SIG_PUBLIC_KEY_SIZE);
2944
105
    }
2945
2946
399
    chat->shared_state = new_shared_state;
2947
2948
399
    memcpy(chat->shared_state_sig, signature, sizeof(chat->shared_state_sig));
2949
2950
399
    set_gc_shared_state_version(chat, chat->shared_state.version);
2951
2952
399
    do_gc_shared_state_changes(c, chat, &old_shared_state, userdata);
2953
2954
399
    return 0;
2955
399
}
2956
2957
/** @brief Validates `data` containing a moderation list and unpacks it into the
2958
 * shared state of `chat`.
2959
 *
2960
 * Return 1 if data is valid but mod list doesn't match shared state.
2961
 * Return 0 if data is valid.
2962
 * Return -1 if data is invalid.
2963
 */
2964
static int validate_unpack_mod_list(GC_Chat *_Nonnull chat, const uint8_t *_Nonnull data, uint16_t length, uint16_t num_mods)
2965
170
{
2966
170
    if (num_mods > MOD_MAX_NUM_MODERATORS) {
2967
0
        return -1;
2968
0
    }
2969
2970
170
    uint8_t mod_list_hash[MOD_MODERATION_HASH_SIZE] = {0};
2971
2972
170
    if (length > 0) {
2973
5
        mod_list_get_data_hash(mod_list_hash, data, length);
2974
5
    }
2975
2976
    // we make sure that this mod list's hash matches the one we got in our last shared state update
2977
170
    if (chat->shared_state.version > 0
2978
170
            && memcmp(mod_list_hash, chat->shared_state.mod_list_hash, MOD_MODERATION_HASH_SIZE) != 0) {
2979
0
        LOGGER_WARNING(chat->log, "failed to validate mod list hash");
2980
0
        return 1;
2981
0
    }
2982
2983
170
    if (mod_list_unpack(&chat->moderation, data, length, num_mods) == -1) {
2984
0
        LOGGER_WARNING(chat->log, "failed to unpack mod list");
2985
0
        return -1;
2986
0
    }
2987
2988
170
    return 0;
2989
170
}
2990
2991
/** @brief Handles new mod_list and compares its hash against the mod_list_hash in the shared state.
2992
 *
2993
 * If the new list fails validation, we attempt to send a sync request to a random peer.
2994
 *
2995
 * Return 0 if packet is handled correctly.
2996
 * Return -1 if packet has invalid size.
2997
 * Return -2 if packet contained invalid data or validation failed.
2998
 */
2999
static int handle_gc_mod_list(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat, const uint8_t *_Nonnull data, uint16_t length, void *_Nullable userdata)
3000
189
{
3001
189
    if (length < sizeof(uint16_t)) {
3002
0
        return -1;
3003
0
    }
3004
3005
    // only the founder can modify the list; the founder can never be out of sync
3006
189
    if (self_gc_is_founder(chat)) {
3007
19
        return 0;
3008
19
    }
3009
3010
170
    uint16_t num_mods;
3011
170
    net_unpack_u16(data, &num_mods);
3012
3013
170
    const int unpack_ret = validate_unpack_mod_list(chat, data + sizeof(uint16_t), length - sizeof(uint16_t), num_mods);
3014
3015
170
    if (unpack_ret == 0) {
3016
170
        update_gc_peer_roles(chat);
3017
3018
170
        if (chat->connection_state == CS_CONNECTED && c->moderation != nullptr) {
3019
68
            c->moderation(c->messenger, chat->group_number, gc_invalid_peer_id(), gc_invalid_peer_id(), MV_MOD, userdata);
3020
68
        }
3021
3022
170
        return 0;
3023
170
    }
3024
3025
0
    if (unpack_ret == 1) {
3026
0
        return 0;
3027
0
    }
3028
3029
    // unpack/validation failed: handle error
3030
3031
0
    if (chat->shared_state.version == 0) {
3032
0
        chat->connection_state = CS_CONNECTING;
3033
0
        return -2;
3034
0
    }
3035
3036
0
    if (chat->numpeers <= 1) {
3037
0
        return 0;
3038
0
    }
3039
3040
0
    send_gc_random_sync_request(chat, GF_STATE);
3041
3042
0
    return 0;
3043
0
}
3044
3045
/** @brief Handles a sanctions list validation error and attempts to send a sync request to a random peer.
3046
 *
3047
 * Return 0 on success.
3048
 * Return -1 on failure.
3049
 */
3050
static int handle_gc_sanctions_list_error(GC_Chat *_Nonnull chat)
3051
0
{
3052
0
    if (chat->moderation.sanctions_creds.version > 0) {
3053
0
        return 0;
3054
0
    }
3055
3056
0
    if (chat->shared_state.version == 0) {
3057
0
        chat->connection_state = CS_CONNECTING;
3058
0
        return 0;
3059
0
    }
3060
3061
0
    if (chat->numpeers <= 1) {
3062
0
        return 0;
3063
0
    }
3064
3065
0
    if (!send_gc_random_sync_request(chat, GF_STATE)) {
3066
0
        return -1;
3067
0
    }
3068
3069
0
    return 0;
3070
0
}
3071
3072
/** @brief Handles a sanctions list packet.
3073
 *
3074
 * Return 0 if packet is handled correctly.
3075
 * Return -1 if we failed to gracefully handle a sanctions list error.
3076
 * Return -2 if packet has invalid size.
3077
 */
3078
static int handle_gc_sanctions_list(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat, const uint8_t *_Nonnull data, uint16_t length,
3079
                                    void *_Nullable userdata)
3080
189
{
3081
189
    if (length < sizeof(uint16_t)) {
3082
0
        return -2;
3083
0
    }
3084
3085
189
    uint16_t num_sanctions;
3086
189
    net_unpack_u16(data, &num_sanctions);
3087
3088
189
    if (num_sanctions > MOD_MAX_NUM_SANCTIONS) {
3089
0
        LOGGER_DEBUG(chat->log, "num_sanctions: %u exceeds maximum", num_sanctions);
3090
0
        return handle_gc_sanctions_list_error(chat);
3091
0
    }
3092
3093
189
    Mod_Sanction_Creds creds;
3094
3095
189
    Mod_Sanction *sanctions = (Mod_Sanction *)mem_valloc(chat->mem, num_sanctions, sizeof(Mod_Sanction));
3096
3097
189
    if (sanctions == nullptr) {
3098
0
        return -1;
3099
0
    }
3100
3101
189
    const int unpacked_num = sanctions_list_unpack(sanctions, &creds, num_sanctions, data + sizeof(uint16_t),
3102
189
                             length - sizeof(uint16_t), nullptr);
3103
3104
189
    if (unpacked_num != num_sanctions) {
3105
0
        LOGGER_WARNING(chat->log, "Failed to unpack sanctions list: %d", unpacked_num);
3106
0
        mem_delete(chat->mem, sanctions);
3107
0
        return handle_gc_sanctions_list_error(chat);
3108
0
    }
3109
3110
189
    if (!sanctions_list_check_integrity(&chat->moderation, &creds, sanctions, num_sanctions)) {
3111
0
        LOGGER_WARNING(chat->log, "Sanctions list failed integrity check");
3112
0
        mem_delete(chat->mem, sanctions);
3113
0
        return handle_gc_sanctions_list_error(chat);
3114
0
    }
3115
3116
189
    if (creds.version < chat->moderation.sanctions_creds.version) {
3117
0
        mem_delete(chat->mem, sanctions);
3118
0
        return 0;
3119
0
    }
3120
3121
    // this may occur if two mods change the sanctions list at the exact same time
3122
189
    if (creds.version == chat->moderation.sanctions_creds.version
3123
189
            && creds.checksum <= chat->moderation.sanctions_creds.checksum) {
3124
86
        mem_delete(chat->mem, sanctions);
3125
86
        return 0;
3126
86
    }
3127
3128
103
    sanctions_list_cleanup(&chat->moderation);
3129
3130
103
    chat->moderation.sanctions_creds = creds;
3131
103
    chat->moderation.sanctions = sanctions;
3132
103
    chat->moderation.num_sanctions = num_sanctions;
3133
3134
103
    update_gc_peer_roles(chat);
3135
3136
103
    if (chat->connection_state == CS_CONNECTED) {
3137
1
        if (c->moderation != nullptr) {
3138
1
            c->moderation(c->messenger, chat->group_number, gc_invalid_peer_id(), gc_invalid_peer_id(), MV_OBSERVER, userdata);
3139
1
        }
3140
1
    }
3141
3142
103
    return 0;
3143
189
}
3144
3145
/** @brief Makes a mod_list packet.
3146
 *
3147
 * Returns length of packet data on success.
3148
 * Returns -1 on failure.
3149
 */
3150
static int make_gc_mod_list_packet(const GC_Chat *_Nonnull chat, uint8_t *_Nonnull data, uint32_t maxlen, uint16_t mod_list_size)
3151
191
{
3152
191
    if (maxlen < sizeof(uint16_t) + mod_list_size) {
3153
0
        return -1;
3154
0
    }
3155
3156
191
    net_pack_u16(data, chat->moderation.num_mods);
3157
191
    const uint16_t length = sizeof(uint16_t) + mod_list_size;
3158
3159
191
    if (mod_list_size > 0) {
3160
6
        uint8_t *packed_mod_list = (uint8_t *)mem_balloc(chat->mem, mod_list_size);
3161
3162
6
        if (packed_mod_list == nullptr) {
3163
0
            return -1;
3164
0
        }
3165
3166
6
        mod_list_pack(&chat->moderation, packed_mod_list);
3167
6
        memcpy(data + sizeof(uint16_t), packed_mod_list, mod_list_size);
3168
3169
6
        mem_delete(chat->mem, packed_mod_list);
3170
6
    }
3171
3172
191
    return length;
3173
191
}
3174
3175
/** @brief Sends the moderator list to peer.
3176
 *
3177
 * Return true on success.
3178
 */
3179
static bool send_peer_mod_list(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn)
3180
192
{
3181
192
    const uint16_t mod_list_size = chat->moderation.num_mods * MOD_LIST_ENTRY_SIZE;
3182
192
    const uint16_t length = sizeof(uint16_t) + mod_list_size;
3183
192
    uint8_t *packet = (uint8_t *)mem_balloc(chat->mem, length);
3184
3185
192
    if (packet == nullptr) {
3186
1
        return false;
3187
1
    }
3188
3189
191
    const int packet_len = make_gc_mod_list_packet(chat, packet, length, mod_list_size);
3190
3191
191
    if (packet_len != length) {
3192
0
        mem_delete(chat->mem, packet);
3193
0
        return false;
3194
0
    }
3195
3196
191
    const bool ret = send_lossless_group_packet(chat, gconn, packet, length, GP_MOD_LIST);
3197
3198
191
    mem_delete(chat->mem, packet);
3199
3200
191
    return ret;
3201
191
}
3202
3203
/** @brief Makes a sanctions list packet.
3204
 *
3205
 * Returns packet length on success.
3206
 * Returns -1 on failure.
3207
 */
3208
static int make_gc_sanctions_list_packet(const GC_Chat *_Nonnull chat, uint8_t *_Nonnull data, uint16_t maxlen)
3209
189
{
3210
189
    if (maxlen < sizeof(uint16_t)) {
3211
0
        return -1;
3212
0
    }
3213
3214
189
    net_pack_u16(data, chat->moderation.num_sanctions);
3215
189
    const uint16_t length = sizeof(uint16_t);
3216
3217
189
    const int packed_len = sanctions_list_pack(data + length, maxlen - length, chat->moderation.sanctions,
3218
189
                           chat->moderation.num_sanctions, &chat->moderation.sanctions_creds);
3219
3220
189
    if (packed_len < 0) {
3221
0
        return -1;
3222
0
    }
3223
3224
189
    return length + packed_len;
3225
189
}
3226
3227
/** @brief Sends the sanctions list to peer.
3228
 *
3229
 * Returns true on success.
3230
 */
3231
static bool send_peer_sanctions_list(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn)
3232
189
{
3233
189
    if (chat->moderation.sanctions_creds.version == 0) {
3234
0
        return true;
3235
0
    }
3236
3237
189
    const uint16_t packet_size = MOD_SANCTION_PACKED_SIZE * chat->moderation.num_sanctions +
3238
189
                                 sizeof(uint16_t) + MOD_SANCTIONS_CREDS_SIZE;
3239
3240
189
    uint8_t *packet = (uint8_t *)mem_balloc(chat->mem, packet_size);
3241
3242
189
    if (packet == nullptr) {
3243
0
        return false;
3244
0
    }
3245
3246
189
    const int packet_len = make_gc_sanctions_list_packet(chat, packet, packet_size);
3247
3248
189
    if (packet_len == -1) {
3249
0
        mem_delete(chat->mem, packet);
3250
0
        return false;
3251
0
    }
3252
3253
189
    const bool ret = send_lossless_group_packet(chat, gconn, packet, (uint16_t)packet_len, GP_SANCTIONS_LIST);
3254
3255
189
    mem_delete(chat->mem, packet);
3256
3257
189
    return ret;
3258
189
}
3259
3260
/** @brief Sends the sanctions list to all peers in group.
3261
 *
3262
 * Returns true on success.
3263
 */
3264
static bool broadcast_gc_sanctions_list(const GC_Chat *_Nonnull chat)
3265
0
{
3266
0
    const uint16_t packet_size = MOD_SANCTION_PACKED_SIZE * chat->moderation.num_sanctions +
3267
0
                                 sizeof(uint16_t) + MOD_SANCTIONS_CREDS_SIZE;
3268
3269
0
    uint8_t *packet = (uint8_t *)mem_balloc(chat->mem, packet_size);
3270
3271
0
    if (packet == nullptr) {
3272
0
        return false;
3273
0
    }
3274
3275
0
    const int packet_len = make_gc_sanctions_list_packet(chat, packet, packet_size);
3276
3277
0
    if (packet_len == -1) {
3278
0
        mem_delete(chat->mem, packet);
3279
0
        return false;
3280
0
    }
3281
3282
0
    const bool ret = send_gc_lossless_packet_all_peers(chat, packet, (uint16_t)packet_len, GP_SANCTIONS_LIST);
3283
3284
0
    mem_delete(chat->mem, packet);
3285
3286
0
    return ret;
3287
0
}
3288
3289
/** @brief Re-signs all sanctions list entries signed by public_sig_key and broadcasts
3290
 * the updated sanctions list to all group peers.
3291
 *
3292
 * Returns true on success.
3293
 */
3294
static bool update_gc_sanctions_list(GC_Chat *_Nonnull chat, const uint8_t *_Nonnull public_sig_key)
3295
4
{
3296
4
    const uint16_t num_replaced = sanctions_list_replace_sig(&chat->moderation, public_sig_key);
3297
3298
4
    if (num_replaced == 0) {
3299
4
        return true;
3300
4
    }
3301
3302
0
    return broadcast_gc_sanctions_list(chat);
3303
4
}
3304
3305
/** @brief Sends mod_list to all peers in group.
3306
 *
3307
 * Returns true on success.
3308
 */
3309
static bool broadcast_gc_mod_list(const GC_Chat *_Nonnull chat)
3310
0
{
3311
0
    const uint16_t mod_list_size = chat->moderation.num_mods * MOD_LIST_ENTRY_SIZE;
3312
0
    const uint16_t length = sizeof(uint16_t) + mod_list_size;
3313
0
    uint8_t *packet = (uint8_t *)mem_balloc(chat->mem, length);
3314
3315
0
    if (packet == nullptr) {
3316
0
        return false;
3317
0
    }
3318
3319
0
    const int packet_len = make_gc_mod_list_packet(chat, packet, length, mod_list_size);
3320
3321
0
    if (packet_len != length) {
3322
0
        mem_delete(chat->mem, packet);
3323
0
        return false;
3324
0
    }
3325
3326
0
    const bool ret = send_gc_lossless_packet_all_peers(chat, packet, length, GP_MOD_LIST);
3327
3328
0
    mem_delete(chat->mem, packet);
3329
3330
0
    return ret;
3331
0
}
3332
3333
/** @brief Sends a parting signal to the group.
3334
 *
3335
 * Returns 0 on success.
3336
 * Returns -1 if the message is too long.
3337
 * Returns -2 if the packet failed to send.
3338
 */
3339
static int send_gc_self_exit(const GC_Chat *_Nonnull chat, const uint8_t *_Nullable partmessage, uint16_t length)
3340
4.43k
{
3341
4.43k
    if (length > MAX_GC_PART_MESSAGE_SIZE) {
3342
0
        return -1;
3343
0
    }
3344
3345
4.43k
    if (!send_gc_broadcast_message(chat, partmessage, length, GM_PEER_EXIT)) {
3346
14
        return -2;
3347
14
    }
3348
3349
4.42k
    return 0;
3350
4.43k
}
3351
3352
/** @brief Handles a peer exit broadcast. */
3353
static void handle_gc_peer_exit(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn, const uint8_t *_Nullable data, uint16_t length)
3354
16
{
3355
16
    if (length > MAX_GC_PART_MESSAGE_SIZE) {
3356
0
        length = MAX_GC_PART_MESSAGE_SIZE;
3357
0
    }
3358
3359
16
    gcc_mark_for_deletion(gconn, chat->tcp_conn, GC_EXIT_TYPE_QUIT, data, length);
3360
16
}
3361
3362
int gc_set_self_nick(const Messenger *m, int group_number, const uint8_t *nick, uint16_t length)
3363
55
{
3364
55
    const GC_Session *c = m->group_handler;
3365
55
    const GC_Chat *chat = gc_get_group(c, group_number);
3366
3367
55
    if (chat == nullptr) {
3368
0
        return -1;
3369
0
    }
3370
3371
55
    if (length > MAX_GC_NICK_SIZE) {
3372
0
        return -2;
3373
0
    }
3374
3375
55
    if (length == 0 || nick == nullptr) {
3376
0
        return -3;
3377
0
    }
3378
3379
55
    if (!self_gc_set_nick(chat, nick, length)) {
3380
0
        return -2;
3381
0
    }
3382
3383
55
    if (!send_gc_broadcast_message(chat, nick, length, GM_NICK)) {
3384
6
        return -4;
3385
6
    }
3386
3387
49
    return 0;
3388
55
}
3389
3390
bool gc_get_peer_nick(const GC_Chat *chat, GC_Peer_Id peer_id, uint8_t *name)
3391
65
{
3392
65
    const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
3393
3394
65
    const GC_Peer *peer = get_gc_peer(chat, peer_number);
3395
3396
65
    if (peer == nullptr) {
3397
0
        return false;
3398
0
    }
3399
3400
65
    if (name != nullptr) {
3401
65
        memcpy(name, peer->nick, peer->nick_length);
3402
65
    }
3403
3404
65
    return true;
3405
65
}
3406
3407
int gc_get_peer_nick_size(const GC_Chat *chat, GC_Peer_Id peer_id)
3408
76
{
3409
76
    const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
3410
3411
76
    const GC_Peer *peer = get_gc_peer(chat, peer_number);
3412
3413
76
    if (peer == nullptr) {
3414
11
        return -1;
3415
11
    }
3416
3417
65
    return peer->nick_length;
3418
76
}
3419
3420
/** @brief Handles a nick change broadcast.
3421
 *
3422
 * Return 0 if packet is handled correctly.
3423
 * Return -1 on failure.
3424
 */
3425
static int handle_gc_nick(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat, GC_Peer *_Nonnull peer, const uint8_t *_Nonnull nick,
3426
                          uint16_t length, void *_Nullable userdata)
3427
41
{
3428
    /* If this happens malicious behaviour is highly suspect */
3429
41
    if (length == 0 || length > MAX_GC_NICK_SIZE) {
3430
0
        GC_Connection *gconn = &peer->gconn;
3431
0
        gcc_mark_for_deletion(gconn, chat->tcp_conn, GC_EXIT_TYPE_SYNC_ERR, nullptr, 0);
3432
0
        LOGGER_WARNING(chat->log, "Invalid nick length for nick: %s (%u)", nick, length);
3433
0
        return -1;
3434
0
    }
3435
3436
41
    memcpy(peer->nick, nick, length);
3437
41
    peer->nick_length = length;
3438
3439
41
    if (c->nick_change != nullptr) {
3440
41
        c->nick_change(c->messenger, chat->group_number, peer->peer_id, nick, length, userdata);
3441
41
    }
3442
3443
41
    return 0;
3444
41
}
3445
3446
/** @brief Copies peer_number's public key to `public_key`.
3447
 *
3448
 * Returns 0 on success.
3449
 * Returns -1 if peer_number is invalid.
3450
 * Returns -2 if `public_key` is null.
3451
 */
3452
static int get_gc_peer_public_key(const GC_Chat *_Nonnull chat, uint32_t peer_number, uint8_t *_Nonnull public_key)
3453
112
{
3454
112
    const GC_Connection *gconn = get_gc_connection(chat, peer_number);
3455
3456
112
    if (gconn == nullptr) {
3457
0
        return -1;
3458
0
    }
3459
3460
112
    if (public_key == nullptr) {
3461
0
        return -2;
3462
0
    }
3463
3464
112
    memcpy(public_key, gconn->addr.public_key.enc, ENC_PUBLIC_KEY_SIZE);
3465
3466
112
    return 0;
3467
112
}
3468
3469
int gc_get_peer_public_key_by_peer_id(const GC_Chat *chat, GC_Peer_Id peer_id, uint8_t *public_key)
3470
1
{
3471
1
    const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
3472
3473
1
    const GC_Connection *gconn = get_gc_connection(chat, peer_number);
3474
3475
1
    if (gconn == nullptr) {
3476
0
        return -1;
3477
0
    }
3478
3479
1
    if (public_key == nullptr) {
3480
0
        return -2;
3481
0
    }
3482
3483
1
    memcpy(public_key, gconn->addr.public_key.enc, ENC_PUBLIC_KEY_SIZE);
3484
3485
1
    return 0;
3486
1
}
3487
3488
/** @brief Puts a string of the IP associated with `ip_port` in `ip_str` if the
3489
 * connection is direct, otherwise puts a placeholder in the buffer indicating that
3490
 * the IP cannot be displayed.
3491
 */
3492
static void get_gc_ip_ntoa(const IP_Port *_Nonnull ip_port, Ip_Ntoa *_Nonnull ip_str)
3493
12
{
3494
12
    net_ip_ntoa(&ip_port->ip, ip_str);
3495
3496
12
    if (!ip_str->ip_is_valid) {
3497
0
        ip_str->buf[0] = '-';
3498
0
        ip_str->buf[1] = '\0';
3499
0
        ip_str->length = 1;
3500
0
    }
3501
12
}
3502
3503
int gc_get_peer_ip_address_size(const GC_Chat *chat, GC_Peer_Id peer_id)
3504
6
{
3505
6
    const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
3506
6
    const GC_Connection *gconn = get_gc_connection(chat, peer_number);
3507
3508
6
    if (gconn == nullptr) {
3509
0
        return -1;
3510
0
    }
3511
3512
6
    const IP_Port *ip_port = peer_number == 0 ? &chat->self_ip_port : &gconn->addr.ip_port;
3513
3514
6
    Ip_Ntoa ip_str;
3515
6
    get_gc_ip_ntoa(ip_port, &ip_str);
3516
3517
6
    return ip_str.length;
3518
6
}
3519
3520
int gc_get_peer_ip_address(const GC_Chat *chat, GC_Peer_Id peer_id, uint8_t *ip_addr)
3521
6
{
3522
6
    const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
3523
6
    const GC_Connection *gconn = get_gc_connection(chat, peer_number);
3524
3525
6
    if (gconn == nullptr) {
3526
0
        return -1;
3527
0
    }
3528
3529
6
    if (ip_addr == nullptr) {
3530
0
        return -2;
3531
0
    }
3532
3533
6
    const IP_Port *ip_port = peer_number == 0 ? &chat->self_ip_port : &gconn->addr.ip_port;
3534
3535
6
    Ip_Ntoa ip_str;
3536
6
    get_gc_ip_ntoa(ip_port, &ip_str);
3537
3538
6
    assert(ip_str.length <= IP_NTOA_LEN);
3539
6
    memcpy(ip_addr, ip_str.buf, ip_str.length);
3540
3541
6
    return 0;
3542
6
}
3543
3544
unsigned int gc_get_peer_connection_status(const GC_Chat *chat, GC_Peer_Id peer_id)
3545
4
{
3546
4
    const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
3547
3548
4
    if (peer_number_is_self(peer_number)) {
3549
0
        return chat->self_udp_status ==  SELF_UDP_STATUS_NONE ? 1 : 2;
3550
0
    }
3551
3552
4
    const GC_Connection *gconn = get_gc_connection(chat, peer_number);
3553
3554
4
    if (gconn == nullptr) {
3555
0
        return 0;
3556
0
    }
3557
3558
4
    if (gcc_conn_is_direct(chat->mono_time, gconn)) {
3559
4
        return 2;
3560
4
    }
3561
3562
0
    return 1;
3563
4
}
3564
3565
/** @brief Creates a topic packet and puts it in data.
3566
 *
3567
 * Packet includes the topic, topic length, public signature key of the
3568
 * setter, topic version, and the signature.
3569
 *
3570
 * Returns packet length on success.
3571
 * Returns -1 on failure.
3572
 */
3573
static int make_gc_topic_packet(const GC_Chat *_Nonnull chat, uint8_t *_Nonnull data, uint16_t length)
3574
628
{
3575
628
    if (length < SIGNATURE_SIZE + chat->topic_info.length + GC_MIN_PACKED_TOPIC_INFO_SIZE) {
3576
0
        return -1;
3577
0
    }
3578
3579
628
    memcpy(data, chat->topic_sig, SIGNATURE_SIZE);
3580
628
    uint16_t data_length = SIGNATURE_SIZE;
3581
3582
628
    const uint16_t packed_len = pack_gc_topic_info(data + data_length, length - data_length, &chat->topic_info);
3583
628
    data_length += packed_len;
3584
3585
628
    if (packed_len != chat->topic_info.length + GC_MIN_PACKED_TOPIC_INFO_SIZE) {
3586
0
        return -1;
3587
0
    }
3588
3589
628
    return data_length;
3590
628
}
3591
3592
/** @brief Sends the group topic to peer.
3593
 *
3594
 * Returns true on success.
3595
 */
3596
static bool send_peer_topic(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn)
3597
131
{
3598
131
    const uint16_t packet_buf_size = SIGNATURE_SIZE + chat->topic_info.length + GC_MIN_PACKED_TOPIC_INFO_SIZE;
3599
131
    uint8_t *packet = (uint8_t *)mem_balloc(chat->mem, packet_buf_size);
3600
3601
131
    if (packet == nullptr) {
3602
0
        return false;
3603
0
    }
3604
3605
131
    const int packet_len = make_gc_topic_packet(chat, packet, packet_buf_size);
3606
3607
131
    if (packet_len != packet_buf_size) {
3608
0
        mem_delete(chat->mem, packet);
3609
0
        return false;
3610
0
    }
3611
3612
131
    if (!send_lossless_group_packet(chat, gconn, packet, packet_buf_size, GP_TOPIC)) {
3613
0
        mem_delete(chat->mem, packet);
3614
0
        return false;
3615
0
    }
3616
3617
131
    mem_delete(chat->mem, packet);
3618
3619
131
    return true;
3620
131
}
3621
3622
/**
3623
 * @brief Initiates a session key rotation with peer designated by `gconn`.
3624
 *
3625
 * Return true on success.
3626
 */
3627
static bool send_peer_key_rotation_request(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn)
3628
0
{
3629
    // Only the peer closest to the chat_id sends requests. This is to prevent both peers from sending
3630
    // requests at the same time and ending up with a different resulting shared key
3631
0
    if (!gconn->self_is_closer) {
3632
        // if this peer hasn't sent us a rotation request in a reasonable timeframe we drop their connection
3633
0
        if (mono_time_is_timeout(chat->mono_time, gconn->last_key_rotation, GC_KEY_ROTATION_TIMEOUT + GC_PING_TIMEOUT)) {
3634
0
            gcc_mark_for_deletion(gconn, chat->tcp_conn, GC_EXIT_TYPE_TIMEOUT, nullptr, 0);
3635
0
        }
3636
3637
0
        return true;
3638
0
    }
3639
3640
0
    uint8_t packet[1 + ENC_PUBLIC_KEY_SIZE];
3641
3642
0
    net_pack_bool(&packet[0], false); // request type
3643
3644
0
    create_gc_session_keypair(chat->log, chat->rng, gconn->session_public_key, gconn->session_secret_key);
3645
3646
    // copy new session public key to packet
3647
0
    memcpy(packet + 1, gconn->session_public_key, ENC_PUBLIC_KEY_SIZE);
3648
3649
0
    if (!send_lossless_group_packet(chat, gconn, packet, sizeof(packet), GP_KEY_ROTATION)) {
3650
0
        return false;
3651
0
    }
3652
3653
0
    gconn->pending_key_rotation_request = true;
3654
3655
0
    return true;
3656
0
}
3657
3658
/** @brief Sends the group topic to all group members.
3659
 *
3660
 * Returns true on success.
3661
 */
3662
static bool broadcast_gc_topic(const GC_Chat *_Nonnull chat)
3663
499
{
3664
499
    const uint16_t packet_buf_size = SIGNATURE_SIZE + chat->topic_info.length + GC_MIN_PACKED_TOPIC_INFO_SIZE;
3665
499
    uint8_t *packet = (uint8_t *)mem_balloc(chat->mem, packet_buf_size);
3666
3667
499
    if (packet == nullptr) {
3668
2
        return false;
3669
2
    }
3670
3671
497
    const int packet_len = make_gc_topic_packet(chat, packet, packet_buf_size);
3672
3673
497
    if (packet_len != packet_buf_size) {
3674
0
        mem_delete(chat->mem, packet);
3675
0
        return false;
3676
0
    }
3677
3678
497
    const bool ret = send_gc_lossless_packet_all_peers(chat, packet, packet_buf_size, GP_TOPIC);
3679
3680
497
    mem_delete(chat->mem, packet);
3681
3682
497
    return ret;
3683
497
}
3684
3685
int gc_set_topic(GC_Chat *chat, const uint8_t *topic, uint16_t length)
3686
577
{
3687
577
    if (length > MAX_GC_TOPIC_SIZE) {
3688
0
        return -1;
3689
0
    }
3690
3691
577
    const bool topic_lock_enabled = group_topic_lock_enabled(chat);
3692
3693
577
    if (topic_lock_enabled && gc_get_self_role(chat) > GR_MODERATOR) {
3694
75
        return -2;
3695
75
    }
3696
3697
502
    if (gc_get_self_role(chat) > GR_USER) {
3698
1
        return -2;
3699
1
    }
3700
3701
501
    const GC_TopicInfo old_topic_info = chat->topic_info;
3702
3703
501
    uint8_t old_topic_sig[SIGNATURE_SIZE];
3704
501
    memcpy(old_topic_sig, chat->topic_sig, SIGNATURE_SIZE);
3705
3706
    // TODO(jfreegman): improbable, but an overflow would break topic setting
3707
501
    if (chat->topic_info.version == UINT32_MAX) {
3708
0
        return -3;
3709
0
    }
3710
3711
    // only increment topic version when lock is enabled
3712
501
    if (topic_lock_enabled) {
3713
198
        ++chat->topic_info.version;
3714
198
    }
3715
3716
501
    chat->topic_info.length = length;
3717
3718
501
    if (length > 0) {
3719
389
        assert(topic != nullptr);
3720
389
        memcpy(chat->topic_info.topic, topic, length);
3721
389
    } else {
3722
112
        memzero(chat->topic_info.topic, sizeof(chat->topic_info.topic));
3723
112
    }
3724
3725
501
    memcpy(chat->topic_info.public_sig_key, get_sig_pk(&chat->self_public_key), SIG_PUBLIC_KEY_SIZE);
3726
3727
501
    chat->topic_info.checksum = get_gc_topic_checksum(&chat->topic_info);
3728
3729
501
    const uint16_t packet_buf_size = length + GC_MIN_PACKED_TOPIC_INFO_SIZE;
3730
501
    uint8_t *packed_topic = (uint8_t *)mem_balloc(chat->mem, packet_buf_size);
3731
3732
501
    if (packed_topic == nullptr) {
3733
2
        return -3;
3734
2
    }
3735
3736
499
    int err = -3;
3737
3738
499
    const uint16_t packed_len = pack_gc_topic_info(packed_topic, packet_buf_size, &chat->topic_info);
3739
3740
499
    if (packed_len != packet_buf_size) {
3741
0
        goto ON_ERROR;
3742
0
    }
3743
3744
499
    if (crypto_sign_detached(chat->topic_sig, nullptr, packed_topic, packet_buf_size,
3745
499
                             get_sig_sk(&chat->self_secret_key)) == -1) {
3746
0
        goto ON_ERROR;
3747
0
    }
3748
3749
499
    if (!broadcast_gc_topic(chat)) {
3750
7
        err = -4;
3751
7
        goto ON_ERROR;
3752
7
    }
3753
3754
492
    chat->topic_prev_checksum = old_topic_info.checksum;
3755
492
    chat->topic_time_set = mono_time_get(chat->mono_time);
3756
3757
492
    mem_delete(chat->mem, packed_topic);
3758
492
    return 0;
3759
3760
7
ON_ERROR:
3761
7
    chat->topic_info = old_topic_info;
3762
7
    memcpy(chat->topic_sig, old_topic_sig, SIGNATURE_SIZE);
3763
7
    mem_delete(chat->mem, packed_topic);
3764
7
    return err;
3765
499
}
3766
3767
void gc_get_topic(const GC_Chat *chat, uint8_t *topic)
3768
486
{
3769
486
    if (topic != nullptr) {
3770
486
        memcpy(topic, chat->topic_info.topic, chat->topic_info.length);
3771
486
    }
3772
486
}
3773
3774
uint16_t gc_get_topic_size(const GC_Chat *chat)
3775
690
{
3776
690
    return chat->topic_info.length;
3777
690
}
3778
3779
/**
3780
 * If public_sig_key is equal to the key of the topic setter, replaces topic credentials
3781
 * and re-broadcasts the updated topic info to the group.
3782
 *
3783
 * Returns true on success
3784
 */
3785
static bool update_gc_topic(GC_Chat *_Nonnull chat, const uint8_t *_Nonnull public_sig_key)
3786
4
{
3787
4
    if (memcmp(public_sig_key, chat->topic_info.public_sig_key, SIG_PUBLIC_KEY_SIZE) != 0) {
3788
4
        return true;
3789
4
    }
3790
3791
0
    LOGGER_TRACE(chat->log, "founder is re-signing topic");
3792
0
    return gc_set_topic(chat, chat->topic_info.topic, chat->topic_info.length) == 0;
3793
4
}
3794
3795
/** @brief Validates `topic_info`.
3796
 *
3797
 * Return true if topic info is valid.
3798
 */
3799
static bool handle_gc_topic_validate(const GC_Chat *_Nonnull chat, const GC_Peer *_Nonnull peer, const GC_TopicInfo *_Nonnull topic_info, bool topic_lock_enabled)
3800
755
{
3801
755
    if (topic_info->checksum != get_gc_topic_checksum(topic_info)) {
3802
0
        LOGGER_WARNING(chat->log, "received invalid topic checksum");
3803
0
        return false;
3804
0
    }
3805
3806
755
    if (topic_lock_enabled) {
3807
260
        if (!mod_list_verify_sig_pk(&chat->moderation, topic_info->public_sig_key)) {
3808
0
            LOGGER_DEBUG(chat->log, "Invalid topic signature (bad credentials)");
3809
0
            return false;
3810
0
        }
3811
3812
260
        if (topic_info->version < chat->topic_info.version) {
3813
0
            return false;
3814
0
        }
3815
495
    } else {
3816
495
        uint8_t public_enc_key[ENC_PUBLIC_KEY_SIZE];
3817
3818
495
        if (gc_get_enc_pk_from_sig_pk(chat, public_enc_key, topic_info->public_sig_key)) {
3819
495
            if (sanctions_list_is_observer(&chat->moderation, public_enc_key)) {
3820
0
                LOGGER_DEBUG(chat->log, "Invalid topic signature (sanctioned peer attempted to change topic)");
3821
0
                return false;
3822
0
            }
3823
495
        }
3824
3825
495
        if (topic_info->version == chat->shared_state.topic_lock) {
3826
            // always accept topic on initial connection
3827
489
            if (!mono_time_is_timeout(chat->mono_time, chat->time_connected, GC_PING_TIMEOUT)) {
3828
220
                return true;
3829
220
            }
3830
3831
269
            if (chat->topic_prev_checksum == topic_info->checksum &&
3832
269
                    !mono_time_is_timeout(chat->mono_time, chat->topic_time_set, GC_CONFIRMED_PEER_TIMEOUT)) {
3833
3
                LOGGER_DEBUG(chat->log, "Topic reversion (probable sync error)");
3834
3
                return false;
3835
3
            }
3836
3837
266
            return true;
3838
269
        }
3839
3840
        // the topic version should never change when the topic lock is disabled except when
3841
        // the founder changes the topic prior to enabling the lock
3842
6
        if (!(peer->role == GR_FOUNDER && topic_info->version == chat->shared_state.topic_lock + 1)) {
3843
0
            LOGGER_ERROR(chat->log, "topic version %u differs from topic lock %u", topic_info->version,
3844
0
                         chat->shared_state.topic_lock);
3845
0
            return false;
3846
0
        }
3847
6
    }
3848
3849
266
    return true;
3850
755
}
3851
3852
/** @brief Handles a topic packet.
3853
 *
3854
 * Return 0 if packet is correctly handled.
3855
 * Return -1 if packet has invalid size.
3856
 */
3857
static int handle_gc_topic(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat, const GC_Peer *_Nonnull peer, const uint8_t *_Nonnull data,
3858
                           uint16_t length, void *_Nullable userdata)
3859
755
{
3860
755
    if (length < SIGNATURE_SIZE + GC_MIN_PACKED_TOPIC_INFO_SIZE) {
3861
0
        return -1;
3862
0
    }
3863
3864
755
    const uint16_t old_checksum = chat->topic_info.checksum;
3865
3866
755
    GC_TopicInfo topic_info;
3867
3868
755
    if (unpack_gc_topic_info(&topic_info, data + SIGNATURE_SIZE, length - SIGNATURE_SIZE) == -1) {
3869
0
        LOGGER_WARNING(chat->log, "failed to unpack topic");
3870
0
        return 0;
3871
0
    }
3872
3873
755
    const uint8_t *signature = data;
3874
3875
755
    if (crypto_sign_verify_detached(signature, data + SIGNATURE_SIZE, length - SIGNATURE_SIZE,
3876
755
                                    topic_info.public_sig_key) == -1) {
3877
0
        LOGGER_WARNING(chat->log, "failed to verify topic signature");
3878
0
        return 0;
3879
0
    }
3880
3881
755
    const bool topic_lock_enabled = group_topic_lock_enabled(chat);
3882
3883
755
    if (!handle_gc_topic_validate(chat, peer, &topic_info, topic_lock_enabled)) {
3884
3
        return 0;
3885
3
    }
3886
3887
    // prevents sync issues from triggering the callback needlessly
3888
752
    const bool skip_callback = chat->topic_info.length == topic_info.length
3889
752
                               && memcmp(chat->topic_info.topic, topic_info.topic, topic_info.length) == 0;
3890
3891
752
    chat->topic_prev_checksum = old_checksum;
3892
752
    chat->topic_time_set = mono_time_get(chat->mono_time);
3893
752
    chat->topic_info = topic_info;
3894
752
    memcpy(chat->topic_sig, signature, SIGNATURE_SIZE);
3895
3896
752
    if (!skip_callback && chat->connection_state == CS_CONNECTED && c->topic_change != nullptr) {
3897
621
        const int setter_peer_number = get_peer_number_of_sig_pk(chat, topic_info.public_sig_key);
3898
621
        const GC_Peer_Id peer_id = setter_peer_number >= 0 ? chat->group[setter_peer_number].peer_id : gc_unknown_peer_id();
3899
3900
621
        c->topic_change(c->messenger, chat->group_number, peer_id, topic_info.topic, topic_info.length, userdata);
3901
621
    }
3902
3903
752
    return 0;
3904
755
}
3905
3906
/** @brief Handles a key exchange packet.
3907
 *
3908
 * Return 0 if packet is handled correctly.
3909
 * Return -1 if length is invalid.
3910
 * Return -2 if we fail to create a new session keypair.
3911
 * Return -3 if response packet fails to send.
3912
 */
3913
static int handle_gc_key_exchange(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn, const uint8_t *_Nonnull data, uint16_t length)
3914
0
{
3915
0
    if (length < 1 + ENC_PUBLIC_KEY_SIZE) {
3916
0
        return -1;
3917
0
    }
3918
3919
0
    bool is_response;
3920
0
    net_unpack_bool(&data[0], &is_response);
3921
3922
0
    const uint8_t *sender_public_session_key = data + 1;
3923
3924
0
    if (is_response) {
3925
0
        if (!gconn->pending_key_rotation_request) {
3926
0
            LOGGER_WARNING(chat->log, "got unsolicited key rotation response from peer %u", gconn->public_key_hash);
3927
0
            return 0;
3928
0
        }
3929
3930
        // now that we have response we can compute our new shared key and begin using it
3931
0
        gcc_make_session_shared_key(gconn, sender_public_session_key);
3932
3933
0
        gconn->pending_key_rotation_request = false;
3934
3935
0
        return 0;
3936
0
    }
3937
3938
    // key generation is pretty cpu intensive so we make sure a peer can't DOS us by spamming requests
3939
0
    if (!mono_time_is_timeout(chat->mono_time, gconn->last_key_rotation, GC_KEY_ROTATION_TIMEOUT / 2)) {
3940
0
        return 0;
3941
0
    }
3942
3943
0
    uint8_t response[1 + ENC_PUBLIC_KEY_SIZE];
3944
0
    uint8_t new_session_pk[ENC_PUBLIC_KEY_SIZE];
3945
0
    uint8_t new_session_sk[ENC_SECRET_KEY_SIZE];
3946
3947
0
    net_pack_bool(&response[0], true);
3948
3949
0
    crypto_memlock(new_session_sk, sizeof(new_session_sk));
3950
3951
0
    create_gc_session_keypair(chat->log, chat->rng, new_session_pk, new_session_sk);
3952
3953
0
    memcpy(response + 1, new_session_pk, ENC_PUBLIC_KEY_SIZE);
3954
3955
0
    if (!send_lossless_group_packet(chat, gconn, response, sizeof(response), GP_KEY_ROTATION)) {
3956
        // Don't really care about zeroing the secret key here, because we failed, but
3957
        // we're doing it anyway for symmetry with the memzero+munlock below, where we
3958
        // really do care about it.
3959
0
        crypto_memzero(new_session_sk, sizeof(new_session_sk));
3960
0
        crypto_memunlock(new_session_sk, sizeof(new_session_sk));
3961
0
        return -3;
3962
0
    }
3963
3964
    // save new keys and compute new shared key AFTER sending response packet with old key
3965
0
    memcpy(gconn->session_public_key, new_session_pk, sizeof(gconn->session_public_key));
3966
0
    memcpy(gconn->session_secret_key, new_session_sk, sizeof(gconn->session_secret_key));
3967
3968
0
    gcc_make_session_shared_key(gconn, sender_public_session_key);
3969
3970
0
    crypto_memzero(new_session_sk, sizeof(new_session_sk));
3971
0
    crypto_memunlock(new_session_sk, sizeof(new_session_sk));
3972
3973
0
    gconn->last_key_rotation = mono_time_get(chat->mono_time);
3974
3975
0
    return 0;
3976
0
}
3977
3978
void gc_get_group_name(const GC_Chat *chat, uint8_t *group_name)
3979
14
{
3980
14
    if (group_name != nullptr) {
3981
14
        memcpy(group_name, chat->shared_state.group_name, chat->shared_state.group_name_len);
3982
14
    }
3983
14
}
3984
3985
uint16_t gc_get_group_name_size(const GC_Chat *chat)
3986
991
{
3987
991
    return chat->shared_state.group_name_len;
3988
991
}
3989
3990
void gc_get_password(const GC_Chat *chat, uint8_t *password)
3991
11
{
3992
11
    if (password != nullptr) {
3993
11
        memcpy(password, chat->shared_state.password, chat->shared_state.password_length);
3994
11
    }
3995
11
}
3996
3997
uint16_t gc_get_password_size(const GC_Chat *chat)
3998
16
{
3999
16
    return chat->shared_state.password_length;
4000
16
}
4001
4002
int gc_founder_set_password(GC_Chat *chat, const uint8_t *password, uint16_t password_length)
4003
68
{
4004
68
    if (!self_gc_is_founder(chat)) {
4005
0
        return -1;
4006
0
    }
4007
4008
68
    const uint16_t oldlen = chat->shared_state.password_length;
4009
68
    uint8_t *oldpasswd = memdup(chat->mem, chat->shared_state.password, oldlen);
4010
4011
68
    if (oldpasswd == nullptr && oldlen > 0) {
4012
0
        return -4;
4013
0
    }
4014
4015
68
    if (!set_gc_password_local(chat, password, password_length)) {
4016
0
        mem_delete(chat->mem, oldpasswd);
4017
0
        return -2;
4018
0
    }
4019
4020
68
    if (!sign_gc_shared_state(chat)) {
4021
0
        set_gc_password_local(chat, oldpasswd, oldlen);
4022
0
        mem_delete(chat->mem, oldpasswd);
4023
0
        return -2;
4024
0
    }
4025
4026
68
    mem_delete(chat->mem, oldpasswd);
4027
4028
68
    if (!broadcast_gc_shared_state(chat)) {
4029
5
        return -3;
4030
5
    }
4031
4032
63
    return 0;
4033
68
}
4034
4035
/** @brief Validates change to moderator list and either adds or removes peer from our moderator list.
4036
 *
4037
 * Return target's peer number on success.
4038
 * Return -1 on packet handle failure.
4039
 * Return -2 if target peer is not online.
4040
 * Return -3 if target peer is not a valid role (probably indicates sync issues).
4041
 * Return -4 on validation failure.
4042
 */
4043
static int validate_unpack_gc_set_mod(GC_Chat *_Nonnull chat, uint32_t peer_number, const uint8_t *_Nonnull data, uint16_t length, bool add_mod)
4044
39
{
4045
39
    int target_peer_number;
4046
39
    uint8_t mod_data[MOD_LIST_ENTRY_SIZE];
4047
4048
39
    if (add_mod) {
4049
24
        if (length < 1 + MOD_LIST_ENTRY_SIZE) {
4050
0
            return -1;
4051
0
        }
4052
4053
24
        memcpy(mod_data, data + 1, MOD_MODERATION_HASH_SIZE);
4054
24
        target_peer_number = get_peer_number_of_sig_pk(chat, mod_data);
4055
4056
24
        if (!gc_peer_number_is_valid(chat, target_peer_number)) {
4057
0
            return -2;
4058
0
        }
4059
4060
24
        const Group_Role target_role = chat->group[target_peer_number].role;
4061
4062
24
        if (target_role != GR_USER) {
4063
0
            return -3;
4064
0
        }
4065
4066
24
        if (!mod_list_add_entry(&chat->moderation, mod_data)) {
4067
0
            return -4;
4068
0
        }
4069
24
    } else {
4070
15
        memcpy(mod_data, data + 1, SIG_PUBLIC_KEY_SIZE);
4071
15
        target_peer_number = get_peer_number_of_sig_pk(chat, mod_data);
4072
4073
15
        if (!gc_peer_number_is_valid(chat, target_peer_number)) {
4074
0
            return -2;
4075
0
        }
4076
4077
15
        const Group_Role target_role = chat->group[target_peer_number].role;
4078
4079
15
        if (target_role != GR_MODERATOR) {
4080
0
            return -3;
4081
0
        }
4082
4083
15
        if (!mod_list_remove_entry(&chat->moderation, mod_data)) {
4084
0
            return -4;
4085
0
        }
4086
15
    }
4087
4088
39
    update_gc_peer_roles(chat);
4089
4090
39
    return target_peer_number;
4091
39
}
4092
4093
/** @brief Handles a moderator set broadcast.
4094
 *
4095
 * Return 0 if packet is handled correctly.
4096
 * Return -1 if packet has invalid size.
4097
 * Return -2 if the packet contains invalid data.
4098
 * Return -3 if `peer_number` does not designate a valid peer.
4099
 */
4100
static int handle_gc_set_mod(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat, uint32_t peer_number, const uint8_t *_Nonnull data,
4101
                             uint16_t length, void *_Nullable userdata)
4102
39
{
4103
39
    if (length < 1 + SIG_PUBLIC_KEY_SIZE) {
4104
0
        return -1;
4105
0
    }
4106
4107
39
    const GC_Peer *setter_peer = get_gc_peer(chat, peer_number);
4108
4109
39
    if (setter_peer == nullptr) {
4110
0
        return -3;
4111
0
    }
4112
4113
39
    if (setter_peer->role != GR_FOUNDER) {
4114
0
        return 0;
4115
0
    }
4116
4117
39
    bool add_mod;
4118
39
    net_unpack_bool(&data[0], &add_mod);
4119
4120
39
    const int target_peer_number = validate_unpack_gc_set_mod(chat, peer_number, data, length, add_mod);
4121
4122
39
    if (target_peer_number == -1) {
4123
0
        return -2;
4124
0
    }
4125
4126
39
    const GC_Peer *target_peer = get_gc_peer(chat, target_peer_number);
4127
4128
39
    if (target_peer == nullptr) {
4129
0
        return 0;
4130
0
    }
4131
4132
39
    if (c->moderation != nullptr) {
4133
39
        c->moderation(c->messenger, chat->group_number, setter_peer->peer_id, target_peer->peer_id,
4134
39
                      add_mod ? MV_MOD : MV_USER, userdata);
4135
39
    }
4136
4137
39
    return 0;
4138
39
}
4139
4140
/** @brief Sends a set mod broadcast to the group.
4141
 *
4142
 * Return true on success.
4143
 */
4144
static bool send_gc_set_mod(const GC_Chat *_Nonnull chat, const GC_Connection *_Nonnull gconn, bool add_mod)
4145
10
{
4146
10
    const uint16_t length = 1 + SIG_PUBLIC_KEY_SIZE;
4147
10
    uint8_t *data = (uint8_t *)mem_balloc(chat->mem, length);
4148
4149
10
    if (data == nullptr) {
4150
0
        return false;
4151
0
    }
4152
4153
10
    net_pack_bool(&data[0], add_mod);
4154
4155
10
    memcpy(data + 1, get_sig_pk(&gconn->addr.public_key), SIG_PUBLIC_KEY_SIZE);
4156
4157
10
    if (!send_gc_broadcast_message(chat, data, length, GM_SET_MOD)) {
4158
0
        mem_delete(chat->mem, data);
4159
0
        return false;
4160
0
    }
4161
4162
10
    mem_delete(chat->mem, data);
4163
4164
10
    return true;
4165
10
}
4166
4167
/**
4168
 * Adds or removes the peer designated by gconn from moderator list if `add_mod` is true or false respectively.
4169
 * Re-signs and re-distributes an updated mod_list hash.
4170
 *
4171
 * Returns true on success.
4172
 */
4173
static bool founder_gc_set_moderator(GC_Chat *_Nonnull chat, const GC_Connection *_Nonnull gconn, bool add_mod)
4174
10
{
4175
10
    if (!self_gc_is_founder(chat)) {
4176
0
        return false;
4177
0
    }
4178
4179
10
    if (add_mod) {
4180
6
        if (chat->moderation.num_mods >= MOD_MAX_NUM_MODERATORS) {
4181
0
            if (!prune_gc_mod_list(chat)) {
4182
0
                return false;
4183
0
            }
4184
0
        }
4185
4186
6
        if (!mod_list_add_entry(&chat->moderation, get_sig_pk(&gconn->addr.public_key))) {
4187
0
            return false;
4188
0
        }
4189
6
    } else {
4190
4
        if (!mod_list_remove_entry(&chat->moderation, get_sig_pk(&gconn->addr.public_key))) {
4191
0
            return false;
4192
0
        }
4193
4194
4
        if (!update_gc_sanctions_list(chat, get_sig_pk(&gconn->addr.public_key))
4195
4
                || !update_gc_topic(chat, get_sig_pk(&gconn->addr.public_key))) {
4196
0
            return false;
4197
0
        }
4198
4
    }
4199
4200
10
    uint8_t old_hash[MOD_MODERATION_HASH_SIZE];
4201
10
    memcpy(old_hash, chat->shared_state.mod_list_hash, MOD_MODERATION_HASH_SIZE);
4202
4203
10
    if (!mod_list_make_hash(&chat->moderation, chat->shared_state.mod_list_hash)) {
4204
0
        return false;
4205
0
    }
4206
4207
10
    if (!sign_gc_shared_state(chat) || !broadcast_gc_shared_state(chat)) {
4208
0
        memcpy(chat->shared_state.mod_list_hash, old_hash, MOD_MODERATION_HASH_SIZE);
4209
0
        return false;
4210
0
    }
4211
4212
10
    return send_gc_set_mod(chat, gconn, add_mod);
4213
10
}
4214
4215
/** @brief Validates `data` containing a change for the sanction list and unpacks it
4216
 * into the sanctions list for `chat`.
4217
 *
4218
 * if `add_obs` is true we're adding an observer to the list.
4219
 *
4220
 * Return 1 if sanctions list is not modified.
4221
 * Return 0 if data is valid and sanctions list is successfully modified.
4222
 * Return -1 if data is invalid format.
4223
 */
4224
static int validate_unpack_observer_entry(GC_Chat *_Nonnull chat, const uint8_t *_Nonnull data, uint16_t length, const uint8_t *_Nonnull public_key, bool add_obs)
4225
28
{
4226
28
    Mod_Sanction_Creds creds;
4227
4228
28
    if (add_obs) {
4229
20
        Mod_Sanction sanction;
4230
4231
20
        if (sanctions_list_unpack(&sanction, &creds, 1, data, length, nullptr) != 1) {
4232
0
            return -1;
4233
0
        }
4234
4235
        // this may occur if two mods change the sanctions list at the exact same time
4236
20
        if (creds.version == chat->moderation.sanctions_creds.version
4237
20
                && creds.checksum <= chat->moderation.sanctions_creds.checksum) {
4238
3
            return 1;
4239
3
        }
4240
4241
17
        if (sanctions_list_entry_exists(&chat->moderation, &sanction)
4242
17
                || !sanctions_list_add_entry(&chat->moderation, &sanction, &creds)) {
4243
1
            return -1;
4244
1
        }
4245
17
    } else {
4246
8
        if (length < MOD_SANCTIONS_CREDS_SIZE) {
4247
0
            return -1;
4248
0
        }
4249
4250
8
        if (sanctions_creds_unpack(&creds, data) != MOD_SANCTIONS_CREDS_SIZE) {
4251
0
            return -1;
4252
0
        }
4253
4254
8
        if (creds.version == chat->moderation.sanctions_creds.version
4255
8
                && creds.checksum <= chat->moderation.sanctions_creds.checksum) {
4256
0
            return 1;
4257
0
        }
4258
4259
8
        if (!sanctions_list_is_observer(&chat->moderation, public_key)
4260
8
                || !sanctions_list_remove_observer(&chat->moderation, public_key, &creds)) {
4261
0
            return 1;
4262
0
        }
4263
8
    }
4264
4265
24
    return 0;
4266
28
}
4267
4268
/** @brief Handles a set observer broadcast.
4269
 *
4270
 * Return 0 if packet is handled correctly.
4271
 * Return -1 if packet has invalid size.
4272
 * Return -2 if the packet contains invalid data.
4273
 * Return -3 if `peer_number` does not designate a valid peer.
4274
 */
4275
static int handle_gc_set_observer(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat, uint32_t peer_number, const uint8_t *_Nonnull data,
4276
                                  uint16_t length, void *_Nullable userdata)
4277
30
{
4278
30
    if (length <= 1 + EXT_PUBLIC_KEY_SIZE) {
4279
0
        return -1;
4280
0
    }
4281
4282
30
    const GC_Peer *setter_peer = get_gc_peer(chat, peer_number);
4283
4284
30
    if (setter_peer == nullptr) {
4285
0
        return -3;
4286
0
    }
4287
4288
30
    if (setter_peer->role > GR_MODERATOR) {
4289
0
        LOGGER_DEBUG(chat->log, "peer with insufficient permissions tried to modify sanctions list");
4290
0
        return 0;
4291
0
    }
4292
4293
30
    bool add_obs;
4294
30
    net_unpack_bool(&data[0], &add_obs);
4295
4296
30
    const uint8_t *public_key = data + 1;
4297
4298
30
    const int target_peer_number = get_peer_number_of_enc_pk(chat, public_key, false);
4299
4300
30
    if (target_peer_number >= 0 && (uint32_t)target_peer_number == peer_number) {
4301
0
        return -2;
4302
0
    }
4303
4304
30
    const GC_Peer *target_peer = get_gc_peer(chat, target_peer_number);
4305
4306
30
    if (target_peer != nullptr) {
4307
30
        if ((add_obs && target_peer->role != GR_USER) || (!add_obs && target_peer->role != GR_OBSERVER)) {
4308
2
            return 0;
4309
2
        }
4310
30
    }
4311
4312
28
    const int ret = validate_unpack_observer_entry(chat,
4313
28
                    data + 1 + EXT_PUBLIC_KEY_SIZE,
4314
28
                    length - 1 - EXT_PUBLIC_KEY_SIZE,
4315
28
                    public_key, add_obs);
4316
4317
28
    if (ret == -1) {
4318
1
        return -2;
4319
1
    }
4320
4321
27
    if (ret == 1) {
4322
3
        return 0;
4323
3
    }
4324
4325
24
    update_gc_peer_roles(chat);
4326
4327
24
    if (target_peer != nullptr) {
4328
24
        if (c->moderation != nullptr) {
4329
24
            c->moderation(c->messenger, chat->group_number, setter_peer->peer_id, target_peer->peer_id,
4330
24
                          add_obs ? MV_OBSERVER : MV_USER, userdata);
4331
24
        }
4332
24
    }
4333
4334
24
    return 0;
4335
27
}
4336
4337
/** @brief Broadcasts observer role data to the group.
4338
 *
4339
 * Returns true on success.
4340
 */
4341
static bool send_gc_set_observer(const GC_Chat *_Nonnull chat, const Extended_Public_Key *_Nonnull target_ext_pk, const uint8_t *_Nonnull sanction_data, uint16_t length, bool add_obs)
4342
8
{
4343
8
    const uint16_t packet_len = 1 + ENC_PUBLIC_KEY_SIZE + SIG_PUBLIC_KEY_SIZE + length;
4344
8
    uint8_t *packet = (uint8_t *)mem_balloc(chat->mem, packet_len);
4345
4346
8
    if (packet == nullptr) {
4347
0
        return false;
4348
0
    }
4349
4350
8
    net_pack_bool(&packet[0], add_obs);
4351
4352
8
    memcpy(packet + 1, target_ext_pk->enc, ENC_PUBLIC_KEY_SIZE);
4353
8
    memcpy(packet + 1 + ENC_PUBLIC_KEY_SIZE, target_ext_pk->sig, SIG_PUBLIC_KEY_SIZE);
4354
8
    memcpy(packet + 1 + ENC_PUBLIC_KEY_SIZE + SIG_PUBLIC_KEY_SIZE, sanction_data, length);
4355
4356
8
    if (!send_gc_broadcast_message(chat, packet, packet_len, GM_SET_OBSERVER)) {
4357
0
        mem_delete(chat->mem, packet);
4358
0
        return false;
4359
0
    }
4360
4361
8
    mem_delete(chat->mem, packet);
4362
4363
8
    return true;
4364
8
}
4365
4366
/** @brief Adds or removes peer_number from the observer list if add_obs is true or false respectively.
4367
 * Broadcasts this change to the entire group.
4368
 *
4369
 * Returns true on success.
4370
 */
4371
static bool mod_gc_set_observer(GC_Chat *_Nonnull chat, uint32_t peer_number, bool add_obs)
4372
8
{
4373
8
    const GC_Connection *gconn = get_gc_connection(chat, peer_number);
4374
4375
8
    if (gconn == nullptr) {
4376
0
        return false;
4377
0
    }
4378
4379
8
    if (gc_get_self_role(chat) >= GR_USER) {
4380
0
        return false;
4381
0
    }
4382
4383
8
    uint8_t sanction_data[MOD_SANCTION_PACKED_SIZE + MOD_SANCTIONS_CREDS_SIZE];
4384
8
    uint16_t length = 0;
4385
4386
8
    if (add_obs) {
4387
6
        if (chat->moderation.num_sanctions >= MOD_MAX_NUM_SANCTIONS) {
4388
0
            if (!prune_gc_sanctions_list(chat)) {
4389
0
                return false;
4390
0
            }
4391
0
        }
4392
4393
        // if sanctioned peer set the topic we need to overwrite his signature and redistribute
4394
        // topic info
4395
6
        const int setter_peer_number = get_peer_number_of_sig_pk(chat, chat->topic_info.public_sig_key);
4396
4397
6
        if (setter_peer_number >= 0 && (uint32_t)setter_peer_number == peer_number) {
4398
1
            if (gc_set_topic(chat, chat->topic_info.topic, chat->topic_info.length) != 0) {
4399
0
                return false;
4400
0
            }
4401
1
        }
4402
4403
6
        Mod_Sanction sanction;
4404
4405
6
        if (!sanctions_list_make_entry(&chat->moderation, gconn->addr.public_key.enc, &sanction, SA_OBSERVER)) {
4406
0
            LOGGER_WARNING(chat->log, "sanctions_list_make_entry failed in mod_gc_set_observer");
4407
0
            return false;
4408
0
        }
4409
4410
6
        const int packed_len = sanctions_list_pack(sanction_data, sizeof(sanction_data), &sanction, 1,
4411
6
                               &chat->moderation.sanctions_creds);
4412
4413
6
        if (packed_len == -1) {
4414
0
            return false;
4415
0
        }
4416
4417
6
        length += packed_len;
4418
6
    } else {
4419
2
        if (!sanctions_list_remove_observer(&chat->moderation, gconn->addr.public_key.enc, nullptr)) {
4420
0
            LOGGER_WARNING(chat->log, "failed to remove sanction");
4421
0
            return false;
4422
0
        }
4423
4424
2
        const uint16_t packed_len = sanctions_creds_pack(&chat->moderation.sanctions_creds, sanction_data);
4425
4426
2
        if (packed_len != MOD_SANCTIONS_CREDS_SIZE) {
4427
0
            return false;
4428
0
        }
4429
4430
2
        length += packed_len;
4431
2
    }
4432
4433
8
    if (length > sizeof(sanction_data)) {
4434
0
        LOGGER_FATAL(chat->log, "Invalid sanction data length: %u", length);
4435
0
        return false;
4436
0
    }
4437
4438
8
    update_gc_peer_roles(chat);
4439
4440
8
    return send_gc_set_observer(chat, &gconn->addr.public_key, sanction_data, length, add_obs);
4441
8
}
4442
4443
/** @brief Sets the role of `peer_number` to `new_role`. If necessary this function will first
4444
 * remove the peer's current role before applying the new one.
4445
 *
4446
 * Return true on success.
4447
 */
4448
static bool apply_new_gc_role(GC_Chat *_Nonnull chat, uint32_t peer_number, Group_Role current_role, Group_Role new_role)
4449
17
{
4450
17
    const GC_Connection *gconn = get_gc_connection(chat, peer_number);
4451
4452
17
    if (gconn == nullptr) {
4453
0
        return false;
4454
0
    }
4455
4456
17
    switch (current_role) {
4457
4
        case GR_MODERATOR: {
4458
4
            if (!founder_gc_set_moderator(chat, gconn, false)) {
4459
0
                return false;
4460
0
            }
4461
4462
4
            update_gc_peer_roles(chat);
4463
4464
4
            if (new_role == GR_OBSERVER) {
4465
0
                return mod_gc_set_observer(chat, peer_number, true);
4466
0
            }
4467
4468
4
            break;
4469
4
        }
4470
4471
4
        case GR_OBSERVER: {
4472
2
            if (!mod_gc_set_observer(chat, peer_number, false)) {
4473
0
                return false;
4474
0
            }
4475
4476
2
            update_gc_peer_roles(chat);
4477
4478
2
            if (new_role == GR_MODERATOR) {
4479
1
                return founder_gc_set_moderator(chat, gconn, true);
4480
1
            }
4481
4482
1
            break;
4483
2
        }
4484
4485
11
        case GR_USER: {
4486
11
            if (new_role == GR_MODERATOR) {
4487
5
                return founder_gc_set_moderator(chat, gconn, true);
4488
6
            } else if (new_role == GR_OBSERVER) {
4489
6
                return mod_gc_set_observer(chat, peer_number, true);
4490
6
            }
4491
4492
0
            break;
4493
11
        }
4494
4495
0
        case GR_FOUNDER:
4496
4497
        // Intentional fallthrough
4498
0
        default: {
4499
0
            return false;
4500
0
        }
4501
17
    }
4502
4503
5
    return true;
4504
17
}
4505
4506
int gc_set_peer_role(const Messenger *m, int group_number, GC_Peer_Id peer_id, Group_Role new_role)
4507
25
{
4508
25
    const GC_Session *c = m->group_handler;
4509
25
    GC_Chat *chat = gc_get_group(c, group_number);
4510
4511
25
    if (chat == nullptr) {
4512
0
        return -1;
4513
0
    }
4514
4515
25
    const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
4516
4517
25
    const GC_Peer *peer = get_gc_peer(chat, peer_number);
4518
4519
25
    if (peer == nullptr) {
4520
0
        return -2;
4521
0
    }
4522
4523
25
    const GC_Connection *gconn = &peer->gconn;
4524
4525
25
    if (!gconn->confirmed) {
4526
0
        return -2;
4527
0
    }
4528
4529
25
    const Group_Role current_role = peer->role;
4530
4531
25
    if (new_role == GR_FOUNDER || peer->role == new_role) {
4532
2
        return -4;
4533
2
    }
4534
4535
23
    if (peer_number_is_self(peer_number)) {
4536
0
        return -6;
4537
0
    }
4538
4539
23
    if (current_role == GR_FOUNDER || gc_get_self_role(chat) >= GR_USER) {
4540
4
        return -3;
4541
4
    }
4542
4543
    // moderators can't demote moderators or promote peers to moderator
4544
19
    if (!self_gc_is_founder(chat) && (new_role == GR_MODERATOR || current_role == GR_MODERATOR)) {
4545
2
        return -3;
4546
2
    }
4547
4548
17
    if (!apply_new_gc_role(chat, peer_number, current_role, new_role)) {
4549
0
        return -5;
4550
0
    }
4551
4552
17
    update_gc_peer_roles(chat);
4553
4554
17
    return 0;
4555
17
}
4556
4557
/** @brief Return true if topic lock is enabled */
4558
static bool group_topic_lock_enabled(const GC_Chat *_Nonnull chat)
4559
2.09k
{
4560
2.09k
    return chat->shared_state.topic_lock == GC_TOPIC_LOCK_ENABLED;
4561
2.09k
}
4562
4563
Group_Privacy_State gc_get_privacy_state(const GC_Chat *chat)
4564
16
{
4565
16
    return chat->shared_state.privacy_state;
4566
16
}
4567
4568
Group_Topic_Lock gc_get_topic_lock_state(const GC_Chat *chat)
4569
296
{
4570
296
    return group_topic_lock_enabled(chat) ? TL_ENABLED : TL_DISABLED;
4571
296
}
4572
4573
Group_Voice_State gc_get_voice_state(const GC_Chat *chat)
4574
84
{
4575
84
    return chat->shared_state.voice_state;
4576
84
}
4577
4578
int gc_founder_set_topic_lock(const Messenger *m, int group_number, Group_Topic_Lock new_lock_state)
4579
75
{
4580
75
    const GC_Session *c = m->group_handler;
4581
75
    GC_Chat *chat = gc_get_group(c, group_number);
4582
4583
75
    if (chat == nullptr) {
4584
0
        return -1;
4585
0
    }
4586
4587
75
    if (new_lock_state > TL_DISABLED) {
4588
0
        return -2;
4589
0
    }
4590
4591
75
    if (!self_gc_is_founder(chat)) {
4592
0
        return -3;
4593
0
    }
4594
4595
75
    if (chat->connection_state <= CS_DISCONNECTED) {
4596
0
        return -4;
4597
0
    }
4598
4599
75
    const Group_Topic_Lock old_lock_state = gc_get_topic_lock_state(chat);
4600
4601
75
    if (new_lock_state == old_lock_state) {
4602
1
        return 0;
4603
1
    }
4604
4605
74
    const uint32_t old_topic_lock = chat->shared_state.topic_lock;
4606
4607
    // If we're enabling the lock the founder needs to sign the current topic and re-broadcast
4608
    // it with a new version. This needs to happen before we re-broadcast the shared state because
4609
    // if it fails we don't want to enable the topic lock with an invalid topic signature or version.
4610
74
    if (new_lock_state == TL_ENABLED) {
4611
2
        chat->shared_state.topic_lock = GC_TOPIC_LOCK_ENABLED;
4612
4613
2
        if (gc_set_topic(chat, chat->topic_info.topic, chat->topic_info.length) != 0) {
4614
0
            chat->shared_state.topic_lock = old_topic_lock;
4615
0
            return -6;
4616
0
        }
4617
72
    } else {
4618
72
        chat->shared_state.topic_lock = chat->topic_info.version;
4619
72
    }
4620
4621
74
    if (!sign_gc_shared_state(chat)) {
4622
0
        chat->shared_state.topic_lock = old_topic_lock;
4623
0
        return -5;
4624
0
    }
4625
4626
74
    if (!broadcast_gc_shared_state(chat)) {
4627
5
        return -6;
4628
5
    }
4629
4630
69
    return 0;
4631
74
}
4632
4633
int gc_founder_set_voice_state(const Messenger *m, int group_number, Group_Voice_State new_voice_state)
4634
5
{
4635
5
    const GC_Session *c = m->group_handler;
4636
5
    GC_Chat *chat = gc_get_group(c, group_number);
4637
4638
5
    if (chat == nullptr) {
4639
0
        return -1;
4640
0
    }
4641
4642
5
    if (!self_gc_is_founder(chat)) {
4643
0
        return -2;
4644
0
    }
4645
4646
5
    if (chat->connection_state == CS_DISCONNECTED || chat->connection_state == CS_NONE) {
4647
0
        return -3;
4648
0
    }
4649
4650
5
    const Group_Voice_State old_voice_state = chat->shared_state.voice_state;
4651
4652
5
    if (new_voice_state == old_voice_state) {
4653
1
        return 0;
4654
1
    }
4655
4656
4
    chat->shared_state.voice_state = new_voice_state;
4657
4658
4
    if (!sign_gc_shared_state(chat)) {
4659
0
        chat->shared_state.voice_state = old_voice_state;
4660
0
        return -4;
4661
0
    }
4662
4663
4
    if (!broadcast_gc_shared_state(chat)) {
4664
0
        return -5;
4665
0
    }
4666
4667
4
    return 0;
4668
4
}
4669
4670
int gc_founder_set_privacy_state(const Messenger *m, int group_number, Group_Privacy_State new_privacy_state)
4671
68
{
4672
68
    const GC_Session *c = m->group_handler;
4673
68
    GC_Chat *chat = gc_get_group(c, group_number);
4674
4675
68
    if (chat == nullptr) {
4676
0
        return -1;
4677
0
    }
4678
4679
68
    if (!self_gc_is_founder(chat)) {
4680
0
        return -2;
4681
0
    }
4682
4683
68
    if (chat->connection_state == CS_DISCONNECTED || chat->connection_state == CS_NONE) {
4684
0
        return -3;
4685
0
    }
4686
4687
68
    const Group_Privacy_State old_privacy_state = chat->shared_state.privacy_state;
4688
4689
68
    if (new_privacy_state == old_privacy_state) {
4690
65
        return 0;
4691
65
    }
4692
4693
3
    chat->shared_state.privacy_state = new_privacy_state;
4694
4695
3
    if (!sign_gc_shared_state(chat)) {
4696
0
        chat->shared_state.privacy_state = old_privacy_state;
4697
0
        return -4;
4698
0
    }
4699
4700
3
    if (new_privacy_state == GI_PRIVATE) {
4701
2
        cleanup_gca(c->announces_list, get_chat_id(&chat->chat_public_key));
4702
2
        kill_group_friend_connection(c, chat);
4703
2
        chat->join_type = HJ_PRIVATE;
4704
2
    } else {
4705
1
        if (!m_create_group_connection(c->messenger, chat)) {
4706
0
            LOGGER_ERROR(chat->log, "Failed to initialize group friend connection");
4707
1
        } else {
4708
1
            chat->update_self_announces = true;
4709
1
            chat->join_type = HJ_PUBLIC;
4710
1
        }
4711
1
    }
4712
4713
3
    if (!broadcast_gc_shared_state(chat)) {
4714
0
        return -5;
4715
0
    }
4716
4717
3
    return 0;
4718
3
}
4719
4720
uint16_t gc_get_max_peers(const GC_Chat *chat)
4721
916
{
4722
916
    return chat->shared_state.maxpeers;
4723
916
}
4724
4725
int gc_founder_set_max_peers(GC_Chat *chat, uint16_t max_peers)
4726
64
{
4727
64
    if (!self_gc_is_founder(chat)) {
4728
0
        return -1;
4729
0
    }
4730
4731
64
    const uint16_t old_maxpeers = chat->shared_state.maxpeers;
4732
4733
64
    if (max_peers == chat->shared_state.maxpeers) {
4734
0
        return 0;
4735
0
    }
4736
4737
64
    chat->shared_state.maxpeers = max_peers;
4738
4739
64
    if (!sign_gc_shared_state(chat)) {
4740
0
        chat->shared_state.maxpeers = old_maxpeers;
4741
0
        return -2;
4742
0
    }
4743
4744
64
    if (!broadcast_gc_shared_state(chat)) {
4745
5
        return -3;
4746
5
    }
4747
4748
59
    return 0;
4749
64
}
4750
4751
int gc_send_message(const GC_Chat *chat, const uint8_t *message, uint16_t length, uint8_t type, uint32_t *message_id)
4752
9.32k
{
4753
9.32k
    if (length > MAX_GC_MESSAGE_SIZE) {
4754
0
        return -1;
4755
0
    }
4756
4757
9.32k
    if (message == nullptr || length == 0) {
4758
0
        return -2;
4759
0
    }
4760
4761
9.32k
    if (type != GC_MESSAGE_TYPE_NORMAL && type != GC_MESSAGE_TYPE_ACTION) {
4762
0
        return -3;
4763
0
    }
4764
4765
9.32k
    const GC_Peer *self = get_gc_peer(chat, 0);
4766
9.32k
    assert(self != nullptr);
4767
4768
9.32k
    if (gc_get_self_role(chat) >= GR_OBSERVER || !peer_has_voice(self, chat->shared_state.voice_state)) {
4769
9
        return -4;
4770
9
    }
4771
4772
9.31k
    const uint8_t packet_type = type == GC_MESSAGE_TYPE_NORMAL ? GM_PLAIN_MESSAGE : GM_ACTION_MESSAGE;
4773
4774
9.31k
    const uint16_t length_raw = length + GC_MESSAGE_PSEUDO_ID_SIZE;
4775
9.31k
    uint8_t *message_raw = (uint8_t *)mem_balloc(chat->mem, length_raw);
4776
4777
9.31k
    if (message_raw == nullptr) {
4778
0
        return -5;
4779
0
    }
4780
4781
9.31k
    const uint32_t pseudo_msg_id = random_u32(chat->rng);
4782
4783
9.31k
    net_pack_u32(message_raw, pseudo_msg_id);
4784
9.31k
    memcpy(message_raw + GC_MESSAGE_PSEUDO_ID_SIZE, message, length);
4785
4786
9.31k
    if (!send_gc_broadcast_message(chat, message_raw, length_raw, packet_type)) {
4787
0
        mem_delete(chat->mem, message_raw);
4788
0
        return -5;
4789
0
    }
4790
4791
9.31k
    mem_delete(chat->mem, message_raw);
4792
4793
9.31k
    if (message_id != nullptr) {
4794
9.31k
        *message_id = pseudo_msg_id;
4795
9.31k
    }
4796
4797
9.31k
    return 0;
4798
9.31k
}
4799
4800
/** @brief Handles a message broadcast.
4801
 *
4802
 * Return 0 if packet is handled correctly.
4803
 * Return -1 if packet has invalid size.
4804
 */
4805
static int handle_gc_message(const GC_Session *_Nonnull c, const GC_Chat *_Nonnull chat, const GC_Peer *_Nonnull peer, const uint8_t *_Nonnull data,
4806
                             uint16_t length, uint8_t type, void *_Nullable userdata)
4807
9.32k
{
4808
9.32k
    if (data == nullptr || length > MAX_GC_MESSAGE_RAW_SIZE || length <= GC_MESSAGE_PSEUDO_ID_SIZE) {
4809
0
        return -1;
4810
0
    }
4811
4812
9.32k
    if (peer->ignore || peer->role >= GR_OBSERVER || !peer_has_voice(peer, chat->shared_state.voice_state)) {
4813
1
        return 0;
4814
1
    }
4815
4816
9.32k
    if (type != GM_PLAIN_MESSAGE && type != GM_ACTION_MESSAGE) {
4817
0
        LOGGER_WARNING(chat->log, "received invalid message type: %u", type);
4818
0
        return 0;
4819
0
    }
4820
4821
9.32k
    const uint8_t cb_type = (type == GM_PLAIN_MESSAGE) ? MESSAGE_NORMAL : MESSAGE_ACTION;
4822
4823
9.32k
    uint32_t pseudo_msg_id;
4824
9.32k
    net_unpack_u32(data, &pseudo_msg_id);
4825
4826
9.32k
    if (c->message != nullptr) {
4827
9.32k
        c->message(c->messenger, chat->group_number, peer->peer_id, cb_type, data + GC_MESSAGE_PSEUDO_ID_SIZE,
4828
9.32k
                   length - GC_MESSAGE_PSEUDO_ID_SIZE, pseudo_msg_id, userdata);
4829
9.32k
    }
4830
4831
9.32k
    return 0;
4832
9.32k
}
4833
4834
int gc_send_private_message(const GC_Chat *chat, GC_Peer_Id peer_id, uint8_t type, const uint8_t *message,
4835
                            uint16_t length, uint32_t *message_id)
4836
1
{
4837
1
    if (length > MAX_GC_MESSAGE_SIZE) {
4838
0
        return -1;
4839
0
    }
4840
4841
1
    if (message == nullptr || length == 0) {
4842
0
        return -2;
4843
0
    }
4844
4845
1
    const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
4846
4847
1
    GC_Connection *gconn = get_gc_connection(chat, peer_number);
4848
4849
1
    if (gconn == nullptr) {
4850
0
        return -3;
4851
0
    }
4852
4853
1
    if (type > MESSAGE_ACTION) {
4854
0
        return -4;
4855
0
    }
4856
4857
1
    if (gc_get_self_role(chat) >= GR_OBSERVER) {
4858
0
        return -5;
4859
0
    }
4860
4861
1
    const uint16_t raw_length = 1 + length + GC_MESSAGE_PSEUDO_ID_SIZE;
4862
1
    uint8_t *message_with_type = (uint8_t *)mem_balloc(chat->mem, raw_length);
4863
4864
1
    if (message_with_type == nullptr) {
4865
0
        return -6;
4866
0
    }
4867
4868
1
    message_with_type[0] = type;
4869
4870
1
    const uint32_t pseudo_msg_id = random_u32(chat->rng);
4871
1
    net_pack_u32(message_with_type + 1, pseudo_msg_id);
4872
4873
1
    memcpy(message_with_type + 1 + GC_MESSAGE_PSEUDO_ID_SIZE, message, length);
4874
4875
1
    uint8_t *packet = (uint8_t *)mem_balloc(chat->mem, raw_length + GC_BROADCAST_ENC_HEADER_SIZE);
4876
4877
1
    if (packet == nullptr) {
4878
0
        mem_delete(chat->mem, message_with_type);
4879
0
        return -6;
4880
0
    }
4881
4882
1
    const uint16_t packet_len = make_gc_broadcast_header(message_with_type, raw_length, packet, GM_PRIVATE_MESSAGE);
4883
4884
1
    mem_delete(chat->mem, message_with_type);
4885
4886
1
    if (!send_lossless_group_packet(chat, gconn, packet, packet_len, GP_BROADCAST)) {
4887
0
        mem_delete(chat->mem, packet);
4888
0
        return -6;
4889
0
    }
4890
4891
1
    mem_delete(chat->mem, packet);
4892
4893
1
    if (message_id != nullptr) {
4894
1
        *message_id = pseudo_msg_id;
4895
1
    }
4896
4897
1
    return 0;
4898
1
}
4899
4900
/** @brief Handles a private message.
4901
 *
4902
 * Return 0 if packet is handled correctly.
4903
 * Return -1 if packet has invalid size.
4904
 */
4905
static int handle_gc_private_message(const GC_Session *_Nonnull c, const GC_Chat *_Nonnull chat, const GC_Peer *_Nonnull peer, const uint8_t *_Nonnull data,
4906
                                     uint16_t length, void *_Nullable userdata)
4907
1
{
4908
1
    if (data == nullptr || length > MAX_GC_MESSAGE_SIZE || length <= 1 + GC_MESSAGE_PSEUDO_ID_SIZE) {
4909
0
        return -1;
4910
0
    }
4911
4912
1
    if (peer->ignore || peer->role >= GR_OBSERVER) {
4913
0
        return 0;
4914
0
    }
4915
4916
1
    const uint8_t message_type = data[0];
4917
4918
1
    if (message_type > MESSAGE_ACTION) {
4919
0
        LOGGER_WARNING(chat->log, "Received invalid private message type: %u", message_type);
4920
0
        return 0;
4921
0
    }
4922
4923
1
    uint32_t message_id;
4924
1
    net_unpack_u32(data + 1, &message_id);
4925
4926
1
    if (c->private_message != nullptr) {
4927
1
        c->private_message(c->messenger, chat->group_number, peer->peer_id, message_type,
4928
1
                           data + 1 + GC_MESSAGE_PSEUDO_ID_SIZE, length - 1 - GC_MESSAGE_PSEUDO_ID_SIZE,
4929
1
                           message_id, userdata);
4930
1
    }
4931
4932
1
    return 0;
4933
1
}
4934
4935
/** @brief Returns false if a custom packet is too large. */
4936
static bool custom_gc_packet_length_is_valid(uint16_t length, bool lossless)
4937
10
{
4938
10
    return length <= (lossless ? MAX_GC_CUSTOM_LOSSLESS_PACKET_SIZE : MAX_GC_CUSTOM_LOSSY_PACKET_SIZE);
4939
10
}
4940
4941
int gc_send_custom_private_packet(const GC_Chat *chat, bool lossless, GC_Peer_Id peer_id, const uint8_t *message,
4942
                                  uint16_t length)
4943
2
{
4944
2
    if (!custom_gc_packet_length_is_valid(length, lossless)) {
4945
0
        return -1;
4946
0
    }
4947
4948
2
    if (message == nullptr || length == 0) {
4949
0
        return -2;
4950
0
    }
4951
4952
2
    const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
4953
4954
2
    GC_Connection *gconn = get_gc_connection(chat, peer_number);
4955
4956
2
    if (gconn == nullptr) {
4957
0
        return -3;
4958
0
    }
4959
4960
2
    bool ret;
4961
4962
2
    if (lossless) {
4963
1
        ret = send_lossless_group_packet(chat, gconn, message, length, GP_CUSTOM_PRIVATE_PACKET);
4964
1
    } else {
4965
1
        ret = send_lossy_group_packet(chat, gconn, message, length, GP_CUSTOM_PRIVATE_PACKET);
4966
1
    }
4967
4968
2
    return ret ? 0 : -4;
4969
2
}
4970
4971
/** @brief Handles a custom private packet.
4972
 *
4973
 * @retval 0 if packet is handled correctly.
4974
 * @retval -1 if packet has invalid size.
4975
 */
4976
static int handle_gc_custom_private_packet(const GC_Session *_Nonnull c, const GC_Chat *_Nonnull chat, const GC_Peer *_Nonnull peer,
4977
        const uint8_t *_Nonnull data, uint16_t length, bool lossless, void *_Nullable userdata)
4978
2
{
4979
2
    if (!custom_gc_packet_length_is_valid(length, lossless)) {
4980
0
        return -1;
4981
0
    }
4982
4983
2
    if (data == nullptr || length == 0) {
4984
0
        return -1;
4985
0
    }
4986
4987
2
    if (c->custom_private_packet != nullptr) {
4988
2
        c->custom_private_packet(c->messenger, chat->group_number, peer->peer_id, data, length, userdata);
4989
2
    }
4990
4991
2
    return 0;
4992
2
}
4993
4994
int gc_send_custom_packet(const GC_Chat *chat, bool lossless, const uint8_t *data, uint16_t length)
4995
3
{
4996
3
    if (!custom_gc_packet_length_is_valid(length, lossless)) {
4997
0
        return -1;
4998
0
    }
4999
5000
3
    if (data == nullptr || length == 0) {
5001
0
        return -2;
5002
0
    }
5003
5004
3
    bool success;
5005
5006
3
    if (lossless) {
5007
1
        success = send_gc_lossless_packet_all_peers(chat, data, length, GP_CUSTOM_PACKET);
5008
2
    } else {
5009
2
        success = send_gc_lossy_packet_all_peers(chat, data, length, GP_CUSTOM_PACKET);
5010
2
    }
5011
5012
3
    return success ? 0 : -3;
5013
3
}
5014
5015
/** @brief Handles a custom packet.
5016
 *
5017
 * Return 0 if packet is handled correctly.
5018
 * Return -1 if packet has invalid size.
5019
 */
5020
static int handle_gc_custom_packet(const GC_Session *_Nonnull c, const GC_Chat *_Nonnull chat, const GC_Peer *_Nonnull peer, const uint8_t *_Nonnull data,
5021
                                   uint16_t length, bool lossless, void *_Nullable userdata)
5022
3
{
5023
3
    if (!custom_gc_packet_length_is_valid(length, lossless)) {
5024
0
        return -1;
5025
0
    }
5026
5027
3
    if (data == nullptr || length == 0) {
5028
0
        return -1;
5029
0
    }
5030
5031
3
    if (c->custom_packet != nullptr) {
5032
3
        c->custom_packet(c->messenger, chat->group_number, peer->peer_id, data, length, userdata);
5033
3
    }
5034
5035
3
    return 0;
5036
3
}
5037
5038
/** @brief Handles a peer kick broadcast.
5039
 *
5040
 * Return 0 if packet is handled correctly.
5041
 * Return -1 if packet has invalid size.
5042
 */
5043
static int handle_gc_kick_peer(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat, const GC_Peer *_Nonnull setter_peer, const uint8_t *_Nonnull data,
5044
                               uint16_t length, void *_Nullable userdata)
5045
4
{
5046
4
    if (length < ENC_PUBLIC_KEY_SIZE) {
5047
0
        return -1;
5048
0
    }
5049
5050
4
    if (setter_peer->role >= GR_USER) {
5051
0
        return 0;
5052
0
    }
5053
5054
4
    const uint8_t *target_pk = data;
5055
5056
4
    const int target_peer_number = get_peer_number_of_enc_pk(chat, target_pk, false);
5057
4
    GC_Peer *target_peer = get_gc_peer(chat, target_peer_number);
5058
5059
4
    if (target_peer != nullptr) {
5060
4
        if (target_peer->role != GR_USER) {
5061
0
            return 0;
5062
0
        }
5063
4
    }
5064
5065
4
    if (peer_number_is_self(target_peer_number)) {
5066
1
        assert(target_peer != nullptr);
5067
5068
5
        for (uint32_t i = 1; i < chat->numpeers; ++i) {
5069
4
            GC_Connection *gconn = get_gc_connection(chat, i);
5070
4
            assert(gconn != nullptr);
5071
5072
4
            gcc_mark_for_deletion(gconn, chat->tcp_conn, GC_EXIT_TYPE_SELF_DISCONNECTED, nullptr, 0);
5073
4
        }
5074
5075
1
        chat->connection_state = CS_DISCONNECTED;
5076
5077
1
        if (c->moderation != nullptr) {
5078
1
            c->moderation(c->messenger, chat->group_number, setter_peer->peer_id, target_peer->peer_id,
5079
1
                          MV_KICK, userdata);
5080
1
        }
5081
5082
1
        return 0;
5083
1
    }
5084
5085
3
    if (target_peer == nullptr) {   /** we don't need to/can't kick a peer that isn't in our peerlist */
5086
0
        return 0;
5087
0
    }
5088
5089
3
    gcc_mark_for_deletion(&target_peer->gconn, chat->tcp_conn, GC_EXIT_TYPE_KICKED, nullptr, 0);
5090
5091
3
    if (c->moderation != nullptr) {
5092
3
        c->moderation(c->messenger, chat->group_number, setter_peer->peer_id, target_peer->peer_id, MV_KICK, userdata);
5093
3
    }
5094
5095
3
    return 0;
5096
3
}
5097
5098
/** @brief Sends a packet to instruct all peers to remove gconn from their peerlist.
5099
 *
5100
 * Returns true on success.
5101
 */
5102
static bool send_gc_kick_peer(const GC_Chat *_Nonnull chat, const GC_Connection *_Nonnull gconn)
5103
1
{
5104
1
    uint8_t packet[ENC_PUBLIC_KEY_SIZE];
5105
1
    memcpy(packet, gconn->addr.public_key.enc, ENC_PUBLIC_KEY_SIZE);
5106
5107
1
    return send_gc_broadcast_message(chat, packet, ENC_PUBLIC_KEY_SIZE, GM_KICK_PEER);
5108
1
}
5109
5110
int gc_kick_peer(const Messenger *m, int group_number, GC_Peer_Id peer_id)
5111
2
{
5112
2
    const GC_Session *c = m->group_handler;
5113
2
    GC_Chat *chat = gc_get_group(c, group_number);
5114
5115
2
    if (chat == nullptr) {
5116
0
        return -1;
5117
0
    }
5118
5119
2
    const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
5120
5121
2
    if (peer_number_is_self(peer_number)) {
5122
0
        return -6;
5123
0
    }
5124
5125
2
    GC_Peer *peer = get_gc_peer(chat, peer_number);
5126
5127
2
    if (peer == nullptr) {
5128
0
        return -2;
5129
0
    }
5130
5131
2
    if (gc_get_self_role(chat) >= GR_USER || peer->role == GR_FOUNDER) {
5132
1
        return -3;
5133
1
    }
5134
5135
1
    if (!self_gc_is_founder(chat) && peer->role == GR_MODERATOR) {
5136
0
        return -3;
5137
0
    }
5138
5139
1
    if (peer->role == GR_MODERATOR || peer->role == GR_OBSERVER) {
5140
        // this first removes peer from any lists they're on and broadcasts new lists to group
5141
1
        if (gc_set_peer_role(c->messenger, chat->group_number, peer_id, GR_USER) < 0) {
5142
0
            return -4;
5143
0
        }
5144
1
    }
5145
5146
1
    if (!send_gc_kick_peer(chat, &peer->gconn)) {
5147
0
        return -5;
5148
0
    }
5149
5150
1
    gcc_mark_for_deletion(&peer->gconn, chat->tcp_conn, GC_EXIT_TYPE_NO_CALLBACK, nullptr, 0);
5151
5152
1
    return 0;
5153
1
}
5154
5155
bool gc_send_message_ack(const GC_Chat *chat, GC_Connection *gconn, uint64_t message_id, Group_Message_Ack_Type type)
5156
13.3k
{
5157
13.3k
    if (gconn->pending_delete) {
5158
0
        return true;
5159
0
    }
5160
5161
13.3k
    if (type == GR_ACK_REQ) {
5162
101
        const uint64_t tm = mono_time_get(chat->mono_time);
5163
5164
101
        if (gconn->last_requested_packet_time == tm) {
5165
88
            return true;
5166
88
        }
5167
5168
13
        gconn->last_requested_packet_time = tm;
5169
13.2k
    } else if (type != GR_ACK_RECV) {
5170
0
        return false;
5171
0
    }
5172
5173
13.2k
    uint8_t data[GC_LOSSLESS_ACK_PACKET_SIZE];
5174
13.2k
    data[0] = (uint8_t) type;
5175
13.2k
    net_pack_u64(data + 1, message_id);
5176
5177
13.2k
    return send_lossy_group_packet(chat, gconn, data, GC_LOSSLESS_ACK_PACKET_SIZE, GP_MESSAGE_ACK);
5178
13.3k
}
5179
5180
/** @brief Handles a lossless message acknowledgement.
5181
 *
5182
 * If the type is GR_ACK_RECV we remove the packet from our
5183
 * send array. If the type is GR_ACK_REQ we re-send the packet
5184
 * associated with the requested message_id.
5185
 *
5186
 * Returns 0 if packet is handled correctly.
5187
 * Return -1 if packet has invalid size.
5188
 * Return -2 if we failed to handle the ack (may be caused by connection issues).
5189
 * Return -3 if we failed to re-send a requested packet.
5190
 */
5191
static int handle_gc_message_ack(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn, const uint8_t *_Nonnull data, uint16_t length)
5192
12.9k
{
5193
12.9k
    if (length < GC_LOSSLESS_ACK_PACKET_SIZE) {
5194
0
        return -1;
5195
0
    }
5196
5197
12.9k
    uint64_t message_id;
5198
12.9k
    net_unpack_u64(data + 1, &message_id);
5199
5200
12.9k
    const Group_Message_Ack_Type type = (Group_Message_Ack_Type) data[0];
5201
5202
12.9k
    if (type == GR_ACK_RECV) {
5203
12.9k
        if (!gcc_handle_ack(chat->log, chat->mem, gconn, message_id)) {
5204
0
            return -2;
5205
0
        }
5206
5207
12.9k
        return 0;
5208
12.9k
    }
5209
5210
13
    if (type != GR_ACK_REQ) {
5211
0
        return 0;
5212
0
    }
5213
5214
13
    const uint64_t tm = mono_time_get(chat->mono_time);
5215
13
    const uint16_t idx = gcc_get_array_index(message_id);
5216
5217
    /* re-send requested packet */
5218
13
    if (gconn->send_array[idx].message_id == message_id) {
5219
13
        if (gcc_encrypt_and_send_lossless_packet(chat, gconn, gconn->send_array[idx].data,
5220
13
                gconn->send_array[idx].data_length,
5221
13
                gconn->send_array[idx].message_id,
5222
13
                gconn->send_array[idx].packet_type) == 0) {
5223
13
            gconn->send_array[idx].last_send_try = tm;
5224
13
            LOGGER_DEBUG(chat->log, "Re-sent requested packet %llu", (unsigned long long)message_id);
5225
13
        } else {
5226
0
            return -3;
5227
0
        }
5228
13
    }
5229
5230
13
    return 0;
5231
13
}
5232
5233
/** @brief Sends a handshake response ack to peer.
5234
 *
5235
 * Return true on success.
5236
 */
5237
static bool send_gc_hs_response_ack(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn)
5238
184
{
5239
184
    return send_lossless_group_packet(chat, gconn, nullptr, 0, GP_HS_RESPONSE_ACK);
5240
184
}
5241
5242
/** @brief Handles a handshake response ack.
5243
 *
5244
 * Return 0 if packet is handled correctly.
5245
 * Return -1 if we failed to respond with an invite request.
5246
 */
5247
static int handle_gc_hs_response_ack(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn)
5248
184
{
5249
184
    gconn->handshaked = true;  // has to be true before we can send a lossless packet
5250
5251
184
    if (!send_gc_invite_request(chat, gconn)) {
5252
0
        gconn->handshaked = false;
5253
0
        return -1;
5254
0
    }
5255
5256
184
    return 0;
5257
184
}
5258
5259
int gc_set_ignore(const GC_Chat *chat, GC_Peer_Id peer_id, bool ignore)
5260
2
{
5261
2
    const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
5262
5263
2
    GC_Peer *peer = get_gc_peer(chat, peer_number);
5264
5265
2
    if (peer == nullptr) {
5266
0
        return -1;
5267
0
    }
5268
5269
2
    if (peer_number_is_self(peer_number)) {
5270
0
        return -2;
5271
0
    }
5272
5273
2
    peer->ignore = ignore;
5274
5275
2
    return 0;
5276
2
}
5277
5278
/** @brief Handles a broadcast packet.
5279
 *
5280
 * Returns 0 if packet is handled correctly.
5281
 * Returns -1 on failure.
5282
 */
5283
static int handle_gc_broadcast(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat, uint32_t peer_number, const uint8_t *_Nonnull data,
5284
                               uint16_t length, void *_Nullable userdata)
5285
9.50k
{
5286
9.50k
    if (length < GC_BROADCAST_ENC_HEADER_SIZE) {
5287
0
        return -1;
5288
0
    }
5289
5290
9.50k
    GC_Peer *peer = get_gc_peer(chat, peer_number);
5291
5292
9.50k
    if (peer == nullptr) {
5293
0
        return -1;
5294
0
    }
5295
5296
9.50k
    GC_Connection *gconn = &peer->gconn;
5297
5298
9.50k
    if (!gconn->confirmed) {
5299
0
        return -1;
5300
0
    }
5301
5302
9.50k
    const uint8_t broadcast_type = data[0];
5303
5304
9.50k
    const uint16_t m_len = length - 1;
5305
9.50k
    const uint8_t *message = data + 1;
5306
5307
9.50k
    int ret = 0;
5308
5309
9.50k
    switch (broadcast_type) {
5310
41
        case GM_STATUS: {
5311
41
            ret = handle_gc_status(c, chat, peer, message, m_len, userdata);
5312
41
            break;
5313
0
        }
5314
5315
41
        case GM_NICK: {
5316
41
            ret = handle_gc_nick(c, chat, peer, message, m_len, userdata);
5317
41
            break;
5318
0
        }
5319
5320
0
        case GM_ACTION_MESSAGE:
5321
5322
        // intentional fallthrough
5323
9.32k
        case GM_PLAIN_MESSAGE: {
5324
9.32k
            ret = handle_gc_message(c, chat, peer, message, m_len, broadcast_type, userdata);
5325
9.32k
            break;
5326
0
        }
5327
5328
1
        case GM_PRIVATE_MESSAGE: {
5329
1
            ret = handle_gc_private_message(c, chat, peer, message, m_len, userdata);
5330
1
            break;
5331
0
        }
5332
5333
16
        case GM_PEER_EXIT: {
5334
16
            handle_gc_peer_exit(chat, gconn, message, m_len);
5335
16
            ret = 0;
5336
16
            break;
5337
0
        }
5338
5339
4
        case GM_KICK_PEER: {
5340
4
            ret = handle_gc_kick_peer(c, chat, peer, message, m_len, userdata);
5341
4
            break;
5342
0
        }
5343
5344
39
        case GM_SET_MOD: {
5345
39
            ret = handle_gc_set_mod(c, chat, peer_number, message, m_len, userdata);
5346
39
            break;
5347
0
        }
5348
5349
30
        case GM_SET_OBSERVER: {
5350
30
            ret = handle_gc_set_observer(c, chat, peer_number, message, m_len, userdata);
5351
30
            break;
5352
0
        }
5353
5354
0
        default: {
5355
0
            LOGGER_DEBUG(chat->log, "Received an invalid broadcast type 0x%02x", broadcast_type);
5356
0
            break;
5357
0
        }
5358
9.50k
    }
5359
5360
9.50k
    if (ret < 0) {
5361
1
        LOGGER_DEBUG(chat->log, "Broadcast handle error %d: type: 0x%02x, peernumber: %u",
5362
1
                     ret, broadcast_type, peer_number);
5363
1
        return -1;
5364
1
    }
5365
5366
9.50k
    return 0;
5367
9.50k
}
5368
5369
/** @brief Decrypts data of size `length` using self secret key and sender's public key.
5370
 *
5371
 * The packet payload should begin with a nonce.
5372
 *
5373
 * Returns length of plaintext data on success.
5374
 * Return -1 if length is invalid.
5375
 * Return -2 if decryption fails.
5376
 */
5377
static int unwrap_group_handshake_packet(const Logger *_Nonnull log, const Memory *_Nonnull mem, const uint8_t *_Nonnull self_sk, const uint8_t *_Nonnull sender_pk, uint8_t *_Nonnull plain,
5378
        size_t plain_size, const uint8_t *_Nonnull packet, uint16_t length)
5379
448
{
5380
448
    if (length <= CRYPTO_NONCE_SIZE) {
5381
0
        LOGGER_FATAL(log, "Invalid handshake packet length %u", length);
5382
0
        return -1;
5383
0
    }
5384
5385
448
    const int plain_len = decrypt_data(mem, sender_pk, self_sk, packet, packet + CRYPTO_NONCE_SIZE,
5386
448
                                       length - CRYPTO_NONCE_SIZE, plain);
5387
5388
448
    if (plain_len < 0 || (uint32_t)plain_len != plain_size) {
5389
0
        LOGGER_DEBUG(log, "decrypt handshake request failed: len: %d, size: %zu", plain_len, plain_size);
5390
0
        return -2;
5391
0
    }
5392
5393
448
    return plain_len;
5394
448
}
5395
5396
/** @brief Encrypts data of length using the peer's shared key a new nonce.
5397
 *
5398
 * Adds plaintext header consisting of: packet identifier, target public encryption key,
5399
 * self public encryption key, nonce.
5400
 *
5401
 * Return length of encrypted packet on success.
5402
 * Return -1 if packet size is invalid.
5403
 * Return -2 on memory allocation failure.
5404
 * Return -3 if encryption fails.
5405
 */
5406
static int wrap_group_handshake_packet(const Logger *_Nonnull log, const Memory *_Nonnull mem, const Random *_Nonnull rng, const uint8_t *_Nonnull self_pk, const uint8_t *_Nonnull self_sk,
5407
                                       const uint8_t *_Nonnull target_pk, uint8_t *_Nonnull packet, uint32_t packet_size, const uint8_t *_Nonnull data, uint16_t length)
5408
663
{
5409
663
    if (packet_size != GC_MIN_ENCRYPTED_HS_PAYLOAD_SIZE + sizeof(Node_format)) {
5410
0
        LOGGER_FATAL(log, "Invalid packet size: %u", packet_size);
5411
0
        return -1;
5412
0
    }
5413
5414
663
    uint8_t nonce[CRYPTO_NONCE_SIZE];
5415
663
    random_nonce(rng, nonce);
5416
5417
663
    const size_t encrypt_buf_size = length + CRYPTO_MAC_SIZE;
5418
663
    uint8_t *encrypt = (uint8_t *)mem_balloc(mem, encrypt_buf_size);
5419
5420
663
    if (encrypt == nullptr) {
5421
1
        return -2;
5422
1
    }
5423
5424
662
    const int enc_len = encrypt_data(mem, target_pk, self_sk, nonce, data, length, encrypt);
5425
5426
662
    if (enc_len < 0 || (size_t)enc_len != encrypt_buf_size) {
5427
0
        LOGGER_ERROR(log, "Failed to encrypt group handshake packet (len: %d)", enc_len);
5428
0
        mem_delete(mem, encrypt);
5429
0
        return -3;
5430
0
    }
5431
5432
662
    packet[0] = NET_PACKET_GC_HANDSHAKE;
5433
662
    memcpy(packet + 1, self_pk, ENC_PUBLIC_KEY_SIZE);
5434
662
    memcpy(packet + 1 + ENC_PUBLIC_KEY_SIZE, target_pk, ENC_PUBLIC_KEY_SIZE);
5435
662
    memcpy(packet + 1 + ENC_PUBLIC_KEY_SIZE + ENC_PUBLIC_KEY_SIZE, nonce, CRYPTO_NONCE_SIZE);
5436
662
    memcpy(packet + 1 + ENC_PUBLIC_KEY_SIZE + ENC_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, encrypt, enc_len);
5437
5438
662
    mem_delete(mem, encrypt);
5439
5440
662
    return 1 + ENC_PUBLIC_KEY_SIZE + ENC_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + enc_len;
5441
662
}
5442
5443
/** @brief Makes, wraps and encrypts a group handshake packet (both request and response are the same format).
5444
 *
5445
 * Packet contains the packet header, handshake type, self public encryption key, self public signature key,
5446
 * request type, and a single TCP relay node.
5447
 *
5448
 * Returns length of encrypted packet on success.
5449
 * Returns -1 on failure.
5450
 */
5451
static int make_gc_handshake_packet(const GC_Chat *_Nonnull chat, const GC_Connection *_Nonnull gconn, uint8_t handshake_type, uint8_t request_type, uint8_t join_type, uint8_t *_Nonnull packet,
5452
                                    size_t packet_size, const Node_format *_Nonnull node)
5453
663
{
5454
663
    if (chat == nullptr || gconn == nullptr || node == nullptr) {
5455
0
        return -1;
5456
0
    }
5457
5458
663
    if (packet_size != GC_MIN_ENCRYPTED_HS_PAYLOAD_SIZE + sizeof(Node_format)) {
5459
0
        LOGGER_FATAL(chat->log, "invalid packet size: %zu", packet_size);
5460
0
        return -1;
5461
0
    }
5462
5463
663
    uint8_t data[GC_MIN_HS_PACKET_PAYLOAD_SIZE + sizeof(Node_format)];
5464
5465
663
    uint16_t length = sizeof(uint8_t);
5466
5467
663
    data[0] = handshake_type;
5468
663
    memcpy(data + length, gconn->session_public_key, ENC_PUBLIC_KEY_SIZE);
5469
663
    length += ENC_PUBLIC_KEY_SIZE;
5470
663
    memcpy(data + length, get_sig_pk(&chat->self_public_key), SIG_PUBLIC_KEY_SIZE);
5471
663
    length += SIG_PUBLIC_KEY_SIZE;
5472
663
    memcpy(data + length, &request_type, sizeof(uint8_t));
5473
663
    length += sizeof(uint8_t);
5474
663
    memcpy(data + length, &join_type, sizeof(uint8_t));
5475
663
    length += sizeof(uint8_t);
5476
5477
663
    int nodes_size = pack_nodes(chat->log, data + length, sizeof(Node_format), node, MAX_SENT_GC_NODES);
5478
5479
663
    if (nodes_size > 0) {
5480
0
        length += nodes_size;
5481
663
    } else {
5482
663
        nodes_size = 0;
5483
663
    }
5484
5485
663
    const int enc_len = wrap_group_handshake_packet(
5486
663
                            chat->log, chat->mem, chat->rng, chat->self_public_key.enc, chat->self_secret_key.enc,
5487
663
                            gconn->addr.public_key.enc, packet, (uint16_t)packet_size, data, length);
5488
5489
663
    if (enc_len != GC_MIN_ENCRYPTED_HS_PAYLOAD_SIZE + nodes_size) {
5490
1
        LOGGER_WARNING(chat->log, "Failed to wrap handshake packet: %d", enc_len);
5491
1
        return -1;
5492
1
    }
5493
5494
662
    return enc_len;
5495
663
}
5496
5497
/** @brief Sends a handshake packet to `gconn`.
5498
 *
5499
 * Handshake_type should be GH_REQUEST or GH_RESPONSE.
5500
 *
5501
 * Returns true on success.
5502
 */
5503
static bool send_gc_handshake_packet(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn, uint8_t handshake_type, uint8_t request_type, uint8_t join_type)
5504
663
{
5505
663
    if (gconn == nullptr) {
5506
0
        return false;
5507
0
    }
5508
5509
663
    Node_format node = {{0}};
5510
5511
663
    if (!gcc_copy_tcp_relay(chat->rng, &node, gconn)) {
5512
663
        LOGGER_TRACE(chat->log, "Failed to copy TCP relay during handshake (%u TCP relays)", gconn->tcp_relays_count);
5513
663
    }
5514
5515
663
    uint8_t packet[GC_MIN_ENCRYPTED_HS_PAYLOAD_SIZE + sizeof(Node_format)];
5516
663
    const int length = make_gc_handshake_packet(chat, gconn, handshake_type, request_type, join_type, packet,
5517
663
                       sizeof(packet), &node);
5518
5519
663
    if (length < 0) {
5520
1
        return false;
5521
1
    }
5522
5523
662
    const bool try_tcp_fallback = gconn->handshake_attempts % 2 == 1 && gconn->tcp_relays_count > 0;
5524
662
    ++gconn->handshake_attempts;
5525
5526
662
    int ret = -1;
5527
5528
662
    if (!try_tcp_fallback && gcc_direct_conn_is_possible(chat, gconn)) {
5529
662
        ret = sendpacket(chat->net, &gconn->addr.ip_port, packet, (uint16_t)length);
5530
662
    }
5531
5532
662
    if (ret != length && gconn->tcp_relays_count == 0) {
5533
0
        LOGGER_WARNING(chat->log, "UDP handshake failed and no TCP relays to fall back on");
5534
0
        return false;
5535
0
    }
5536
5537
    // Send a TCP handshake if UDP fails, or if UDP succeeded last time but we never got a response
5538
662
    if (gconn->tcp_relays_count > 0 && (ret != length || try_tcp_fallback)) {
5539
0
        if (send_packet_tcp_connection(chat->tcp_conn, gconn->tcp_connection_num, packet, (uint16_t)length) == -1) {
5540
0
            LOGGER_DEBUG(chat->log, "Send handshake packet failed. Type 0x%02x", request_type);
5541
0
            return false;
5542
0
        }
5543
0
    }
5544
5545
662
    if (gconn->is_pending_handshake_response) {
5546
184
        gcc_set_send_message_id(gconn, 3);  // handshake response is always second packet
5547
478
    }  else {
5548
478
        gcc_set_send_message_id(gconn, 2);  // handshake request is always first packet
5549
478
    }
5550
5551
662
    return true;
5552
662
}
5553
5554
/** @brief Sends an out-of-band TCP handshake request packet to `gconn`.
5555
 *
5556
 * Return true on success.
5557
 */
5558
static bool send_gc_oob_handshake_request(const GC_Chat *chat, const GC_Connection *gconn)
5559
0
{
5560
0
    if (gconn == nullptr) {
5561
0
        return false;
5562
0
    }
5563
5564
0
    Node_format node = {{0}};
5565
5566
0
    if (!gcc_copy_tcp_relay(chat->rng, &node, gconn)) {
5567
0
        LOGGER_WARNING(chat->log, "Failed to copy TCP relay");
5568
0
        return false;
5569
0
    }
5570
5571
0
    uint8_t packet[GC_MIN_ENCRYPTED_HS_PAYLOAD_SIZE + sizeof(Node_format)];
5572
0
    const int length = make_gc_handshake_packet(chat, gconn, GH_REQUEST, gconn->pending_handshake_type, chat->join_type,
5573
0
                       packet, sizeof(packet), &node);
5574
5575
0
    if (length < 0) {
5576
0
        LOGGER_WARNING(chat->log, "Failed to make handshake packet");
5577
0
        return false;
5578
0
    }
5579
5580
0
    return tcp_send_oob_packet_using_relay(chat->tcp_conn, gconn->oob_relay_pk, gconn->addr.public_key.enc,
5581
0
                                           packet, (uint16_t)length) == 0;
5582
0
}
5583
5584
/** @brief Handles a handshake response packet and takes appropriate action depending on the value of request_type.
5585
 *
5586
 * This function assumes the length has already been validated.
5587
 *
5588
 * Returns peer_number of new connected peer on success.
5589
 * Returns -1 on failure.
5590
 */
5591
static int handle_gc_handshake_response(const GC_Chat *_Nonnull chat, const uint8_t *_Nonnull sender_pk, const uint8_t *_Nonnull data, uint16_t length)
5592
184
{
5593
    // this should be checked at lower level; this is a redundant defense check. Ideally we should
5594
    // guarantee that this can never happen in the future.
5595
184
    if (length < ENC_PUBLIC_KEY_SIZE + SIG_PUBLIC_KEY_SIZE + 1) {
5596
0
        LOGGER_FATAL(chat->log, "Invalid handshake response size (%u)", length);
5597
0
        return -1;
5598
0
    }
5599
5600
184
    const int peer_number = get_peer_number_of_enc_pk(chat, sender_pk, false);
5601
5602
184
    if (peer_number == -1) {
5603
0
        return -1;
5604
0
    }
5605
5606
184
    GC_Connection *gconn = get_gc_connection(chat, peer_number);
5607
5608
184
    if (gconn == nullptr) {
5609
0
        return -1;
5610
0
    }
5611
5612
184
    const uint8_t *sender_session_pk = data;
5613
5614
184
    gcc_make_session_shared_key(gconn, sender_session_pk);
5615
5616
184
    set_sig_pk(&gconn->addr.public_key, data + ENC_PUBLIC_KEY_SIZE);
5617
5618
184
    gcc_set_recv_message_id(gconn, 2);  // handshake response is always second packet
5619
5620
184
    gconn->handshaked = true;
5621
5622
184
    send_gc_hs_response_ack(chat, gconn);
5623
5624
184
    const uint8_t request_type = data[ENC_PUBLIC_KEY_SIZE + SIG_PUBLIC_KEY_SIZE];
5625
5626
184
    switch (request_type) {
5627
173
        case HS_INVITE_REQUEST: {
5628
173
            if (!send_gc_invite_request(chat, gconn)) {
5629
0
                return -1;
5630
0
            }
5631
5632
173
            break;
5633
173
        }
5634
5635
173
        case HS_PEER_INFO_EXCHANGE: {
5636
11
            if (!send_gc_peer_exchange(chat, gconn)) {
5637
0
                return -1;
5638
0
            }
5639
5640
11
            break;
5641
11
        }
5642
5643
11
        default: {
5644
0
            return -1;
5645
11
        }
5646
184
    }
5647
5648
184
    return peer_number;
5649
184
}
5650
5651
/** @brief Sends a handshake response packet of type `request_type` to `gconn`.
5652
 *
5653
 * Return true on success.
5654
 */
5655
static bool send_gc_handshake_response(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn)
5656
184
{
5657
184
    return send_gc_handshake_packet(chat, gconn, GH_RESPONSE, gconn->pending_handshake_type, 0);
5658
184
}
5659
5660
/** @brief Handles handshake request packets.
5661
 *
5662
 * Peer is added to peerlist and a lossless connection is established.
5663
 *
5664
 * This function assumes the length has already been validated.
5665
 *
5666
 * Return new peer's peer_number on success.
5667
 * Return -1 on failure.
5668
 */
5669
264
#define GC_NEW_PEER_CONNECTION_LIMIT 10
5670
static int handle_gc_handshake_request(GC_Chat *_Nonnull chat, const IP_Port *_Nullable ipp, const uint8_t *_Nonnull sender_pk,
5671
                                       const uint8_t *_Nonnull data, uint16_t length)
5672
264
{
5673
    // this should be checked at lower level; this is a redundant defense check. Ideally we should
5674
    // guarantee that this can never happen in the future.
5675
264
    if (length < ENC_PUBLIC_KEY_SIZE + SIG_PUBLIC_KEY_SIZE + 1 + 1) {
5676
0
        LOGGER_FATAL(chat->log, "Invalid length (%u)", length);
5677
0
        return -1;
5678
0
    }
5679
5680
264
    if (chat->connection_state <= CS_DISCONNECTED) {
5681
0
        LOGGER_DEBUG(chat->log, "Handshake request ignored; state is disconnected");
5682
0
        return -1;
5683
0
    }
5684
5685
264
    if (chat->connection_o_metre >= GC_NEW_PEER_CONNECTION_LIMIT) {
5686
0
        chat->block_handshakes = true;
5687
0
        LOGGER_DEBUG(chat->log, "Handshake overflow. Blocking handshakes.");
5688
0
        return -1;
5689
0
    }
5690
5691
264
    ++chat->connection_o_metre;
5692
5693
264
    const uint8_t *public_sig_key = data + ENC_PUBLIC_KEY_SIZE;
5694
5695
264
    const uint8_t request_type = data[ENC_PUBLIC_KEY_SIZE + SIG_PUBLIC_KEY_SIZE];
5696
264
    const uint8_t join_type = data[ENC_PUBLIC_KEY_SIZE + SIG_PUBLIC_KEY_SIZE + 1];
5697
5698
264
    int peer_number = get_peer_number_of_enc_pk(chat, sender_pk, false);
5699
264
    const bool is_new_peer = peer_number < 0;
5700
5701
264
    if (is_new_peer) {
5702
74
        peer_number = peer_add(chat, ipp, sender_pk);
5703
5704
74
        if (peer_number < 0) {
5705
0
            LOGGER_WARNING(chat->log, "Failed to add peer during handshake request");
5706
0
            return -1;
5707
0
        }
5708
190
    } else  {
5709
190
        GC_Connection *gconn = get_gc_connection(chat, peer_number);
5710
5711
190
        if (gconn == nullptr) {
5712
0
            LOGGER_WARNING(chat->log, "Invalid peer number");
5713
0
            return -1;
5714
0
        }
5715
5716
190
        if (gconn->handshaked) {
5717
12
            gconn->handshaked = false;
5718
12
            LOGGER_DEBUG(chat->log, "Handshaked peer sent a handshake request");
5719
12
            return -1;
5720
12
        }
5721
5722
        // peers sent handshake request at same time so the closer peer becomes the requestor
5723
        // and ignores the request packet while further peer continues on with the response
5724
178
        if (gconn->self_is_closer) {
5725
68
            LOGGER_DEBUG(chat->log, "Simultaneous handshake requests; other peer is closer");
5726
68
            return 0;
5727
68
        }
5728
178
    }
5729
5730
184
    GC_Connection *gconn = get_gc_connection(chat, peer_number);
5731
5732
184
    if (gconn == nullptr) {
5733
0
        LOGGER_DEBUG(chat->log, "Peer connection invalid");
5734
0
        return -1;
5735
0
    }
5736
5737
184
    gcc_set_ip_port(gconn, ipp);
5738
5739
184
    Node_format node[GCA_MAX_ANNOUNCED_TCP_RELAYS];
5740
184
    const int processed = ENC_PUBLIC_KEY_SIZE + SIG_PUBLIC_KEY_SIZE + 1 + 1;
5741
5742
184
    const int nodes_count = unpack_nodes(node, GCA_MAX_ANNOUNCED_TCP_RELAYS, nullptr,
5743
184
                                         data + processed, length - processed, true);
5744
5745
184
    if (nodes_count <= 0 && ipp == nullptr) {
5746
0
        if (is_new_peer) {
5747
0
            LOGGER_WARNING(chat->log, "Broken tcp relay for new peer");
5748
0
            gcc_mark_for_deletion(gconn, chat->tcp_conn, GC_EXIT_TYPE_DISCONNECTED, nullptr, 0);
5749
0
        }
5750
5751
0
        return -1;
5752
0
    }
5753
5754
184
    if (nodes_count > 0) {
5755
0
        const int add_tcp_result = add_tcp_relay_connection(chat->tcp_conn, gconn->tcp_connection_num,
5756
0
                                   &node->ip_port, node->public_key);
5757
5758
0
        if (add_tcp_result < 0 && is_new_peer && ipp == nullptr) {
5759
0
            LOGGER_WARNING(chat->log, "Broken tcp relay for new peer");
5760
0
            gcc_mark_for_deletion(gconn, chat->tcp_conn, GC_EXIT_TYPE_DISCONNECTED, nullptr, 0);
5761
0
            return -1;
5762
0
        }
5763
5764
0
        if (add_tcp_result == 0) {
5765
0
            gcc_save_tcp_relay(chat->rng, gconn, node);
5766
0
        }
5767
0
    }
5768
5769
184
    const uint8_t *sender_session_pk = data;
5770
5771
184
    gcc_make_session_shared_key(gconn, sender_session_pk);
5772
5773
184
    set_sig_pk(&gconn->addr.public_key, public_sig_key);
5774
5775
184
    if (join_type == HJ_PUBLIC && !is_public_chat(chat)) {
5776
0
        gcc_mark_for_deletion(gconn, chat->tcp_conn, GC_EXIT_TYPE_DISCONNECTED, nullptr, 0);
5777
0
        LOGGER_DEBUG(chat->log, "Ignoring invalid invite request");
5778
0
        return -1;
5779
0
    }
5780
5781
184
    gcc_set_recv_message_id(gconn, 1);  // handshake request is always first packet
5782
5783
184
    gconn->is_pending_handshake_response = true;
5784
184
    gconn->pending_handshake_type = request_type;
5785
5786
184
    return peer_number;
5787
184
}
5788
5789
/** @brief Handles handshake request and handshake response packets.
5790
 *
5791
 * Returns the peer_number of the connecting peer on success.
5792
 * Returns -1 on failure.
5793
 */
5794
static int handle_gc_handshake_packet(GC_Chat *_Nonnull chat, const uint8_t *_Nonnull sender_pk, const IP_Port *_Nullable ipp,
5795
                                      const uint8_t *_Nonnull packet, uint16_t length, bool direct_conn, void *_Nullable userdata)
5796
448
{
5797
448
    if (length < GC_MIN_HS_PACKET_PAYLOAD_SIZE + CRYPTO_MAC_SIZE + CRYPTO_NONCE_SIZE) {
5798
0
        return -1;
5799
0
    }
5800
5801
448
    const size_t data_buf_size = length - CRYPTO_NONCE_SIZE - CRYPTO_MAC_SIZE;
5802
448
    uint8_t *data = (uint8_t *)mem_balloc(chat->mem, data_buf_size);
5803
5804
448
    if (data == nullptr) {
5805
0
        return -1;
5806
0
    }
5807
5808
448
    const int plain_len = unwrap_group_handshake_packet(chat->log, chat->mem, chat->self_secret_key.enc, sender_pk, data,
5809
448
                          data_buf_size, packet, length);
5810
5811
448
    if (plain_len < GC_MIN_HS_PACKET_PAYLOAD_SIZE)  {
5812
0
        LOGGER_DEBUG(chat->log, "Failed to unwrap handshake packet (probably a stale request using an old key)");
5813
0
        mem_delete(chat->mem, data);
5814
0
        return -1;
5815
0
    }
5816
5817
448
    const uint8_t handshake_type = data[0];
5818
5819
448
    const uint8_t *real_data = data + 1;
5820
448
    const uint16_t real_len = (uint16_t)plain_len - 1;
5821
5822
448
    int peer_number;
5823
5824
448
    if (handshake_type == GH_REQUEST) {
5825
264
        peer_number = handle_gc_handshake_request(chat, ipp, sender_pk, real_data, real_len);
5826
264
    } else if (handshake_type == GH_RESPONSE) {
5827
184
        peer_number = handle_gc_handshake_response(chat, sender_pk, real_data, real_len);
5828
184
    } else {
5829
0
        mem_delete(chat->mem, data);
5830
0
        return -1;
5831
0
    }
5832
5833
448
    mem_delete(chat->mem, data);
5834
5835
448
    GC_Connection *gconn = get_gc_connection(chat, peer_number);
5836
5837
448
    if (gconn == nullptr) {
5838
12
        return -1;
5839
12
    }
5840
5841
436
    if (direct_conn) {
5842
436
        gconn->last_received_direct_time = mono_time_get(chat->mono_time);
5843
436
    }
5844
5845
436
    return peer_number;
5846
448
}
5847
5848
bool handle_gc_lossless_helper(const GC_Session *c, GC_Chat *chat, uint32_t peer_number, const uint8_t *data,
5849
                               uint16_t length, uint8_t packet_type, void *userdata)
5850
12.8k
{
5851
12.8k
    GC_Peer *peer = get_gc_peer(chat, peer_number);
5852
5853
12.8k
    if (peer == nullptr) {
5854
0
        return false;
5855
0
    }
5856
5857
12.8k
    GC_Connection *gconn = &peer->gconn;
5858
5859
12.8k
    int ret;
5860
5861
12.8k
    switch (packet_type) {
5862
9.50k
        case GP_BROADCAST: {
5863
9.50k
            ret = handle_gc_broadcast(c, chat, peer_number, data, length, userdata);
5864
9.50k
            break;
5865
0
        }
5866
5867
210
        case GP_PEER_INFO_REQUEST: {
5868
210
            ret = handle_gc_peer_info_request(chat, peer_number);
5869
210
            break;
5870
0
        }
5871
5872
413
        case GP_PEER_INFO_RESPONSE: {
5873
413
            ret = handle_gc_peer_info_response(c, chat, peer_number, data, length, userdata);
5874
413
            break;
5875
0
        }
5876
5877
196
        case GP_SYNC_REQUEST: {
5878
196
            ret = handle_gc_sync_request(chat, peer_number, data, length);
5879
196
            break;
5880
0
        }
5881
5882
206
        case GP_SYNC_RESPONSE: {
5883
206
            ret = handle_gc_sync_response(c, chat, peer_number, data, length, userdata);
5884
206
            break;
5885
0
        }
5886
5887
354
        case GP_INVITE_REQUEST: {
5888
354
            ret = handle_gc_invite_request(chat, peer_number, data, length);
5889
354
            break;
5890
0
        }
5891
5892
204
        case GP_INVITE_RESPONSE: {
5893
204
            ret = handle_gc_invite_response(chat, gconn);
5894
204
            break;
5895
0
        }
5896
5897
755
        case GP_TOPIC: {
5898
755
            ret = handle_gc_topic(c, chat, peer, data, length, userdata);
5899
755
            break;
5900
0
        }
5901
5902
400
        case GP_SHARED_STATE: {
5903
400
            ret = handle_gc_shared_state(c, chat, gconn, data, length, userdata);
5904
400
            break;
5905
0
        }
5906
5907
189
        case GP_MOD_LIST: {
5908
189
            ret = handle_gc_mod_list(c, chat, data, length, userdata);
5909
189
            break;
5910
0
        }
5911
5912
189
        case GP_SANCTIONS_LIST: {
5913
189
            ret = handle_gc_sanctions_list(c, chat, data, length, userdata);
5914
189
            break;
5915
0
        }
5916
5917
184
        case GP_HS_RESPONSE_ACK: {
5918
184
            ret = handle_gc_hs_response_ack(chat, gconn);
5919
184
            break;
5920
0
        }
5921
5922
0
        case GP_TCP_RELAYS: {
5923
0
            ret = handle_gc_tcp_relays(chat, gconn, data, length);
5924
0
            break;
5925
0
        }
5926
5927
0
        case GP_KEY_ROTATION: {
5928
0
            ret = handle_gc_key_exchange(chat, gconn, data, length);
5929
0
            break;
5930
0
        }
5931
5932
1
        case GP_CUSTOM_PACKET: {
5933
1
            ret = handle_gc_custom_packet(c, chat, peer, data, length, true, userdata);
5934
1
            break;
5935
0
        }
5936
5937
1
        case GP_CUSTOM_PRIVATE_PACKET: {
5938
1
            ret = handle_gc_custom_private_packet(c, chat, peer, data, length, true, userdata);
5939
1
            break;
5940
0
        }
5941
5942
0
        default: {
5943
0
            LOGGER_DEBUG(chat->log, "Handling invalid lossless group packet type 0x%02x", packet_type);
5944
0
            return false;
5945
0
        }
5946
12.8k
    }
5947
5948
12.8k
    if (ret < 0) {
5949
16
        LOGGER_DEBUG(chat->log, "Lossless packet handle error %d: type: 0x%02x, peernumber: %u",
5950
16
                     ret, packet_type, peer_number);
5951
16
        return false;
5952
16
    }
5953
5954
12.7k
    peer = get_gc_peer(chat, peer_number);
5955
5956
12.7k
    if (peer != nullptr) {
5957
12.7k
        peer->gconn.last_requested_packet_time = mono_time_get(chat->mono_time);
5958
12.7k
    }
5959
5960
12.7k
    return true;
5961
12.8k
}
5962
5963
/** @brief Handles a packet fragment.
5964
 *
5965
 * If the fragment is the last one in a sequence we send an ack. Otherwise we
5966
 * store the fragment in the receive array and wait for the next segment.
5967
 *
5968
 * Segments must be processed in correct sequence, and we cannot handle
5969
 * non-fragment packets while a sequence is incomplete.
5970
 *
5971
 * Return true if packet is handled successfully.
5972
 */
5973
static bool handle_gc_packet_fragment(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat, uint32_t peer_number, GC_Connection *_Nonnull gconn,
5974
                                      const uint8_t *_Nullable data, uint16_t length, uint8_t packet_type, uint64_t message_id,
5975
                                      void *_Nullable userdata)
5976
648
{
5977
648
    if (gconn->last_chunk_id != 0 && message_id != gconn->last_chunk_id + 1) {
5978
0
        return gc_send_message_ack(chat, gconn, gconn->last_chunk_id + 1, GR_ACK_REQ);
5979
0
    }
5980
5981
648
    if (gconn->last_chunk_id == 0 && message_id != gconn->received_message_id + 1) {
5982
0
        return gc_send_message_ack(chat, gconn, gconn->received_message_id + 1, GR_ACK_REQ);
5983
0
    }
5984
5985
648
    const int frag_ret = gcc_handle_packet_fragment(c, chat, peer_number, gconn, data, length, packet_type,
5986
648
                         message_id, userdata);
5987
5988
648
    if (frag_ret == -1) {
5989
0
        return false;
5990
0
    }
5991
5992
648
    if (frag_ret == 0) {
5993
191
        gc_send_message_ack(chat, gconn, message_id, GR_ACK_RECV);
5994
191
    }
5995
5996
648
    gconn->last_received_packet_time = mono_time_get(chat->mono_time);
5997
5998
648
    return true;
5999
648
}
6000
6001
/** @brief Handles lossless groupchat packets.
6002
 *
6003
 * This function assumes the length has already been validated.
6004
 *
6005
 * Returns true if packet is successfully handled.
6006
 */
6007
static bool handle_gc_lossless_packet(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat, const uint8_t *_Nonnull sender_pk,
6008
                                      const uint8_t *_Nonnull packet, uint16_t length, bool direct_conn, void *_Nullable userdata)
6009
13.8k
{
6010
13.8k
    if (length < GC_MIN_LOSSLESS_PAYLOAD_SIZE) {
6011
0
        return false;
6012
0
    }
6013
6014
13.8k
    int peer_number = get_peer_number_of_enc_pk(chat, sender_pk, false);
6015
6016
13.8k
    GC_Connection *gconn = get_gc_connection(chat, peer_number);
6017
6018
13.8k
    if (gconn == nullptr) {
6019
0
        return false;
6020
0
    }
6021
6022
13.8k
    if (gconn->pending_delete) {
6023
0
        return true;
6024
0
    }
6025
6026
13.8k
    uint8_t *data = (uint8_t *)mem_balloc(chat->mem, length);
6027
6028
13.8k
    if (data == nullptr) {
6029
2
        LOGGER_DEBUG(chat->log, "Failed to allocate memory for packet data buffer");
6030
2
        return false;
6031
2
    }
6032
6033
13.8k
    uint8_t packet_type;
6034
13.8k
    uint64_t message_id;
6035
6036
13.8k
    const int len = group_packet_unwrap(chat->log, chat->mem, gconn, data, &message_id, &packet_type, packet, length);
6037
6038
13.8k
    if (len < 0) {
6039
2
        Ip_Ntoa ip_str;
6040
2
        LOGGER_DEBUG(chat->log, "Failed to unwrap lossless packet from %s:%d: %d",
6041
2
                     net_ip_ntoa(&gconn->addr.ip_port.ip, &ip_str), net_ntohs(gconn->addr.ip_port.port), len);
6042
2
        mem_delete(chat->mem, data);
6043
2
        return false;
6044
2
    }
6045
6046
13.8k
    if (!gconn->handshaked && (packet_type != GP_HS_RESPONSE_ACK && packet_type != GP_INVITE_REQUEST)) {
6047
0
        LOGGER_DEBUG(chat->log, "Got lossless packet type 0x%02x from unconfirmed peer", packet_type);
6048
0
        mem_delete(chat->mem, data);
6049
0
        return false;
6050
0
    }
6051
6052
13.8k
    const bool is_invite_packet = packet_type == GP_INVITE_REQUEST || packet_type == GP_INVITE_RESPONSE
6053
13.8k
                                  || packet_type == GP_INVITE_RESPONSE_REJECT;
6054
6055
13.8k
    if (message_id == 3 && is_invite_packet && gconn->received_message_id <= 1) {
6056
        // we missed initial handshake request. Drop this packet and wait for another handshake request.
6057
0
        LOGGER_DEBUG(chat->log, "Missed handshake packet, type: 0x%02x", packet_type);
6058
0
        mem_delete(chat->mem, data);
6059
0
        return false;
6060
0
    }
6061
6062
13.8k
    const int lossless_ret = gcc_handle_received_message(chat->log, chat->mem, chat->mono_time, gconn, data, (uint16_t) len, packet_type, message_id, direct_conn);
6063
6064
13.8k
    if (packet_type == GP_INVITE_REQUEST && !gconn->handshaked) {  // Both peers sent request at same time
6065
0
        mem_delete(chat->mem, data);
6066
0
        return true;
6067
0
    }
6068
6069
13.8k
    if (lossless_ret < 0) {
6070
1
        LOGGER_DEBUG(chat->log, "failed to handle packet %llu (type: 0x%02x, id: %llu)",
6071
1
                     (unsigned long long)message_id, packet_type, (unsigned long long)message_id);
6072
1
        mem_delete(chat->mem, data);
6073
1
        return false;
6074
1
    }
6075
6076
    /* Duplicate packet */
6077
13.8k
    if (lossless_ret == 0) {
6078
472
        mem_delete(chat->mem, data);
6079
472
        return gc_send_message_ack(chat, gconn, message_id, GR_ACK_RECV);
6080
472
    }
6081
6082
    /* request missing packet */
6083
13.3k
    if (lossless_ret == 1) {
6084
101
        LOGGER_TRACE(chat->log, "received out of order packet from peer %d. expected %llu, got %llu", peer_number,
6085
101
                     (unsigned long long)gconn->received_message_id + 1, (unsigned long long)message_id);
6086
101
        mem_delete(chat->mem, data);
6087
101
        return gc_send_message_ack(chat, gconn, gconn->received_message_id + 1, GR_ACK_REQ);
6088
101
    }
6089
6090
    /* handle packet fragment */
6091
13.2k
    if (lossless_ret == 3) {
6092
648
        const bool frag_ret = handle_gc_packet_fragment(c, chat, peer_number, gconn, data, (uint16_t)len, packet_type,
6093
648
                              message_id, userdata);
6094
648
        mem_delete(chat->mem, data);
6095
648
        return frag_ret;
6096
648
    }
6097
6098
12.5k
    const bool ret = handle_gc_lossless_helper(c, chat, peer_number, data, (uint16_t)len, packet_type, userdata);
6099
6100
12.5k
    mem_delete(chat->mem, data);
6101
6102
12.5k
    if (!ret) {
6103
16
        return false;
6104
16
    }
6105
6106
    /* peer number can change from peer add operations in packet handlers */
6107
12.5k
    peer_number = get_peer_number_of_enc_pk(chat, sender_pk, false);
6108
12.5k
    gconn = get_gc_connection(chat, peer_number);
6109
6110
12.5k
    if (gconn != nullptr && lossless_ret == 2) {
6111
12.5k
        gc_send_message_ack(chat, gconn, message_id, GR_ACK_RECV);
6112
12.5k
    }
6113
6114
12.5k
    return true;
6115
12.5k
}
6116
6117
static int handle_gc_lossy_packet_decoded(
6118
    const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn, const GC_Peer *_Nonnull peer,
6119
    uint8_t packet_type, const uint8_t *_Nonnull data, uint16_t payload_len, void *_Nullable userdata)
6120
13.3k
{
6121
13.3k
    switch (packet_type) {
6122
12.9k
        case GP_MESSAGE_ACK: {
6123
12.9k
            return handle_gc_message_ack(chat, gconn, data, payload_len);
6124
0
        }
6125
6126
415
        case GP_PING: {
6127
415
            return handle_gc_ping(chat, gconn, data, payload_len);
6128
0
        }
6129
6130
3
        case GP_INVITE_RESPONSE_REJECT: {
6131
3
            return handle_gc_invite_response_reject(c, chat, data, payload_len, userdata);
6132
0
        }
6133
6134
2
        case GP_CUSTOM_PACKET: {
6135
2
            return handle_gc_custom_packet(c, chat, peer, data, payload_len, false, userdata);
6136
0
        }
6137
6138
1
        case GP_CUSTOM_PRIVATE_PACKET: {
6139
1
            return handle_gc_custom_private_packet(c, chat, peer, data, payload_len, false, userdata);
6140
0
        }
6141
6142
0
        default: {
6143
0
            LOGGER_WARNING(chat->log, "Warning: handling invalid lossy group packet type 0x%02x", packet_type);
6144
0
            return -1;
6145
0
        }
6146
13.3k
    }
6147
13.3k
}
6148
6149
/** @brief Handles lossy groupchat message packets.
6150
 *
6151
 * This function assumes the length has already been validated.
6152
 *
6153
 * Return true if packet is handled successfully.
6154
 */
6155
static bool handle_gc_lossy_packet(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat, const uint8_t *_Nonnull sender_pk,
6156
                                   const uint8_t *_Nonnull packet, uint16_t length, bool direct_conn, void *_Nullable userdata)
6157
13.3k
{
6158
13.3k
    if (length < GC_MIN_LOSSY_PAYLOAD_SIZE) {
6159
0
        return false;
6160
0
    }
6161
6162
13.3k
    const int peer_number = get_peer_number_of_enc_pk(chat, sender_pk, false);
6163
6164
13.3k
    GC_Peer *peer = get_gc_peer(chat, peer_number);
6165
6166
13.3k
    if (peer == nullptr) {
6167
0
        return false;
6168
0
    }
6169
6170
13.3k
    GC_Connection *gconn = &peer->gconn;
6171
6172
13.3k
    if (!gconn->handshaked || gconn->pending_delete) {
6173
0
        LOGGER_DEBUG(chat->log, "Got lossy packet from invalid peer");
6174
0
        return false;
6175
0
    }
6176
6177
13.3k
    uint8_t *data = (uint8_t *)mem_balloc(chat->mem, length);
6178
6179
13.3k
    if (data == nullptr) {
6180
1
        LOGGER_ERROR(chat->log, "Failed to allocate memory for packet buffer");
6181
1
        return false;
6182
1
    }
6183
6184
13.3k
    uint8_t packet_type;
6185
6186
13.3k
    const int len = group_packet_unwrap(chat->log, chat->mem, gconn, data, nullptr, &packet_type, packet, length);
6187
6188
13.3k
    if (len <= 0) {
6189
2
        Ip_Ntoa ip_str;
6190
2
        LOGGER_DEBUG(chat->log, "Failed to unwrap lossy packet from %s:%d: %d",
6191
2
                     net_ip_ntoa(&gconn->addr.ip_port.ip, &ip_str), net_ntohs(gconn->addr.ip_port.port), len);
6192
2
        mem_delete(chat->mem, data);
6193
2
        return false;
6194
2
    }
6195
6196
13.3k
    const int ret = handle_gc_lossy_packet_decoded(c, chat, gconn, peer, packet_type, data, (uint16_t)len, userdata);
6197
6198
13.3k
    mem_delete(chat->mem, data);
6199
6200
13.3k
    if (ret < 0) {
6201
0
        LOGGER_DEBUG(chat->log, "Lossy packet handle error %d: type: 0x%02x, peernumber %d", ret, packet_type,
6202
0
                     peer_number);
6203
0
        return false;
6204
0
    }
6205
6206
13.3k
    const uint64_t tm = mono_time_get(chat->mono_time);
6207
6208
13.3k
    if (direct_conn) {
6209
13.3k
        gconn->last_received_direct_time = tm;
6210
13.3k
    }
6211
6212
13.3k
    gconn->last_received_packet_time = tm;
6213
6214
13.3k
    return true;
6215
13.3k
}
6216
6217
/** @brief Return true if group is either connected or attempting to connect. */
6218
static bool group_can_handle_packets(const GC_Chat *_Nonnull chat)
6219
46.1k
{
6220
46.1k
    const GC_Conn_State state = chat->connection_state;
6221
46.1k
    return state == CS_CONNECTING || state == CS_CONNECTED;
6222
46.1k
}
6223
6224
/** @brief Sends a group packet to appropriate handler function.
6225
 *
6226
 * Returns non-negative value on success.
6227
 * Returns -1 on failure.
6228
 */
6229
0
#define MIN_TCP_PACKET_SIZE (1 + ENC_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE)
6230
static int handle_gc_tcp_packet(void *_Nonnull object, int crypt_connection_id, const uint8_t *_Nonnull packet, uint16_t length, void *_Nullable userdata)
6231
0
{
6232
0
    const Messenger *m = (Messenger *)object;
6233
0
    if (m == nullptr) {
6234
0
        return -1;
6235
0
    }
6236
6237
0
    if (length <= MIN_TCP_PACKET_SIZE) {
6238
0
        LOGGER_WARNING(m->log, "Got tcp packet with invalid length: %u (expected %u to %u)", length,
6239
0
                       (unsigned int)MIN_TCP_PACKET_SIZE, (unsigned int)(MAX_GC_PACKET_INCOMING_CHUNK_SIZE + MIN_TCP_PACKET_SIZE + ENC_PUBLIC_KEY_SIZE));
6240
0
        return -1;
6241
0
    }
6242
6243
0
    if (length > MAX_GC_PACKET_INCOMING_CHUNK_SIZE + MIN_TCP_PACKET_SIZE + ENC_PUBLIC_KEY_SIZE) {
6244
0
        LOGGER_WARNING(m->log, "Got tcp packet with invalid length: %u (expected %u to %u)", length,
6245
0
                       (unsigned int)MIN_TCP_PACKET_SIZE, (unsigned int)(MAX_GC_PACKET_INCOMING_CHUNK_SIZE + MIN_TCP_PACKET_SIZE + ENC_PUBLIC_KEY_SIZE));
6246
0
        return -1;
6247
0
    }
6248
6249
0
    const uint8_t packet_type = packet[0];
6250
6251
0
    const uint8_t *sender_pk = packet + 1;
6252
6253
0
    const GC_Session *c = m->group_handler;
6254
0
    GC_Chat *chat = nullptr;
6255
6256
0
    if (packet_type == NET_PACKET_GC_HANDSHAKE) {
6257
0
        chat = get_chat_by_id(c, packet + 1 + ENC_PUBLIC_KEY_SIZE);
6258
0
    } else {
6259
0
        chat = get_chat_by_id(c, sender_pk);
6260
0
    }
6261
6262
0
    if (chat == nullptr) {
6263
0
        return -1;
6264
0
    }
6265
6266
0
    if (!group_can_handle_packets(chat)) {
6267
0
        return -1;
6268
0
    }
6269
6270
0
    const uint8_t *payload = packet + 1 + ENC_PUBLIC_KEY_SIZE;
6271
0
    uint16_t payload_len = length - 1 - ENC_PUBLIC_KEY_SIZE;
6272
6273
0
    switch (packet_type) {
6274
0
        case NET_PACKET_GC_LOSSLESS: {
6275
0
            if (!handle_gc_lossless_packet(c, chat, sender_pk, payload, payload_len, false, userdata)) {
6276
0
                return -1;
6277
0
            }
6278
6279
0
            return 0;
6280
0
        }
6281
6282
0
        case NET_PACKET_GC_LOSSY: {
6283
0
            if (!handle_gc_lossy_packet(c, chat, sender_pk, payload, payload_len, false, userdata)) {
6284
0
                return -1;
6285
0
            }
6286
6287
0
            return 0;
6288
0
        }
6289
6290
0
        case NET_PACKET_GC_HANDSHAKE: {
6291
            // handshake packets have an extra public key in plaintext header
6292
0
            if (length <= 1 + ENC_PUBLIC_KEY_SIZE + ENC_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE) {
6293
0
                return -1;
6294
0
            }
6295
6296
0
            payload_len = payload_len - ENC_PUBLIC_KEY_SIZE;
6297
0
            payload = payload + ENC_PUBLIC_KEY_SIZE;
6298
6299
0
            return handle_gc_handshake_packet(chat, sender_pk, nullptr, payload, payload_len, false, userdata);
6300
0
        }
6301
6302
0
        default: {
6303
0
            return -1;
6304
0
        }
6305
0
    }
6306
0
}
6307
6308
static int handle_gc_tcp_oob_packet(void *_Nonnull object, const uint8_t *_Nonnull public_key, unsigned int tcp_connections_number,
6309
                                    const uint8_t *_Nonnull packet, uint16_t length, void *_Nullable userdata)
6310
0
{
6311
0
    const Messenger *m = (Messenger *)object;
6312
0
    if (m == nullptr) {
6313
0
        return -1;
6314
0
    }
6315
6316
0
    if (length <= GC_MIN_HS_PACKET_PAYLOAD_SIZE) {
6317
0
        LOGGER_WARNING(m->log, "Got tcp oob packet with invalid length: %u (expected %u to %u)", length,
6318
0
                       (unsigned int)GC_MIN_HS_PACKET_PAYLOAD_SIZE, (unsigned int)(MAX_GC_PACKET_INCOMING_CHUNK_SIZE + CRYPTO_MAC_SIZE + CRYPTO_NONCE_SIZE));
6319
0
        return -1;
6320
0
    }
6321
6322
0
    if (length > MAX_GC_PACKET_INCOMING_CHUNK_SIZE + CRYPTO_MAC_SIZE + CRYPTO_NONCE_SIZE) {
6323
0
        LOGGER_WARNING(m->log, "Got tcp oob packet with invalid length: %u (expected %u to %u)", length,
6324
0
                       (unsigned int)GC_MIN_HS_PACKET_PAYLOAD_SIZE, (unsigned int)(MAX_GC_PACKET_INCOMING_CHUNK_SIZE + CRYPTO_MAC_SIZE + CRYPTO_NONCE_SIZE));
6325
0
        return -1;
6326
0
    }
6327
6328
0
    const GC_Session *c = m->group_handler;
6329
0
    GC_Chat *chat = get_chat_by_id(c, packet + 1 + ENC_PUBLIC_KEY_SIZE);
6330
6331
0
    if (chat == nullptr) {
6332
0
        return -1;
6333
0
    }
6334
6335
0
    if (!group_can_handle_packets(chat)) {
6336
0
        return -1;
6337
0
    }
6338
6339
0
    const uint8_t packet_type = packet[0];
6340
6341
0
    if (packet_type != NET_PACKET_GC_HANDSHAKE) {
6342
0
        return -1;
6343
0
    }
6344
6345
0
    const uint8_t *sender_pk = packet + 1;
6346
6347
0
    const uint8_t *payload = packet + 1 + ENC_PUBLIC_KEY_SIZE + ENC_PUBLIC_KEY_SIZE;
6348
0
    const uint16_t payload_len = length - 1 - ENC_PUBLIC_KEY_SIZE - ENC_PUBLIC_KEY_SIZE;
6349
6350
0
    if (payload_len < GC_MIN_HS_PACKET_PAYLOAD_SIZE + CRYPTO_MAC_SIZE + CRYPTO_NONCE_SIZE) {
6351
0
        return -1;
6352
0
    }
6353
6354
0
    if (handle_gc_handshake_packet(chat, sender_pk, nullptr, payload, payload_len, false, userdata) == -1) {
6355
0
        return -1;
6356
0
    }
6357
6358
0
    return 0;
6359
0
}
6360
6361
55.7k
#define MIN_UDP_PACKET_SIZE (1 + ENC_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE)
6362
static int handle_gc_udp_packet(void *_Nonnull object, const IP_Port *_Nonnull source, const uint8_t *_Nonnull packet, uint16_t length,
6363
                                void *_Nullable userdata)
6364
27.8k
{
6365
27.8k
    const Messenger *m = (Messenger *)object;
6366
27.8k
    if (m == nullptr) {
6367
0
        return -1;
6368
0
    }
6369
6370
27.8k
    if (length <= MIN_UDP_PACKET_SIZE) {
6371
0
        LOGGER_WARNING(m->log, "Got UDP packet with invalid length: %u (expected %u to %u)", length,
6372
0
                       (unsigned int)MIN_UDP_PACKET_SIZE, (unsigned int)(MAX_GC_PACKET_INCOMING_CHUNK_SIZE + MIN_UDP_PACKET_SIZE + ENC_PUBLIC_KEY_SIZE));
6373
0
        return -1;
6374
0
    }
6375
6376
27.8k
    if (length > MAX_GC_PACKET_INCOMING_CHUNK_SIZE + MIN_UDP_PACKET_SIZE + ENC_PUBLIC_KEY_SIZE) {
6377
0
        LOGGER_WARNING(m->log, "Got UDP packet with invalid length: %u (expected %u to %u)", length,
6378
0
                       (unsigned int)MIN_UDP_PACKET_SIZE, (unsigned int)(MAX_GC_PACKET_INCOMING_CHUNK_SIZE + MIN_UDP_PACKET_SIZE + ENC_PUBLIC_KEY_SIZE));
6379
0
        return -1;
6380
0
    }
6381
6382
27.8k
    const uint8_t packet_type = packet[0];
6383
27.8k
    const uint8_t *sender_pk = packet + 1;
6384
6385
27.8k
    const GC_Session *c = m->group_handler;
6386
27.8k
    GC_Chat *chat = nullptr;
6387
6388
27.8k
    if (packet_type == NET_PACKET_GC_HANDSHAKE) {
6389
662
        chat = get_chat_by_id(c, packet + 1 + ENC_PUBLIC_KEY_SIZE);
6390
27.2k
    } else {
6391
27.2k
        chat = get_chat_by_id(c, sender_pk);
6392
27.2k
    }
6393
6394
27.8k
    if (chat == nullptr) {
6395
14
        return -1;
6396
14
    }
6397
6398
27.8k
    if (!group_can_handle_packets(chat)) {
6399
215
        return -1;
6400
215
    }
6401
6402
27.6k
    const uint8_t *payload = packet + 1 + ENC_PUBLIC_KEY_SIZE;
6403
27.6k
    uint16_t payload_len = length - 1 - ENC_PUBLIC_KEY_SIZE;
6404
27.6k
    bool ret = false;
6405
6406
27.6k
    switch (packet_type) {
6407
13.8k
        case NET_PACKET_GC_LOSSLESS: {
6408
13.8k
            ret = handle_gc_lossless_packet(c, chat, sender_pk, payload, payload_len, true, userdata);
6409
13.8k
            break;
6410
0
        }
6411
6412
13.3k
        case NET_PACKET_GC_LOSSY: {
6413
13.3k
            ret = handle_gc_lossy_packet(c, chat, sender_pk, payload, payload_len, true, userdata);
6414
13.3k
            break;
6415
0
        }
6416
6417
448
        case NET_PACKET_GC_HANDSHAKE: {
6418
            // handshake packets have an extra public key in plaintext header
6419
448
            if (length <= 1 + ENC_PUBLIC_KEY_SIZE + ENC_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE) {
6420
0
                return -1;
6421
0
            }
6422
6423
448
            payload_len = payload_len - ENC_PUBLIC_KEY_SIZE;
6424
448
            payload = payload + ENC_PUBLIC_KEY_SIZE;
6425
6426
448
            ret = handle_gc_handshake_packet(chat, sender_pk, source, payload, payload_len, true, userdata) != -1;
6427
448
            break;
6428
448
        }
6429
6430
0
        default: {
6431
0
            return -1;
6432
448
        }
6433
27.6k
    }
6434
6435
27.6k
    return ret ? 0 : -1;
6436
27.6k
}
6437
6438
void gc_callback_message(const Messenger *m, gc_message_cb *function)
6439
2.37k
{
6440
2.37k
    GC_Session *c = m->group_handler;
6441
2.37k
    c->message = function;
6442
2.37k
}
6443
6444
void gc_callback_private_message(const Messenger *m, gc_private_message_cb *function)
6445
2.37k
{
6446
2.37k
    GC_Session *c = m->group_handler;
6447
2.37k
    c->private_message = function;
6448
2.37k
}
6449
6450
void gc_callback_custom_packet(const Messenger *m, gc_custom_packet_cb *function)
6451
2.37k
{
6452
2.37k
    GC_Session *c = m->group_handler;
6453
2.37k
    c->custom_packet = function;
6454
2.37k
}
6455
6456
void gc_callback_custom_private_packet(const Messenger *m, gc_custom_private_packet_cb *function)
6457
2.37k
{
6458
2.37k
    GC_Session *c = m->group_handler;
6459
2.37k
    c->custom_private_packet = function;
6460
2.37k
}
6461
6462
void gc_callback_moderation(const Messenger *m, gc_moderation_cb *function)
6463
2.37k
{
6464
2.37k
    GC_Session *c = m->group_handler;
6465
2.37k
    c->moderation = function;
6466
2.37k
}
6467
6468
void gc_callback_nick_change(const Messenger *m, gc_nick_change_cb *function)
6469
2.37k
{
6470
2.37k
    GC_Session *c = m->group_handler;
6471
2.37k
    c->nick_change = function;
6472
2.37k
}
6473
6474
void gc_callback_status_change(const Messenger *m, gc_status_change_cb *function)
6475
2.37k
{
6476
2.37k
    GC_Session *c = m->group_handler;
6477
2.37k
    c->status_change = function;
6478
2.37k
}
6479
6480
void gc_callback_topic_change(const Messenger *m, gc_topic_change_cb *function)
6481
2.37k
{
6482
2.37k
    GC_Session *c = m->group_handler;
6483
2.37k
    c->topic_change = function;
6484
2.37k
}
6485
6486
void gc_callback_topic_lock(const Messenger *m, gc_topic_lock_cb *function)
6487
2.37k
{
6488
2.37k
    GC_Session *c = m->group_handler;
6489
2.37k
    c->topic_lock = function;
6490
2.37k
}
6491
6492
void gc_callback_voice_state(const Messenger *m, gc_voice_state_cb *function)
6493
2.37k
{
6494
2.37k
    GC_Session *c = m->group_handler;
6495
2.37k
    c->voice_state = function;
6496
2.37k
}
6497
6498
void gc_callback_peer_limit(const Messenger *m, gc_peer_limit_cb *function)
6499
2.37k
{
6500
2.37k
    GC_Session *c = m->group_handler;
6501
2.37k
    c->peer_limit = function;
6502
2.37k
}
6503
6504
void gc_callback_privacy_state(const Messenger *m, gc_privacy_state_cb *function)
6505
2.37k
{
6506
2.37k
    GC_Session *c = m->group_handler;
6507
2.37k
    c->privacy_state = function;
6508
2.37k
}
6509
6510
void gc_callback_password(const Messenger *m, gc_password_cb *function)
6511
2.37k
{
6512
2.37k
    GC_Session *c = m->group_handler;
6513
2.37k
    c->password = function;
6514
2.37k
}
6515
6516
void gc_callback_peer_join(const Messenger *m, gc_peer_join_cb *function)
6517
2.37k
{
6518
2.37k
    GC_Session *c = m->group_handler;
6519
2.37k
    c->peer_join = function;
6520
2.37k
}
6521
6522
void gc_callback_peer_exit(const Messenger *m, gc_peer_exit_cb *function)
6523
2.37k
{
6524
2.37k
    GC_Session *c = m->group_handler;
6525
2.37k
    c->peer_exit = function;
6526
2.37k
}
6527
6528
void gc_callback_self_join(const Messenger *m, gc_self_join_cb *function)
6529
2.37k
{
6530
2.37k
    GC_Session *c = m->group_handler;
6531
2.37k
    c->self_join = function;
6532
2.37k
}
6533
6534
void gc_callback_rejected(const Messenger *m, gc_rejected_cb *function)
6535
2.37k
{
6536
2.37k
    GC_Session *c = m->group_handler;
6537
2.37k
    c->rejected = function;
6538
2.37k
}
6539
6540
/** @brief Deletes peer_number from group.
6541
 *
6542
 * `no_callback` should be set to true if the `peer_exit` callback
6543
 * should not be triggered.
6544
 *
6545
 * Return true on success.
6546
 */
6547
static bool peer_delete(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat, uint32_t peer_number, void *_Nullable userdata)
6548
161
{
6549
161
    GC_Peer *peer = get_gc_peer(chat, peer_number);
6550
161
    if (peer == nullptr) {
6551
0
        return false;
6552
0
    }
6553
6554
161
    GC_Connection *gconn = &peer->gconn;
6555
6556
    // We need to save some peer info for the callback before deleting it
6557
161
    const bool peer_confirmed = gconn->confirmed;
6558
161
    const GC_Peer_Id peer_id = peer->peer_id;
6559
161
    uint8_t nick[MAX_GC_NICK_SIZE];
6560
161
    const uint16_t nick_length = peer->nick_length;
6561
161
    const GC_Exit_Info exit_info = gconn->exit_info;
6562
6563
161
    assert(nick_length <= MAX_GC_NICK_SIZE);
6564
161
    memcpy(nick, peer->nick, nick_length);
6565
6566
161
    if (exit_info.exit_type == GC_EXIT_TYPE_KICKED) {
6567
3
        saved_peers_remove_entry(chat, gconn->addr.public_key.enc);
6568
3
    }
6569
6570
161
    gcc_peer_cleanup(chat->mem, gconn);
6571
6572
161
    --chat->numpeers;
6573
6574
161
    if (chat->numpeers != peer_number) {
6575
102
        chat->group[peer_number] = chat->group[chat->numpeers];
6576
102
    }
6577
6578
161
    chat->group[chat->numpeers] = (GC_Peer) {
6579
161
        0
6580
161
    };
6581
6582
161
    GC_Peer *tmp_group = (GC_Peer *)mem_vrealloc(chat->mem, chat->group, chat->numpeers, sizeof(GC_Peer));
6583
6584
161
    if (tmp_group == nullptr) {
6585
0
        return false;
6586
0
    }
6587
6588
161
    chat->group = tmp_group;
6589
6590
161
    set_gc_peerlist_checksum(chat);
6591
6592
161
    if (peer_confirmed) {
6593
9
        refresh_gc_saved_peers(chat);
6594
9
    }
6595
6596
161
    if (exit_info.exit_type != GC_EXIT_TYPE_NO_CALLBACK && c->peer_exit != nullptr && peer_confirmed) {
6597
8
        c->peer_exit(c->messenger, chat->group_number, peer_id, exit_info.exit_type, nick,
6598
8
                     nick_length, exit_info.part_message, exit_info.length, userdata);
6599
8
    }
6600
6601
161
    return true;
6602
161
}
6603
6604
/** @brief Updates peer_number with info from `peer` and validates peer data.
6605
 *
6606
 * Returns peer_number on success.
6607
 * Returns -1 on failure.
6608
 */
6609
static int peer_update(const GC_Chat *chat, const GC_Peer *peer, uint32_t peer_number)
6610
413
{
6611
413
    if (peer->nick_length == 0) {
6612
0
        return -1;
6613
0
    }
6614
6615
413
    if (peer->status > GS_BUSY) {
6616
0
        return -1;
6617
0
    }
6618
6619
413
    if (peer->role > GR_OBSERVER) {
6620
0
        return -1;
6621
0
    }
6622
6623
413
    GC_Peer *curr_peer = get_gc_peer(chat, peer_number);
6624
413
    assert(curr_peer != nullptr);
6625
6626
413
    curr_peer->status = peer->status;
6627
413
    curr_peer->nick_length = peer->nick_length;
6628
6629
413
    memcpy(curr_peer->nick, peer->nick, peer->nick_length);
6630
6631
413
    return peer_number;
6632
413
}
6633
6634
int peer_add(GC_Chat *chat, const IP_Port *ipp, const uint8_t *public_key)
6635
5.26k
{
6636
5.26k
    if (get_peer_number_of_enc_pk(chat, public_key, false) != -1) {
6637
4.43k
        return -2;
6638
4.43k
    }
6639
6640
823
    const GC_Peer_Id peer_id = get_new_peer_id(chat);
6641
6642
823
    if (!gc_peer_id_is_valid(peer_id)) {
6643
0
        LOGGER_WARNING(chat->log, "Failed to add peer: all peer ID's are taken?");
6644
0
        return -1;
6645
0
    }
6646
6647
823
    const int peer_number = chat->numpeers;
6648
823
    int tcp_connection_num = -1;
6649
6650
823
    if (peer_number > 0) {  // we don't need a connection to ourself
6651
445
        tcp_connection_num = new_tcp_connection_to(chat->tcp_conn, public_key, 0);
6652
6653
445
        if (tcp_connection_num == -1) {
6654
2
            LOGGER_WARNING(chat->log, "Failed to init tcp connection for peer %d", peer_number);
6655
2
        }
6656
445
    }
6657
6658
823
    GC_Message_Array_Entry *send = (GC_Message_Array_Entry *)mem_valloc(chat->mem, GCC_BUFFER_SIZE, sizeof(GC_Message_Array_Entry));
6659
823
    GC_Message_Array_Entry *recv = (GC_Message_Array_Entry *)mem_valloc(chat->mem, GCC_BUFFER_SIZE, sizeof(GC_Message_Array_Entry));
6660
6661
823
    if (send == nullptr || recv == nullptr) {
6662
4
        LOGGER_ERROR(chat->log, "Failed to allocate memory for gconn buffers");
6663
6664
4
        if (tcp_connection_num != -1) {
6665
0
            kill_tcp_connection_to(chat->tcp_conn, tcp_connection_num);
6666
0
        }
6667
6668
4
        mem_delete(chat->mem, send);
6669
4
        mem_delete(chat->mem, recv);
6670
4
        return -1;
6671
4
    }
6672
6673
819
    GC_Peer *tmp_group = (GC_Peer *)mem_vrealloc(chat->mem, chat->group, chat->numpeers + 1, sizeof(GC_Peer));
6674
6675
819
    if (tmp_group == nullptr) {
6676
3
        LOGGER_ERROR(chat->log, "Failed to allocate memory for group mem_vrealloc");
6677
6678
3
        if (tcp_connection_num != -1) {
6679
1
            kill_tcp_connection_to(chat->tcp_conn, tcp_connection_num);
6680
1
        }
6681
6682
3
        mem_delete(chat->mem, send);
6683
3
        mem_delete(chat->mem, recv);
6684
3
        return -1;
6685
3
    }
6686
6687
816
    ++chat->numpeers;
6688
816
    chat->group = tmp_group;
6689
6690
816
    chat->group[peer_number] = (GC_Peer) {
6691
816
        0
6692
816
    };
6693
6694
816
    GC_Connection *gconn = &chat->group[peer_number].gconn;
6695
6696
816
    gconn->send_array = send;
6697
816
    gconn->recv_array = recv;
6698
6699
816
    gcc_set_ip_port(gconn, ipp);
6700
816
    chat->group[peer_number].role = GR_USER;
6701
816
    chat->group[peer_number].peer_id = peer_id;
6702
816
    chat->group[peer_number].ignore = false;
6703
6704
816
    crypto_memlock(gconn->session_secret_key, sizeof(gconn->session_secret_key));
6705
6706
816
    create_gc_session_keypair(chat->log, chat->rng, gconn->session_public_key, gconn->session_secret_key);
6707
6708
816
    if (peer_number > 0) {
6709
442
        memcpy(gconn->addr.public_key.enc, public_key, ENC_PUBLIC_KEY_SIZE);  // we get the sig key in the handshake
6710
442
    } else {
6711
374
        gconn->addr.public_key = chat->self_public_key;
6712
374
    }
6713
6714
816
    const uint64_t tm = mono_time_get(chat->mono_time);
6715
6716
816
    gcc_set_send_message_id(gconn, 1);
6717
816
    gconn->public_key_hash = gc_get_pk_jenkins_hash(public_key);
6718
816
    gconn->last_received_packet_time = tm;
6719
816
    gconn->last_key_rotation = tm;
6720
816
    gconn->tcp_connection_num = tcp_connection_num;
6721
816
    gconn->last_sent_ip_time = tm;
6722
816
    gconn->last_sent_ping_time = tm - (GC_PING_TIMEOUT / 2) + (peer_number % (GC_PING_TIMEOUT / 2));
6723
816
    gconn->self_is_closer = id_closest(get_chat_id(&chat->chat_public_key),
6724
816
                                       get_enc_key(&chat->self_public_key),
6725
816
                                       get_enc_key(&gconn->addr.public_key)) == 1;
6726
816
    return peer_number;
6727
819
}
6728
6729
/** @brief Copies own peer data to `peer`. */
6730
static void copy_self(const GC_Chat *_Nonnull chat, GC_Peer *_Nonnull peer)
6731
425
{
6732
425
    *peer = (GC_Peer) {
6733
425
        0
6734
425
    };
6735
6736
425
    peer->status = gc_get_self_status(chat);
6737
425
    gc_get_self_nick(chat, peer->nick);
6738
425
    peer->nick_length = gc_get_self_nick_size(chat);
6739
425
    peer->role = gc_get_self_role(chat);
6740
425
}
6741
6742
/** @brief Returns true if we haven't received a ping from this peer after n seconds.
6743
 * n depends on whether or not the peer has been confirmed.
6744
 */
6745
static bool peer_timed_out(const Mono_Time *_Nonnull mono_time, const GC_Connection *_Nonnull gconn)
6746
38.7k
{
6747
38.7k
    return mono_time_is_timeout(mono_time, gconn->last_received_packet_time, gconn->confirmed
6748
38.7k
                                ? GC_CONFIRMED_PEER_TIMEOUT
6749
38.7k
                                : GC_UNCONFIRMED_PEER_TIMEOUT);
6750
38.7k
}
6751
6752
/** @brief Attempts to send pending handshake packets to peer designated by `gconn`.
6753
 *
6754
 * One request of each type can be sent per `GC_SEND_HANDSHAKE_INTERVAL` seconds.
6755
 *
6756
 * Return true on success.
6757
 */
6758
static bool send_pending_handshake(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn)
6759
3.44k
{
6760
3.44k
    if (chat == nullptr || gconn == nullptr) {
6761
0
        return false;
6762
0
    }
6763
6764
3.44k
    if (gconn->is_pending_handshake_response) {
6765
184
        if (!mono_time_is_timeout(chat->mono_time, gconn->last_handshake_response, GC_SEND_HANDSHAKE_INTERVAL)) {
6766
0
            return true;
6767
0
        }
6768
6769
184
        gconn->last_handshake_response = mono_time_get(chat->mono_time);
6770
6771
184
        return send_gc_handshake_response(chat, gconn);
6772
184
    }
6773
6774
3.25k
    if (!mono_time_is_timeout(chat->mono_time, gconn->last_handshake_request, GC_SEND_HANDSHAKE_INTERVAL)) {
6775
2.78k
        return true;
6776
2.78k
    }
6777
6778
479
    gconn->last_handshake_request = mono_time_get(chat->mono_time);
6779
6780
479
    if (gconn->is_oob_handshake) {
6781
0
        return send_gc_oob_handshake_request(chat, gconn);
6782
0
    }
6783
6784
479
    return send_gc_handshake_packet(chat, gconn, GH_REQUEST, gconn->pending_handshake_type, chat->join_type);
6785
479
}
6786
6787
0
#define GC_TCP_RELAY_SEND_INTERVAL (60 * 3)
6788
static void do_peer_connections(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat, void *_Nullable userdata)
6789
13.7k
{
6790
52.6k
    for (uint32_t i = 1; i < chat->numpeers; ++i) {
6791
38.9k
        GC_Connection *gconn = get_gc_connection(chat, i);
6792
38.9k
        assert(gconn != nullptr);
6793
6794
38.9k
        if (gconn->pending_delete) {
6795
195
            continue;
6796
195
        }
6797
6798
38.7k
        if (peer_timed_out(chat->mono_time, gconn)) {
6799
147
            gcc_mark_for_deletion(gconn, chat->tcp_conn, GC_EXIT_TYPE_TIMEOUT, nullptr, 0);
6800
147
            continue;
6801
147
        }
6802
6803
38.6k
        gcc_resend_packets(chat, gconn);
6804
6805
38.6k
        if (gconn->tcp_relays_count > 0 &&
6806
38.6k
                mono_time_is_timeout(chat->mono_time, gconn->last_sent_tcp_relays_time, GC_TCP_RELAY_SEND_INTERVAL)) {
6807
0
            if (gconn->confirmed) {
6808
0
                send_gc_tcp_relays(chat, gconn);
6809
0
                gconn->last_sent_tcp_relays_time = mono_time_get(chat->mono_time);
6810
0
            }
6811
0
        }
6812
6813
38.6k
        gcc_check_recv_array(c, chat, gconn, i, userdata);   // may change peer numbers
6814
38.6k
    }
6815
13.7k
}
6816
6817
/** @brief Executes pending handshakes for peers.
6818
 *
6819
 * If our peerlist is empty we periodically try to
6820
 * load peers from our saved peers list and initiate handshake requests with them.
6821
 */
6822
236
#define LOAD_PEERS_TIMEOUT (GC_UNCONFIRMED_PEER_TIMEOUT + 10)
6823
static void do_handshakes(GC_Chat *_Nonnull chat)
6824
13.7k
{
6825
52.6k
    for (uint32_t i = 1; i < chat->numpeers; ++i) {
6826
38.9k
        GC_Connection *gconn = get_gc_connection(chat, i);
6827
38.9k
        assert(gconn != nullptr);
6828
6829
38.9k
        if (gconn->handshaked || gconn->pending_delete) {
6830
35.5k
            continue;
6831
35.5k
        }
6832
6833
3.44k
        send_pending_handshake(chat, gconn);
6834
3.44k
    }
6835
6836
13.7k
    if (chat->numpeers <= 1) {
6837
236
        const uint64_t tm = mono_time_get(chat->mono_time);
6838
6839
236
        if (mono_time_is_timeout(chat->mono_time, chat->last_time_peers_loaded, LOAD_PEERS_TIMEOUT)) {
6840
129
            load_gc_peers(chat, chat->saved_peers, GC_MAX_SAVED_PEERS);
6841
129
            chat->last_time_peers_loaded = tm;
6842
129
        }
6843
236
    }
6844
13.7k
}
6845
6846
/** @brief Adds `gconn` to the group timeout list. */
6847
static void add_gc_peer_timeout_list(GC_Chat *_Nonnull chat, const GC_Connection *_Nonnull gconn)
6848
0
{
6849
0
    const size_t idx = chat->timeout_list_index;
6850
0
    const uint64_t tm = mono_time_get(chat->mono_time);
6851
6852
0
    copy_gc_saved_peer(chat->rng, gconn, &chat->timeout_list[idx].addr);
6853
6854
0
    chat->timeout_list[idx].last_seen = tm;
6855
0
    chat->timeout_list[idx].last_reconn_try = 0;
6856
0
    chat->timeout_list_index = (idx + 1) % MAX_GC_SAVED_TIMEOUTS;
6857
0
}
6858
6859
static void do_peer_delete(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat, void *_Nullable userdata)
6860
15.1k
{
6861
63.3k
    for (uint32_t i = 1; i < chat->numpeers; ++i) {
6862
48.2k
        GC_Connection *gconn = get_gc_connection(chat, i);
6863
48.2k
        assert(gconn != nullptr);
6864
6865
48.2k
        if (!gconn->pending_delete) {
6866
47.9k
            continue;
6867
47.9k
        }
6868
6869
338
        if (!gconn->delete_this_iteration) {
6870
177
            gconn->delete_this_iteration = true;
6871
177
            continue;
6872
177
        }
6873
6874
161
        const GC_Exit_Info *exit_info = &gconn->exit_info;
6875
6876
161
        if (exit_info->exit_type == GC_EXIT_TYPE_TIMEOUT && gconn->confirmed) {
6877
0
            add_gc_peer_timeout_list(chat, gconn);
6878
0
        }
6879
6880
161
        if (!peer_delete(c, chat, i, userdata)) {
6881
0
            LOGGER_ERROR(chat->log, "Failed to delete peer %u", i);
6882
0
        }
6883
6884
161
        if (i >= chat->numpeers) {
6885
59
            break;
6886
59
        }
6887
161
    }
6888
15.1k
}
6889
6890
/** @brief Constructs and sends a ping packet to `gconn` containing info needed for group syncing
6891
 * and connection maintenance.
6892
 *
6893
 * Return true on success.
6894
 */
6895
static bool ping_peer(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn)
6896
415
{
6897
415
    const uint16_t buf_size = GC_PING_PACKET_MIN_DATA_SIZE + sizeof(IP_Port);
6898
415
    uint8_t *data = (uint8_t *)mem_balloc(chat->mem, buf_size);
6899
6900
415
    if (data == nullptr) {
6901
0
        return false;
6902
0
    }
6903
6904
415
    const uint16_t roles_checksum = chat->moderation.sanctions_creds.checksum + chat->roles_checksum;
6905
415
    uint16_t packed_len = 0;
6906
6907
415
    net_pack_u16(data, chat->peers_checksum);
6908
415
    packed_len += sizeof(uint16_t);
6909
6910
415
    net_pack_u16(data + packed_len, get_gc_confirmed_numpeers(chat));
6911
415
    packed_len += sizeof(uint16_t);
6912
6913
415
    net_pack_u32(data + packed_len, chat->shared_state.version);
6914
415
    packed_len += sizeof(uint32_t);
6915
6916
415
    net_pack_u32(data + packed_len, chat->moderation.sanctions_creds.version);
6917
415
    packed_len += sizeof(uint32_t);
6918
6919
415
    net_pack_u16(data + packed_len, roles_checksum);
6920
415
    packed_len += sizeof(uint16_t);
6921
6922
415
    net_pack_u32(data + packed_len, chat->topic_info.version);
6923
415
    packed_len += sizeof(uint32_t);
6924
6925
415
    net_pack_u16(data + packed_len, chat->topic_info.checksum);
6926
415
    packed_len += sizeof(uint16_t);
6927
6928
415
    if (packed_len != GC_PING_PACKET_MIN_DATA_SIZE) {
6929
0
        LOGGER_FATAL(chat->log, "Packed length is impossible");
6930
0
    }
6931
6932
415
    if (chat->self_udp_status == SELF_UDP_STATUS_WAN && !gcc_conn_is_direct(chat->mono_time, gconn)
6933
415
            && mono_time_is_timeout(chat->mono_time, gconn->last_sent_ip_time, GC_SEND_IP_PORT_INTERVAL)) {
6934
6935
0
        const int packed_ipp_len = pack_ip_port(chat->log, data + buf_size - sizeof(IP_Port), sizeof(IP_Port),
6936
0
                                                &chat->self_ip_port);
6937
6938
0
        if (packed_ipp_len > 0) {
6939
0
            packed_len += packed_ipp_len;
6940
0
        }
6941
0
    }
6942
6943
415
    if (!send_lossy_group_packet(chat, gconn, data, packed_len, GP_PING)) {
6944
0
        mem_delete(chat->mem, data);
6945
0
        return false;
6946
0
    }
6947
6948
415
    mem_delete(chat->mem, data);
6949
6950
415
    return true;
6951
415
}
6952
6953
/**
6954
 * Sends a ping packet to peers that haven't been pinged in at least GC_PING_TIMEOUT seconds, and
6955
 * a key rotation request to peers with whom we haven't refreshed keys in at least GC_KEY_ROTATION_TIMEOUT
6956
 * seconds.
6957
 *
6958
 * Ping packet always includes your confirmed peer count, a peer list checksum, your shared state and sanctions
6959
 * list version for syncing purposes. We also occasionally try to send our own IP info to peers that we
6960
 * do not have a direct connection with.
6961
 */
6962
11.9k
#define GC_DO_PINGS_INTERVAL 2
6963
static void do_gc_ping_and_key_rotation(GC_Chat *_Nonnull chat)
6964
11.9k
{
6965
11.9k
    if (!mono_time_is_timeout(chat->mono_time, chat->last_ping_interval, GC_DO_PINGS_INTERVAL)) {
6966
10.6k
        return;
6967
10.6k
    }
6968
6969
1.28k
    const uint64_t tm = mono_time_get(chat->mono_time);
6970
6971
5.12k
    for (uint32_t i = 1; i < chat->numpeers; ++i) {
6972
3.83k
        GC_Connection *gconn = get_gc_connection(chat, i);
6973
3.83k
        assert(gconn != nullptr);
6974
6975
3.83k
        if (!gconn->confirmed) {
6976
1.36k
            continue;
6977
1.36k
        }
6978
6979
2.46k
        if (mono_time_is_timeout(chat->mono_time, gconn->last_sent_ping_time, GC_PING_TIMEOUT)) {
6980
415
            if (ping_peer(chat, gconn)) {
6981
415
                gconn->last_sent_ping_time = tm;
6982
415
            }
6983
415
        }
6984
6985
2.46k
        if (mono_time_is_timeout(chat->mono_time, gconn->last_key_rotation, GC_KEY_ROTATION_TIMEOUT)) {
6986
0
            if (send_peer_key_rotation_request(chat, gconn)) {
6987
0
                gconn->last_key_rotation = tm;
6988
0
            }
6989
0
        }
6990
2.46k
    }
6991
6992
1.28k
    chat->last_ping_interval = tm;
6993
1.28k
}
6994
6995
static void do_new_connection_cooldown(GC_Chat *_Nonnull chat)
6996
15.1k
{
6997
15.1k
    if (chat->connection_o_metre == 0) {
6998
14.7k
        return;
6999
14.7k
    }
7000
7001
371
    const uint64_t tm = mono_time_get(chat->mono_time);
7002
7003
371
    if (chat->connection_cooldown_timer < tm) {
7004
264
        chat->connection_cooldown_timer = tm;
7005
264
        --chat->connection_o_metre;
7006
7007
264
        if (chat->connection_o_metre == 0 && chat->block_handshakes) {
7008
0
            chat->block_handshakes = false;
7009
0
            LOGGER_DEBUG(chat->log, "Unblocking handshakes");
7010
0
        }
7011
264
    }
7012
371
}
7013
7014
13.7k
#define TCP_RELAYS_CHECK_INTERVAL 10
7015
static void do_gc_tcp(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat, void *_Nullable userdata)
7016
13.7k
{
7017
13.7k
    if (chat->tcp_conn == nullptr || !group_can_handle_packets(chat)) {
7018
0
        return;
7019
0
    }
7020
7021
13.7k
    do_tcp_connections(chat->log, chat->tcp_conn, userdata);
7022
7023
52.6k
    for (uint32_t i = 1; i < chat->numpeers; ++i) {
7024
38.9k
        const GC_Connection *gconn = get_gc_connection(chat, i);
7025
38.9k
        assert(gconn != nullptr);
7026
7027
38.9k
        const bool tcp_set = !gcc_conn_is_direct(chat->mono_time, gconn);
7028
38.9k
        set_tcp_connection_to_status(chat->tcp_conn, gconn->tcp_connection_num, tcp_set);
7029
38.9k
    }
7030
7031
13.7k
    if (mono_time_is_timeout(chat->mono_time, chat->last_checked_tcp_relays, TCP_RELAYS_CHECK_INTERVAL)
7032
13.7k
            && tcp_connected_relays_count(chat->tcp_conn) != chat->connected_tcp_relays) {
7033
0
        add_tcp_relays_to_chat(c, chat);
7034
0
        chat->connected_tcp_relays = tcp_connected_relays_count(chat->tcp_conn);
7035
0
        chat->last_checked_tcp_relays = mono_time_get(chat->mono_time);
7036
0
    }
7037
13.7k
}
7038
7039
/**
7040
 * Updates our TCP and UDP connection status and flags a new announcement if our connection has
7041
 * changed and we have either a UDP or TCP connection.
7042
 */
7043
13.7k
#define GC_SELF_CONNECTION_CHECK_INTERVAL 5  // how often in seconds we should run this function
7044
0
#define GC_SELF_REFRESH_ANNOUNCE_INTERVAL (60 * 20)  // how often in seconds we force refresh our group announcement
7045
static void do_self_connection(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat)
7046
13.7k
{
7047
13.7k
    if (!mono_time_is_timeout(chat->mono_time, chat->last_self_announce_check, GC_SELF_CONNECTION_CHECK_INTERVAL)) {
7048
13.0k
        return;
7049
13.0k
    }
7050
7051
636
    const unsigned int self_udp_status = ipport_self_copy(c->messenger->dht, &chat->self_ip_port);
7052
636
    const bool udp_change = (chat->self_udp_status != self_udp_status) && (self_udp_status != SELF_UDP_STATUS_NONE);
7053
7054
    // We flag a group announce if our UDP status has changed since last run, or if our last announced TCP
7055
    // relay is no longer valid. Additionally, we will always flag an announce in the specified interval
7056
    // regardless of the prior conditions. Private groups are never announced.
7057
636
    if (is_public_chat(chat) &&
7058
636
            ((udp_change || !tcp_relay_is_valid(chat->tcp_conn, chat->announced_tcp_relay_pk))
7059
454
             || mono_time_is_timeout(chat->mono_time, chat->last_time_self_announce, GC_SELF_REFRESH_ANNOUNCE_INTERVAL))) {
7060
454
        chat->update_self_announces = true;
7061
454
    }
7062
7063
636
    chat->self_udp_status = (Self_UDP_Status) self_udp_status;
7064
636
    chat->last_self_announce_check = mono_time_get(chat->mono_time);
7065
636
}
7066
7067
/** @brief Attempts to initiate a new connection with peers in the timeout list.
7068
 *
7069
 * This function is not used for public groups as the DHT and group sync mechanism
7070
 * should automatically do this for us.
7071
 */
7072
3.79k
#define TIMED_OUT_RECONN_INTERVAL 2
7073
static void do_timed_out_reconn(GC_Chat *_Nonnull chat)
7074
11.9k
{
7075
11.9k
    if (is_public_chat(chat)) {
7076
8.17k
        return;
7077
8.17k
    }
7078
7079
3.79k
    if (!mono_time_is_timeout(chat->mono_time, chat->last_timed_out_reconn_try, TIMED_OUT_RECONN_INTERVAL)) {
7080
3.32k
        return;
7081
3.32k
    }
7082
7083
477
    const uint64_t curr_time = mono_time_get(chat->mono_time);
7084
7085
6.20k
    for (size_t i = 0; i < MAX_GC_SAVED_TIMEOUTS; ++i) {
7086
5.72k
        GC_TimedOutPeer *timeout = &chat->timeout_list[i];
7087
7088
5.72k
        if (timeout->last_seen == 0 || timeout->last_seen == curr_time) {
7089
5.72k
            continue;
7090
5.72k
        }
7091
7092
0
        if (mono_time_is_timeout(chat->mono_time, timeout->last_seen, GC_TIMED_OUT_STALE_TIMEOUT)
7093
0
                || get_peer_number_of_enc_pk(chat, timeout->addr.public_key, true) != -1) {
7094
0
            *timeout = (GC_TimedOutPeer) {
7095
0
                {{
7096
0
                        0
7097
0
                    }
7098
0
                }
7099
0
            };
7100
0
            continue;
7101
0
        }
7102
7103
0
        if (mono_time_is_timeout(chat->mono_time, timeout->last_reconn_try, GC_TIMED_OUT_RECONN_TIMEOUT)) {
7104
0
            if (load_gc_peers(chat, &timeout->addr, 1) != 1) {
7105
0
                LOGGER_WARNING(chat->log, "Failed to load timed out peer");
7106
0
            }
7107
7108
0
            timeout->last_reconn_try = curr_time;
7109
0
        }
7110
0
    }
7111
7112
477
    chat->last_timed_out_reconn_try = curr_time;
7113
477
}
7114
7115
void do_gc(GC_Session *c, void *userdata)
7116
129k
{
7117
129k
    if (c == nullptr) {
7118
0
        return;
7119
0
    }
7120
7121
144k
    for (uint32_t i = 0; i < c->chats_index; ++i) {
7122
15.1k
        GC_Chat *chat = &c->chats[i];
7123
7124
15.1k
        const GC_Conn_State state = chat->connection_state;
7125
7126
15.1k
        if (state == CS_NONE) {
7127
0
            continue;
7128
0
        }
7129
7130
15.1k
        if (state != CS_DISCONNECTED) {
7131
13.7k
            do_peer_connections(c, chat, userdata);
7132
13.7k
            do_gc_tcp(c, chat, userdata);
7133
13.7k
            do_handshakes(chat);
7134
13.7k
            do_self_connection(c, chat);
7135
13.7k
        }
7136
7137
15.1k
        if (chat->connection_state == CS_CONNECTED) {
7138
11.9k
            do_gc_ping_and_key_rotation(chat);
7139
11.9k
            do_timed_out_reconn(chat);
7140
11.9k
        }
7141
7142
15.1k
        do_new_connection_cooldown(chat);
7143
15.1k
        do_peer_delete(c, chat, userdata);
7144
7145
15.1k
        if (chat->flag_exit) {  // should always come last as it modifies the chats array
7146
18
            group_delete(c, chat);
7147
18
        }
7148
15.1k
    }
7149
129k
}
7150
7151
/** @brief Set the size of the groupchat list to n.
7152
 *
7153
 * Return true on success.
7154
 */
7155
static bool realloc_groupchats(const Memory *_Nonnull mem, GC_Session *_Nonnull c, uint32_t n)
7156
5.63k
{
7157
5.63k
    if (n == 0) {
7158
360
        mem_delete(mem, c->chats);
7159
360
        c->chats = nullptr;
7160
360
        return true;
7161
360
    }
7162
7163
5.27k
    GC_Chat *temp = (GC_Chat *)mem_vrealloc(mem, c->chats, n, sizeof(GC_Chat));
7164
7165
5.27k
    if (temp == nullptr) {
7166
3
        return false;
7167
3
    }
7168
7169
5.26k
    c->chats = temp;
7170
5.26k
    return true;
7171
5.27k
}
7172
7173
static int get_new_group_index(const Memory *_Nonnull mem, GC_Session *_Nonnull c)
7174
21.3k
{
7175
21.3k
    if (c == nullptr) {
7176
0
        return -1;
7177
0
    }
7178
7179
627k
    for (uint32_t i = 0; i < c->chats_index; ++i) {
7180
621k
        if (c->chats[i].connection_state == CS_NONE) {
7181
16.1k
            return i;
7182
16.1k
        }
7183
621k
    }
7184
7185
5.23k
    if (!realloc_groupchats(mem, c, c->chats_index + 1)) {
7186
3
        return -1;
7187
3
    }
7188
7189
5.23k
    const int new_index = c->chats_index;
7190
7191
5.23k
    c->chats[new_index] = empty_gc_chat;
7192
7193
57.5k
    for (size_t i = 0; i < sizeof(c->chats[new_index].saved_invites) / sizeof(*c->chats[new_index].saved_invites); ++i) {
7194
52.3k
        c->chats[new_index].saved_invites[i] = -1;
7195
52.3k
    }
7196
7197
5.23k
    ++c->chats_index;
7198
7199
5.23k
    return new_index;
7200
5.23k
}
7201
7202
/** Attempts to associate new TCP relays with our group connection. */
7203
static void add_tcp_relays_to_chat(const GC_Session *c, GC_Chat *chat)
7204
335
{
7205
335
    const Messenger *m = c->messenger;
7206
7207
335
    const uint32_t num_relays = tcp_connections_count(nc_get_tcp_c(m->net_crypto));
7208
7209
335
    if (num_relays == 0) {
7210
335
        return;
7211
335
    }
7212
7213
0
    Node_format *tcp_relays = (Node_format *)mem_valloc(chat->mem, num_relays, sizeof(Node_format));
7214
7215
0
    if (tcp_relays == nullptr) {
7216
0
        return;
7217
0
    }
7218
7219
0
    const uint32_t num_copied = tcp_copy_connected_relays(nc_get_tcp_c(m->net_crypto), tcp_relays, (uint16_t)num_relays);
7220
7221
0
    for (uint32_t i = 0; i < num_copied; ++i) {
7222
0
        add_tcp_relay_global(chat->tcp_conn, &tcp_relays[i].ip_port, tcp_relays[i].public_key);
7223
0
    }
7224
7225
0
    mem_delete(chat->mem, tcp_relays);
7226
0
}
7227
7228
static bool init_gc_tcp_connection(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat)
7229
338
{
7230
338
    const Messenger *m = c->messenger;
7231
7232
338
    chat->tcp_conn = new_tcp_connections(chat->log, chat->mem, chat->rng, m->ns, chat->mono_time, chat->self_secret_key.enc,
7233
338
                                         &m->options.proxy_info, c->tcp_np);
7234
7235
338
    if (chat->tcp_conn == nullptr) {
7236
3
        return false;
7237
3
    }
7238
7239
335
    add_tcp_relays_to_chat(c, chat);
7240
7241
335
    set_packet_tcp_connection_callback(chat->tcp_conn, &handle_gc_tcp_packet, c->messenger);
7242
335
    set_oob_packet_tcp_connection_callback(chat->tcp_conn, &handle_gc_tcp_oob_packet, c->messenger);
7243
7244
335
    return true;
7245
338
}
7246
7247
/** Initializes default shared state values. */
7248
static void init_gc_shared_state(GC_Chat *_Nonnull chat, Group_Privacy_State privacy_state)
7249
231
{
7250
231
    chat->shared_state.maxpeers = MAX_GC_PEERS_DEFAULT;
7251
231
    chat->shared_state.privacy_state = privacy_state;
7252
231
    chat->shared_state.topic_lock = GC_TOPIC_LOCK_ENABLED;
7253
231
    chat->shared_state.voice_state = GV_ALL;
7254
231
}
7255
7256
/** @brief Initializes the group shared state for the founder.
7257
 *
7258
 * Return true on success.
7259
 */
7260
static bool init_gc_shared_state_founder(GC_Chat *_Nonnull chat, Group_Privacy_State privacy_state, const uint8_t *_Nonnull group_name, uint16_t name_length)
7261
111
{
7262
111
    chat->shared_state.founder_public_key = chat->self_public_key;
7263
111
    memcpy(chat->shared_state.group_name, group_name, name_length);
7264
111
    chat->shared_state.group_name_len = name_length;
7265
111
    chat->shared_state.privacy_state = privacy_state;
7266
7267
111
    return sign_gc_shared_state(chat);
7268
111
}
7269
7270
/** @brief Initializes shared state for moderation object.
7271
 *
7272
 * This must be called before any moderation
7273
 * or sanctions related operations.
7274
 */
7275
static void init_gc_moderation(GC_Chat *_Nonnull chat)
7276
449
{
7277
449
    memcpy(chat->moderation.founder_public_sig_key,
7278
449
           get_sig_pk(&chat->shared_state.founder_public_key), SIG_PUBLIC_KEY_SIZE);
7279
449
    memcpy(chat->moderation.self_public_sig_key, get_sig_pk(&chat->self_public_key), SIG_PUBLIC_KEY_SIZE);
7280
449
    memcpy(chat->moderation.self_secret_sig_key, get_sig_sk(&chat->self_secret_key), SIG_SECRET_KEY_SIZE);
7281
449
    chat->moderation.shared_state_version = chat->shared_state.version;
7282
449
    chat->moderation.log = chat->log;
7283
449
    chat->moderation.mem = chat->mem;
7284
449
}
7285
7286
static bool create_new_chat_ext_keypair(GC_Chat *_Nonnull chat);
7287
7288
static int create_new_group(const Memory *_Nonnull mem, GC_Session *_Nonnull c, const uint8_t *_Nonnull nick, size_t nick_length, bool founder, const Group_Privacy_State privacy_state)
7289
233
{
7290
233
    if (nick == nullptr || nick_length == 0) {
7291
0
        return -1;
7292
0
    }
7293
7294
233
    if (nick_length > MAX_GC_NICK_SIZE) {
7295
0
        return -1;
7296
0
    }
7297
7298
233
    const int group_number = get_new_group_index(mem, c);
7299
7300
233
    if (group_number == -1) {
7301
2
        return -1;
7302
2
    }
7303
7304
231
    Messenger *m = c->messenger;
7305
231
    GC_Chat *chat = &c->chats[group_number];
7306
7307
231
    chat->log = m->log;
7308
231
    chat->mem = m->mem;
7309
231
    chat->rng = m->rng;
7310
7311
231
    const uint64_t tm = mono_time_get(m->mono_time);
7312
7313
231
    chat->group_number = group_number;
7314
231
    chat->numpeers = 0;
7315
231
    chat->connection_state = CS_CONNECTING;
7316
231
    chat->net = m->net;
7317
231
    chat->mono_time = m->mono_time;
7318
231
    chat->last_ping_interval = tm;
7319
231
    chat->friend_connection_id = -1;
7320
7321
231
    if (!create_new_chat_ext_keypair(chat)) {
7322
0
        LOGGER_ERROR(chat->log, "Failed to create extended keypair");
7323
0
        group_delete(c, chat);
7324
0
        return -1;
7325
0
    }
7326
7327
231
    init_gc_shared_state(chat, privacy_state);
7328
231
    init_gc_moderation(chat);
7329
7330
231
    if (!init_gc_tcp_connection(c, chat)) {
7331
2
        group_delete(c, chat);
7332
2
        return -1;
7333
2
    }
7334
7335
229
    if (peer_add(chat, nullptr, chat->self_public_key.enc) != 0) {    /* you are always peer_number/index 0 */
7336
4
        group_delete(c, chat);
7337
4
        return -1;
7338
4
    }
7339
7340
225
    if (!self_gc_set_nick(chat, nick, (uint16_t)nick_length)) {
7341
0
        group_delete(c, chat);
7342
0
        return -1;
7343
0
    }
7344
7345
225
    self_gc_set_status(chat, GS_NONE);
7346
225
    self_gc_set_role(chat, founder ? GR_FOUNDER : GR_USER);
7347
225
    self_gc_set_confirmed(chat, true);
7348
225
    self_gc_set_ext_public_key(chat, &chat->self_public_key);
7349
7350
225
    return group_number;
7351
225
}
7352
7353
/** @brief Inits the sanctions list credentials.
7354
 *
7355
 * This should be called by the group founder on creation.
7356
 *
7357
 * This function must be called after `init_gc_moderation()`.
7358
 *
7359
 * Return true on success.
7360
 */
7361
static bool init_gc_sanctions_creds(GC_Chat *_Nonnull chat)
7362
111
{
7363
111
    return sanctions_list_make_creds(&chat->moderation);
7364
111
}
7365
7366
/** @brief Attempts to add `num_addrs` peers from `addrs` to our peerlist and initiate invite requests
7367
 * for all of them.
7368
 *
7369
 * Returns the number of peers successfully loaded.
7370
 */
7371
static size_t load_gc_peers(GC_Chat *chat, const GC_SavedPeerInfo *addrs, uint16_t num_addrs)
7372
129
{
7373
129
    size_t count = 0;
7374
7375
13.0k
    for (size_t i = 0; i < num_addrs; ++i) {
7376
12.9k
        if (!saved_peer_is_valid(&addrs[i])) {
7377
12.9k
            continue;
7378
12.9k
        }
7379
7380
0
        const bool ip_port_is_set = ipport_isset(&addrs[i].ip_port);
7381
0
        const IP_Port *ip_port = ip_port_is_set ? &addrs[i].ip_port : nullptr;
7382
7383
0
        const int peer_number = peer_add(chat, ip_port, addrs[i].public_key);
7384
7385
0
        GC_Connection *gconn = get_gc_connection(chat, peer_number);
7386
7387
0
        if (gconn == nullptr) {
7388
0
            continue;
7389
0
        }
7390
7391
0
        add_tcp_relay_global(chat->tcp_conn, &addrs[i].tcp_relay.ip_port, addrs[i].tcp_relay.public_key);
7392
7393
0
        const int add_tcp_result = add_tcp_relay_connection(chat->tcp_conn, gconn->tcp_connection_num,
7394
0
                                   &addrs[i].tcp_relay.ip_port,
7395
0
                                   addrs[i].tcp_relay.public_key);
7396
7397
0
        if (add_tcp_result == -1 && !ip_port_is_set) {
7398
0
            gcc_mark_for_deletion(gconn, chat->tcp_conn, GC_EXIT_TYPE_DISCONNECTED, nullptr, 0);
7399
0
            continue;
7400
0
        }
7401
7402
0
        if (add_tcp_result == 0) {
7403
0
            const int save_tcp_result = gcc_save_tcp_relay(chat->rng, gconn, &addrs[i].tcp_relay);
7404
7405
0
            if (save_tcp_result == -1) {
7406
0
                gcc_mark_for_deletion(gconn, chat->tcp_conn, GC_EXIT_TYPE_DISCONNECTED, nullptr, 0);
7407
0
                continue;
7408
0
            }
7409
7410
0
            memcpy(gconn->oob_relay_pk, addrs[i].tcp_relay.public_key, CRYPTO_PUBLIC_KEY_SIZE);
7411
0
        }
7412
7413
0
        const uint64_t tm = mono_time_get(chat->mono_time);
7414
7415
0
        gconn->is_oob_handshake = !gcc_direct_conn_is_possible(chat, gconn);
7416
0
        gconn->is_pending_handshake_response = false;
7417
0
        gconn->pending_handshake_type = HS_INVITE_REQUEST;
7418
0
        gconn->last_received_packet_time = tm;
7419
0
        gconn->last_key_rotation = tm;
7420
7421
0
        ++count;
7422
0
    }
7423
7424
129
    update_gc_peer_roles(chat);
7425
7426
129
    return count;
7427
129
}
7428
7429
void gc_group_save(const GC_Chat *chat, Bin_Pack *bp)
7430
2.00k
{
7431
2.00k
    gc_save_pack_group(chat, bp);
7432
2.00k
}
7433
7434
int gc_group_load(GC_Session *c, Bin_Unpack *bu)
7435
21.1k
{
7436
21.1k
    const int group_number = get_new_group_index(c->messenger->mem, c);
7437
7438
21.1k
    if (group_number < 0) {
7439
1
        return -1;
7440
1
    }
7441
7442
21.1k
    const uint64_t tm = mono_time_get(c->messenger->mono_time);
7443
7444
21.1k
    Messenger *m = c->messenger;
7445
21.1k
    GC_Chat *chat = &c->chats[group_number];
7446
7447
21.1k
    chat->group_number = group_number;
7448
21.1k
    chat->numpeers = 0;
7449
21.1k
    chat->net = m->net;
7450
21.1k
    chat->mono_time = m->mono_time;
7451
21.1k
    chat->log = m->log;
7452
21.1k
    chat->mem = m->mem;
7453
21.1k
    chat->rng = m->rng;
7454
21.1k
    chat->last_ping_interval = tm;
7455
21.1k
    chat->friend_connection_id = -1;
7456
7457
    // Initialise these first, because we may need to log/dealloc things on cleanup.
7458
21.1k
    chat->moderation.log = m->log;
7459
21.1k
    chat->moderation.mem = m->mem;
7460
7461
21.1k
    if (!gc_load_unpack_group(chat, bu)) {
7462
21.0k
        LOGGER_ERROR(chat->log, "Failed to unpack group");
7463
21.0k
        return -1;
7464
21.0k
    }
7465
7466
107
    init_gc_moderation(chat);
7467
7468
107
    if (!init_gc_tcp_connection(c, chat)) {
7469
1
        LOGGER_ERROR(chat->log, "Failed to init tcp connection");
7470
1
        return -1;
7471
1
    }
7472
7473
106
    if (chat->connection_state == CS_DISCONNECTED) {
7474
2
        return group_number;
7475
2
    }
7476
7477
104
    if (is_public_chat(chat)) {
7478
85
        if (!m_create_group_connection(m, chat)) {
7479
0
            LOGGER_ERROR(chat->log, "Failed to initialize group friend connection");
7480
0
        }
7481
85
    }
7482
7483
104
    return group_number;
7484
106
}
7485
7486
int gc_group_add(GC_Session *c, Group_Privacy_State privacy_state,
7487
                 const uint8_t *group_name, uint16_t group_name_length,
7488
                 const uint8_t *nick, size_t nick_length)
7489
115
{
7490
115
    if (group_name_length > MAX_GC_GROUP_NAME_SIZE) {
7491
0
        return -1;
7492
0
    }
7493
7494
115
    if (nick_length > MAX_GC_NICK_SIZE) {
7495
0
        return -1;
7496
0
    }
7497
7498
115
    if (group_name_length == 0 || group_name == nullptr) {
7499
0
        return -2;
7500
0
    }
7501
7502
115
    if (nick_length == 0 || nick == nullptr) {
7503
0
        return -2;
7504
0
    }
7505
7506
115
    const int group_number = create_new_group(c->messenger->mem, c, nick, nick_length, true, privacy_state);
7507
7508
115
    if (group_number == -1) {
7509
4
        return -3;
7510
4
    }
7511
7512
111
    GC_Chat *chat = gc_get_group(c, group_number);
7513
7514
111
    if (chat == nullptr) {
7515
0
        return -3;
7516
0
    }
7517
7518
111
    crypto_memlock(&chat->chat_secret_key, sizeof(chat->chat_secret_key));
7519
7520
111
    create_extended_keypair(&chat->chat_public_key, &chat->chat_secret_key, chat->rng);
7521
7522
111
    if (!init_gc_shared_state_founder(chat, privacy_state, group_name, group_name_length)) {
7523
0
        group_delete(c, chat);
7524
0
        return -4;
7525
0
    }
7526
7527
111
    init_gc_moderation(chat);
7528
7529
111
    if (!init_gc_sanctions_creds(chat)) {
7530
0
        group_delete(c, chat);
7531
0
        return -4;
7532
0
    }
7533
7534
111
    if (gc_set_topic(chat, nullptr, 0) != 0) {
7535
2
        group_delete(c, chat);
7536
2
        return -4;
7537
2
    }
7538
7539
109
    chat->join_type = HJ_PRIVATE;
7540
109
    chat->connection_state = CS_CONNECTED;
7541
109
    chat->time_connected = mono_time_get(c->messenger->mono_time);
7542
7543
109
    if (is_public_chat(chat)) {
7544
6
        if (!m_create_group_connection(c->messenger, chat)) {
7545
0
            LOGGER_ERROR(chat->log, "Failed to initialize group friend connection");
7546
0
            group_delete(c, chat);
7547
0
            return -5;
7548
0
        }
7549
7550
6
        chat->join_type = HJ_PUBLIC;
7551
6
    }
7552
7553
109
    update_gc_peer_roles(chat);
7554
7555
109
    return group_number;
7556
109
}
7557
7558
int gc_rejoin_group(GC_Session *c, GC_Chat *chat, const uint8_t *passwd, uint16_t passwd_len)
7559
1
{
7560
1
    if (c == nullptr) {
7561
0
        LOGGER_ERROR(chat->log, "NULL group session pointer.");
7562
0
        return -1;
7563
0
    }
7564
7565
1
    if (passwd != nullptr && passwd_len > 0) {
7566
0
        if (!set_gc_password_local(chat, passwd, passwd_len)) {
7567
0
            LOGGER_WARNING(chat->log, "Failed to set new password during reconnect.");
7568
0
        }
7569
0
    }
7570
7571
1
    chat->time_connected = 0;
7572
7573
1
    if (group_can_handle_packets(chat)) {
7574
0
        send_gc_self_exit(chat, nullptr, 0);
7575
0
    }
7576
7577
1
    for (uint32_t i = 1; i < chat->numpeers; ++i) {
7578
0
        GC_Connection *gconn = get_gc_connection(chat, i);
7579
0
        assert(gconn != nullptr);
7580
7581
0
        gcc_mark_for_deletion(gconn, chat->tcp_conn, GC_EXIT_TYPE_SELF_DISCONNECTED, nullptr, 0);
7582
0
    }
7583
7584
1
    if (is_public_chat(chat)) {
7585
1
        kill_group_friend_connection(c, chat);
7586
7587
1
        if (!m_create_group_connection(c->messenger, chat)) {
7588
0
            LOGGER_WARNING(chat->log, "Failed to create new messenger connection for group");
7589
0
            return -1;
7590
0
        }
7591
7592
1
        chat->update_self_announces = true;
7593
1
    }
7594
7595
1
    chat->connection_state = CS_CONNECTING;
7596
7597
1
    return 0;
7598
1
}
7599
7600
int gc_group_join(GC_Session *c, const uint8_t *chat_id, const uint8_t *nick, size_t nick_length, const uint8_t *passwd,
7601
                  uint16_t passwd_len)
7602
23
{
7603
23
    if (chat_id == nullptr) {
7604
0
        return -2;
7605
0
    }
7606
7607
23
    if (nick_length > MAX_GC_NICK_SIZE) {
7608
0
        return -3;
7609
0
    }
7610
7611
23
    if (nick == nullptr || nick_length == 0) {
7612
0
        return -4;
7613
0
    }
7614
7615
23
    GC_Chat *existing_group = gc_get_group_by_public_key(c, chat_id);
7616
7617
    // If we're already in the group we try to reconnect to it
7618
23
    if (existing_group != nullptr) {
7619
1
        const int ret = gc_rejoin_group(c, existing_group, passwd, passwd_len);
7620
1
        return ret != 0 ? -6 : ret;
7621
1
    }
7622
7623
22
    const int group_number = create_new_group(c->messenger->mem, c, nick, nick_length, false, GI_PUBLIC);
7624
7625
22
    if (group_number == -1) {
7626
0
        return -1;
7627
0
    }
7628
7629
22
    GC_Chat *chat = gc_get_group(c, group_number);
7630
7631
22
    if (chat == nullptr) {
7632
0
        return -1;
7633
0
    }
7634
7635
22
    if (!expand_chat_id(&chat->chat_public_key, chat_id)) {
7636
0
        group_delete(c, chat);
7637
0
        return -1;
7638
0
    }
7639
7640
22
    chat->connection_state = CS_CONNECTING;
7641
7642
22
    if (passwd != nullptr && passwd_len > 0) {
7643
6
        if (!set_gc_password_local(chat, passwd, passwd_len)) {
7644
0
            group_delete(c, chat);
7645
0
            return -5;
7646
0
        }
7647
6
    }
7648
7649
22
    if (!m_create_group_connection(c->messenger, chat)) {
7650
0
        group_delete(c, chat);
7651
0
        return -6;
7652
0
    }
7653
7654
22
    update_gc_peer_roles(chat);
7655
7656
22
    return group_number;
7657
22
}
7658
7659
bool gc_disconnect_from_group(const GC_Session *c, GC_Chat *chat)
7660
1
{
7661
1
    if (c == nullptr || chat == nullptr) {
7662
0
        return false;
7663
0
    }
7664
7665
1
    chat->connection_state = CS_DISCONNECTED;
7666
7667
1
    if (!send_gc_broadcast_message(chat, nullptr, 0, GM_PEER_EXIT)) {
7668
0
        LOGGER_DEBUG(chat->log, "Failed to broadcast group exit packet");
7669
0
    }
7670
7671
2
    for (uint32_t i = 1; i < chat->numpeers; ++i) {
7672
1
        GC_Connection *gconn = get_gc_connection(chat, i);
7673
1
        assert(gconn != nullptr);
7674
7675
1
        gcc_mark_for_deletion(gconn, chat->tcp_conn, GC_EXIT_TYPE_SELF_DISCONNECTED, nullptr, 0);
7676
1
    }
7677
7678
1
    return true;
7679
1
}
7680
7681
bool group_not_added(const GC_Session *c, const uint8_t *chat_id, uint32_t length)
7682
100
{
7683
100
    if (length < CHAT_ID_SIZE) {
7684
0
        return false;
7685
0
    }
7686
7687
100
    return !group_exists(c, chat_id);
7688
100
}
7689
7690
int gc_invite_friend(const GC_Session *c, GC_Chat *chat, int32_t friend_number,
7691
                     gc_send_group_invite_packet_cb *callback)
7692
103
{
7693
103
    if (!friend_is_valid(c->messenger, friend_number)) {
7694
0
        return -1;
7695
0
    }
7696
7697
103
    const uint16_t group_name_length = chat->shared_state.group_name_len;
7698
7699
103
    assert(group_name_length <= MAX_GC_GROUP_NAME_SIZE);
7700
7701
103
    uint8_t *packet = (uint8_t *)mem_balloc(chat->mem, 2 + CHAT_ID_SIZE + ENC_PUBLIC_KEY_SIZE + group_name_length);
7702
7703
103
    if (packet == nullptr) {
7704
1
        return -1;
7705
1
    }
7706
7707
102
    packet[0] = GP_FRIEND_INVITE;
7708
102
    packet[1] = GROUP_INVITE;
7709
7710
102
    memcpy(packet + 2, get_chat_id(&chat->chat_public_key), CHAT_ID_SIZE);
7711
102
    uint16_t length = 2 + CHAT_ID_SIZE;
7712
7713
102
    memcpy(packet + length, chat->self_public_key.enc, ENC_PUBLIC_KEY_SIZE);
7714
102
    length += ENC_PUBLIC_KEY_SIZE;
7715
7716
102
    memcpy(packet + length, chat->shared_state.group_name, group_name_length);
7717
102
    length += group_name_length;
7718
7719
102
    assert(length <= MAX_GC_PACKET_SIZE);
7720
7721
102
    if (!callback(c->messenger, friend_number, packet, length)) {
7722
1
        mem_delete(chat->mem, packet);
7723
1
        return -2;
7724
1
    }
7725
7726
101
    mem_delete(chat->mem, packet);
7727
7728
101
    chat->saved_invites[chat->saved_invites_index] = friend_number;
7729
101
    chat->saved_invites_index = (chat->saved_invites_index + 1) % MAX_GC_SAVED_INVITES;
7730
7731
101
    return 0;
7732
102
}
7733
7734
/** @brief Sends an invite accepted packet to `friend_number`.
7735
 *
7736
 * Return 0 on success.
7737
 * Return -1 if `friend_number` does not designate a valid friend.
7738
 * Return -2 if `chat `is null.
7739
 * Return -3 if packet failed to send.
7740
 */
7741
static int send_gc_invite_accepted_packet(const Messenger *_Nonnull m, const GC_Chat *_Nonnull chat, uint32_t friend_number)
7742
90
{
7743
90
    if (!friend_is_valid(m, friend_number)) {
7744
0
        return -1;
7745
0
    }
7746
7747
90
    if (chat == nullptr) {
7748
0
        return -2;
7749
0
    }
7750
7751
90
    uint8_t packet[1 + 1 + CHAT_ID_SIZE + ENC_PUBLIC_KEY_SIZE];
7752
90
    packet[0] = GP_FRIEND_INVITE;
7753
90
    packet[1] = GROUP_INVITE_ACCEPTED;
7754
7755
90
    memcpy(packet + 2, get_chat_id(&chat->chat_public_key), CHAT_ID_SIZE);
7756
90
    uint16_t length = 2 + CHAT_ID_SIZE;
7757
7758
90
    memcpy(packet + length, chat->self_public_key.enc, ENC_PUBLIC_KEY_SIZE);
7759
90
    length += ENC_PUBLIC_KEY_SIZE;
7760
7761
90
    if (!send_group_invite_packet(m, friend_number, packet, length)) {
7762
1
        LOGGER_ERROR(chat->log, "Failed to send group invite packet.");
7763
1
        return -3;
7764
1
    }
7765
7766
89
    return 0;
7767
90
}
7768
7769
/** @brief Sends an invite confirmed packet to friend designated by `friend_number`.
7770
 *
7771
 * `data` must contain the group's Chat ID, the sender's public encryption key,
7772
 * and either the sender's packed IP_Port, or at least one packed TCP node that
7773
 * the sender can be connected to through (or both).
7774
 *
7775
 * Return true on success.
7776
 */
7777
static bool send_gc_invite_confirmed_packet(const Messenger *_Nonnull m, const GC_Chat *_Nonnull chat, uint32_t friend_number, const uint8_t *_Nonnull data, uint16_t length)
7778
86
{
7779
86
    if (!friend_is_valid(m, friend_number)) {
7780
0
        return false;
7781
0
    }
7782
7783
86
    if (chat == nullptr) {
7784
0
        return false;
7785
0
    }
7786
7787
86
    if (length > MAX_GC_PACKET_SIZE) {
7788
0
        return false;
7789
0
    }
7790
7791
86
    const uint16_t packet_length = 2 + length;
7792
86
    uint8_t *packet = (uint8_t *)mem_balloc(chat->mem, packet_length);
7793
7794
86
    if (packet == nullptr) {
7795
0
        return false;
7796
0
    }
7797
7798
86
    packet[0] = GP_FRIEND_INVITE;
7799
86
    packet[1] = GROUP_INVITE_CONFIRMATION;
7800
7801
86
    memcpy(packet + 2, data, length);
7802
7803
86
    if (!send_group_invite_packet(m, friend_number, packet, packet_length)) {
7804
0
        mem_delete(chat->mem, packet);
7805
0
        return false;
7806
0
    }
7807
7808
86
    mem_delete(chat->mem, packet);
7809
7810
86
    return true;
7811
86
}
7812
7813
/** @brief Adds `num_nodes` tcp relays from `tcp_relays` to tcp relays list associated with `gconn`
7814
 *
7815
 * Returns the number of relays successfully added.
7816
 */
7817
static uint32_t add_gc_tcp_relays(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn, const Node_format *_Nonnull tcp_relays, size_t num_nodes)
7818
0
{
7819
0
    uint32_t relays_added = 0;
7820
7821
0
    for (size_t i = 0; i < num_nodes; ++i) {
7822
0
        const int add_tcp_result = add_tcp_relay_connection(chat->tcp_conn,
7823
0
                                   gconn->tcp_connection_num, &tcp_relays[i].ip_port,
7824
0
                                   tcp_relays[i].public_key);
7825
7826
0
        if (add_tcp_result == 0) {
7827
0
            if (gcc_save_tcp_relay(chat->rng, gconn, &tcp_relays[i]) == 0) {
7828
0
                ++relays_added;
7829
0
            }
7830
0
        }
7831
0
    }
7832
7833
0
    return relays_added;
7834
0
}
7835
7836
static bool copy_friend_ip_port_to_gconn(const Messenger *_Nonnull m, int friend_number, GC_Connection *_Nonnull gconn)
7837
172
{
7838
172
    if (!friend_is_valid(m, friend_number)) {
7839
0
        return false;
7840
0
    }
7841
7842
172
    const Friend *f = &m->friendlist[friend_number];
7843
172
    const int friend_connection_id = f->friendcon_id;
7844
172
    const Friend_Conn *connection = get_conn(m->fr_c, friend_connection_id);
7845
7846
172
    if (connection == nullptr) {
7847
0
        return false;
7848
0
    }
7849
7850
172
    const IP_Port *friend_ip_port = friend_conn_get_dht_ip_port(connection);
7851
7852
172
    if (!ipport_isset(friend_ip_port)) {
7853
0
        return false;
7854
0
    }
7855
7856
172
    gconn->addr.ip_port = *friend_ip_port;
7857
7858
172
    return true;
7859
172
}
7860
7861
int handle_gc_invite_confirmed_packet(const GC_Session *c, int friend_number, const uint8_t *data, uint16_t length)
7862
86
{
7863
86
    if (length < GC_JOIN_DATA_LENGTH) {
7864
0
        return -1;
7865
0
    }
7866
7867
86
    if (!friend_is_valid(c->messenger, friend_number)) {
7868
0
        return -4;
7869
0
    }
7870
7871
86
    uint8_t chat_id[CHAT_ID_SIZE];
7872
86
    uint8_t invite_chat_pk[ENC_PUBLIC_KEY_SIZE];
7873
7874
86
    memcpy(chat_id, data, CHAT_ID_SIZE);
7875
86
    memcpy(invite_chat_pk, data + CHAT_ID_SIZE, ENC_PUBLIC_KEY_SIZE);
7876
7877
86
    const GC_Chat *chat = gc_get_group_by_public_key(c, chat_id);
7878
7879
86
    if (chat == nullptr) {
7880
0
        return -2;
7881
0
    }
7882
7883
86
    const int peer_number = get_peer_number_of_enc_pk(chat, invite_chat_pk, false);
7884
7885
86
    GC_Connection *gconn = get_gc_connection(chat, peer_number);
7886
7887
86
    if (gconn == nullptr) {
7888
0
        return -3;
7889
0
    }
7890
7891
86
    Node_format tcp_relays[GCC_MAX_TCP_SHARED_RELAYS];
7892
86
    const int num_nodes = unpack_nodes(tcp_relays, GCC_MAX_TCP_SHARED_RELAYS,
7893
86
                                       nullptr, data + ENC_PUBLIC_KEY_SIZE + CHAT_ID_SIZE,
7894
86
                                       length - GC_JOIN_DATA_LENGTH, true);
7895
7896
86
    const bool copy_ip_port_result = copy_friend_ip_port_to_gconn(c->messenger, friend_number, gconn);
7897
7898
86
    uint32_t tcp_relays_added = 0;
7899
7900
86
    if (num_nodes > 0) {
7901
0
        tcp_relays_added = add_gc_tcp_relays(chat, gconn, tcp_relays, num_nodes);
7902
86
    } else {
7903
86
        LOGGER_WARNING(chat->log, "Invite confirm packet did not contain any TCP relays");
7904
86
    }
7905
7906
86
    if (tcp_relays_added == 0 && !copy_ip_port_result) {
7907
0
        LOGGER_ERROR(chat->log, "Got invalid connection info from peer");
7908
0
        return -5;
7909
0
    }
7910
7911
86
    gconn->pending_handshake_type = HS_INVITE_REQUEST;
7912
7913
86
    return 0;
7914
86
}
7915
7916
/** Return true if we have a pending sent invite for our friend designated by `friend_number`. */
7917
static bool friend_was_invited(const Messenger *_Nonnull m, GC_Chat *_Nonnull chat, int friend_number)
7918
87
{
7919
87
    for (size_t i = 0; i < MAX_GC_SAVED_INVITES; ++i) {
7920
87
        if (chat->saved_invites[i] == friend_number) {
7921
87
            chat->saved_invites[i] = -1;
7922
87
            return friend_is_valid(m, friend_number);
7923
87
        }
7924
87
    }
7925
7926
0
    return false;
7927
87
}
7928
7929
bool handle_gc_invite_accepted_packet(const GC_Session *c, int friend_number, const uint8_t *data, uint16_t length)
7930
87
{
7931
87
    if (length < GC_JOIN_DATA_LENGTH) {
7932
0
        return false;
7933
0
    }
7934
7935
87
    const Messenger *m = c->messenger;
7936
7937
87
    const uint8_t *chat_id = data;
7938
7939
87
    GC_Chat *chat = gc_get_group_by_public_key(c, chat_id);
7940
7941
87
    if (chat == nullptr || !group_can_handle_packets(chat)) {
7942
0
        return false;
7943
0
    }
7944
7945
87
    const uint8_t *invite_chat_pk = data + CHAT_ID_SIZE;
7946
7947
87
    const int peer_number = peer_add(chat, nullptr, invite_chat_pk);
7948
7949
87
    if (!friend_was_invited(m, chat, friend_number)) {
7950
0
        return false;
7951
0
    }
7952
7953
87
    GC_Connection *gconn = get_gc_connection(chat, peer_number);
7954
7955
87
    if (gconn == nullptr) {
7956
1
        return false;
7957
1
    }
7958
7959
86
    Node_format tcp_relays[GCC_MAX_TCP_SHARED_RELAYS];
7960
86
    const uint32_t num_tcp_relays = tcp_copy_connected_relays(chat->tcp_conn, tcp_relays, GCC_MAX_TCP_SHARED_RELAYS);
7961
7962
86
    const bool copy_ip_port_result = copy_friend_ip_port_to_gconn(m, friend_number, gconn);
7963
7964
86
    if (num_tcp_relays == 0 && !copy_ip_port_result) {
7965
0
        return false;
7966
0
    }
7967
7968
86
    uint16_t len = GC_JOIN_DATA_LENGTH;
7969
86
    uint8_t out_data[GC_JOIN_DATA_LENGTH + (GCC_MAX_TCP_SHARED_RELAYS * PACKED_NODE_SIZE_IP6)];
7970
7971
86
    memcpy(out_data, chat_id, CHAT_ID_SIZE);
7972
86
    memcpy(out_data + CHAT_ID_SIZE, chat->self_public_key.enc, ENC_PUBLIC_KEY_SIZE);
7973
7974
86
    if (num_tcp_relays > 0) {
7975
0
        const uint32_t tcp_relays_added = add_gc_tcp_relays(chat, gconn, tcp_relays, num_tcp_relays);
7976
7977
0
        if (tcp_relays_added == 0 && !copy_ip_port_result) {
7978
0
            LOGGER_ERROR(chat->log, "Got invalid connection info from peer");
7979
0
            return false;
7980
0
        }
7981
7982
0
        const int nodes_len = pack_nodes(chat->log, out_data + len, sizeof(out_data) - len, tcp_relays,
7983
0
                                         (uint16_t)num_tcp_relays);
7984
7985
0
        if (nodes_len <= 0 && !copy_ip_port_result) {
7986
0
            return false;
7987
0
        }
7988
7989
0
        len += nodes_len;
7990
0
    }
7991
7992
86
    return send_gc_invite_confirmed_packet(m, chat, friend_number, out_data, len);
7993
86
}
7994
7995
int gc_accept_invite(GC_Session *c, int32_t friend_number, const uint8_t *data, uint16_t length, const uint8_t *nick,
7996
                     size_t nick_length, const uint8_t *passwd, uint16_t passwd_len)
7997
96
{
7998
96
    if (length < CHAT_ID_SIZE + ENC_PUBLIC_KEY_SIZE) {
7999
0
        return -1;
8000
0
    }
8001
8002
96
    if (nick_length > MAX_GC_NICK_SIZE) {
8003
0
        return -3;
8004
0
    }
8005
8006
96
    if (nick == nullptr || nick_length == 0) {
8007
0
        return -4;
8008
0
    }
8009
8010
96
    if (!friend_is_valid(c->messenger, friend_number)) {
8011
0
        return -6;
8012
0
    }
8013
8014
96
    const uint8_t *chat_id = data;
8015
96
    const uint8_t *invite_chat_pk = data + CHAT_ID_SIZE;
8016
8017
96
    const int group_number = create_new_group(c->messenger->mem, c, nick, nick_length, false, GI_PUBLIC);
8018
8019
96
    if (group_number == -1) {
8020
4
        return -2;
8021
4
    }
8022
8023
92
    GC_Chat *chat = gc_get_group(c, group_number);
8024
8025
92
    if (chat == nullptr) {
8026
0
        return -2;
8027
0
    }
8028
8029
92
    if (!expand_chat_id(&chat->chat_public_key, chat_id)) {
8030
0
        group_delete(c, chat);
8031
0
        return -2;
8032
0
    }
8033
8034
92
    if (passwd != nullptr && passwd_len > 0) {
8035
0
        if (!set_gc_password_local(chat, passwd, passwd_len)) {
8036
0
            group_delete(c, chat);
8037
0
            return -5;
8038
0
        }
8039
0
    }
8040
8041
92
    const int peer_id = peer_add(chat, nullptr, invite_chat_pk);
8042
8043
92
    if (peer_id < 0) {
8044
2
        return -2;
8045
2
    }
8046
8047
90
    chat->join_type = HJ_PRIVATE;
8048
8049
90
    if (send_gc_invite_accepted_packet(c->messenger, chat, friend_number) != 0) {
8050
1
        return -7;
8051
1
    }
8052
8053
89
    return group_number;
8054
90
}
8055
8056
static bool gc_handle_announce_response_callback(Onion_Client *_Nonnull onion_c, uint32_t sendback_num, const uint8_t *_Nonnull data,
8057
        size_t data_length, void *_Nullable user_data);
8058
GC_Session *new_dht_groupchats(Messenger *m)
8059
2.77k
{
8060
2.77k
    if (m == nullptr) {
8061
0
        return nullptr;
8062
0
    }
8063
8064
2.77k
    GC_Session *c = (GC_Session *)mem_alloc(m->mem, sizeof(GC_Session));
8065
8066
2.77k
    if (c == nullptr) {
8067
17
        return nullptr;
8068
17
    }
8069
8070
2.76k
    c->messenger = m;
8071
2.76k
    c->announces_list = m->group_announce;
8072
2.76k
    c->tcp_np = m->tcp_np;
8073
8074
2.76k
    networking_registerhandler(m->net, NET_PACKET_GC_LOSSLESS, &handle_gc_udp_packet, m);
8075
2.76k
    networking_registerhandler(m->net, NET_PACKET_GC_LOSSY, &handle_gc_udp_packet, m);
8076
2.76k
    networking_registerhandler(m->net, NET_PACKET_GC_HANDSHAKE, &handle_gc_udp_packet, m);
8077
2.76k
    onion_group_announce_register(m->onion_c, gc_handle_announce_response_callback, c);
8078
8079
2.76k
    return c;
8080
2.77k
}
8081
8082
static void group_cleanup(const GC_Session *c, GC_Chat *chat)
8083
4.42k
{
8084
4.42k
    kill_group_friend_connection(c, chat);
8085
8086
4.42k
    mod_list_cleanup(&chat->moderation);
8087
4.42k
    sanctions_list_cleanup(&chat->moderation);
8088
8089
4.42k
    if (chat->tcp_conn != nullptr) {
8090
158
        kill_tcp_connections(chat->tcp_conn);
8091
158
    }
8092
8093
4.42k
    gcc_cleanup(chat);
8094
8095
4.42k
    if (chat->group != nullptr) {
8096
197
        mem_delete(chat->mem, chat->group);
8097
197
        chat->group = nullptr;
8098
197
    }
8099
8100
4.42k
    crypto_memunlock(&chat->self_secret_key, sizeof(chat->self_secret_key));
8101
4.42k
    crypto_memunlock(&chat->chat_secret_key, sizeof(chat->chat_secret_key));
8102
4.42k
    crypto_memunlock(chat->shared_state.password, sizeof(chat->shared_state.password));
8103
4.42k
}
8104
8105
/** Deletes chat from group chat array and cleans up. */
8106
static void group_delete(GC_Session *c, GC_Chat *chat)
8107
4.42k
{
8108
4.42k
    if (c == nullptr || chat == nullptr) {
8109
0
        if (chat != nullptr) {
8110
0
            LOGGER_ERROR(chat->log, "Null pointer");
8111
0
        }
8112
8113
0
        return;
8114
0
    }
8115
8116
4.42k
    group_cleanup(c, chat);
8117
8118
4.42k
    c->chats[chat->group_number] = empty_gc_chat;
8119
8120
4.42k
    uint32_t i;
8121
8122
8.90k
    for (i = c->chats_index; i > 0; --i) {
8123
8.54k
        if (c->chats[i - 1].connection_state != CS_NONE) {
8124
4.06k
            break;
8125
4.06k
        }
8126
8.54k
    }
8127
8128
4.42k
    if (c->chats_index != i) {
8129
395
        c->chats_index = i;
8130
8131
395
        if (!realloc_groupchats(c->messenger->mem, c, c->chats_index)) {
8132
0
            LOGGER_ERROR(c->messenger->log, "Failed to reallocate groupchats array");
8133
0
        }
8134
395
    }
8135
4.42k
}
8136
8137
int gc_group_exit(GC_Session *c, GC_Chat *chat, const uint8_t *message, uint16_t length)
8138
4.51k
{
8139
4.51k
    chat->flag_exit = true;
8140
4.51k
    return group_can_handle_packets(chat) ? send_gc_self_exit(chat, message, length) : 0;
8141
4.51k
}
8142
8143
static int kill_group(GC_Session *_Nonnull c, GC_Chat *_Nonnull chat)
8144
4.40k
{
8145
4.40k
    const int ret = gc_group_exit(c, chat, nullptr, 0);
8146
4.40k
    group_delete(c, chat);
8147
4.40k
    return ret;
8148
4.40k
}
8149
8150
void kill_dht_groupchats(GC_Session *c)
8151
1.88k
{
8152
1.88k
    if (c == nullptr) {
8153
0
        return;
8154
0
    }
8155
8156
6.86k
    for (uint32_t i = 0; i < c->chats_index; ++i) {
8157
4.97k
        GC_Chat *chat = &c->chats[i];
8158
8159
4.97k
        if (chat->connection_state == CS_NONE) {
8160
578
            continue;
8161
578
        }
8162
8163
4.40k
        if (kill_group(c, chat) != 0) {
8164
1
            LOGGER_WARNING(c->messenger->log, "Failed to send group exit packet");
8165
1
        }
8166
4.40k
    }
8167
8168
1.88k
    networking_registerhandler(c->messenger->net, NET_PACKET_GC_LOSSY, nullptr, nullptr);
8169
1.88k
    networking_registerhandler(c->messenger->net, NET_PACKET_GC_LOSSLESS, nullptr, nullptr);
8170
1.88k
    networking_registerhandler(c->messenger->net, NET_PACKET_GC_HANDSHAKE, nullptr, nullptr);
8171
1.88k
    onion_group_announce_register(c->messenger->onion_c, nullptr, nullptr);
8172
8173
1.88k
    mem_delete(c->messenger->mem, c->chats);
8174
1.88k
    mem_delete(c->messenger->mem, c);
8175
1.88k
}
8176
8177
bool gc_group_is_valid(const GC_Chat *chat)
8178
634k
{
8179
634k
    return chat->connection_state != CS_NONE && chat->shared_state.version > 0;
8180
634k
}
8181
8182
/** Return true if `group_number` designates an active group in session `c`. */
8183
static bool group_number_valid(const GC_Session *c, int group_number)
8184
17.5k
{
8185
17.5k
    if (group_number < 0 || (uint32_t)group_number >= c->chats_index) {
8186
1
        return false;
8187
1
    }
8188
8189
17.5k
    if (c->chats == nullptr) {
8190
0
        return false;
8191
0
    }
8192
8193
17.5k
    return c->chats[group_number].connection_state != CS_NONE;
8194
17.5k
}
8195
8196
uint32_t gc_count_groups(const GC_Session *c)
8197
24.7k
{
8198
24.7k
    uint32_t count = 0;
8199
8200
656k
    for (uint32_t i = 0; i < c->chats_index; ++i) {
8201
631k
        const GC_Chat *chat = &c->chats[i];
8202
8203
631k
        if (gc_group_is_valid(chat)) {
8204
57.6k
            ++count;
8205
57.6k
        }
8206
631k
    }
8207
8208
24.7k
    return count;
8209
24.7k
}
8210
8211
GC_Chat *gc_get_group(const GC_Session *c, int group_number)
8212
17.5k
{
8213
17.5k
    if (!group_number_valid(c, group_number)) {
8214
1
        return nullptr;
8215
1
    }
8216
8217
17.5k
    return &c->chats[group_number];
8218
17.5k
}
8219
8220
GC_Chat *gc_get_group_by_public_key(const GC_Session *c, const uint8_t *public_key)
8221
11.7k
{
8222
11.7k
    for (uint32_t i = 0; i < c->chats_index; ++i) {
8223
11.5k
        GC_Chat *chat = &c->chats[i];
8224
8225
11.5k
        if (chat->connection_state == CS_NONE) {
8226
0
            continue;
8227
0
        }
8228
8229
11.5k
        if (memcmp(public_key, get_chat_id(&chat->chat_public_key), CHAT_ID_SIZE) == 0) {
8230
11.5k
            return chat;
8231
11.5k
        }
8232
11.5k
    }
8233
8234
122
    return nullptr;
8235
11.7k
}
8236
8237
/** Return True if chat_id exists in the session chat array */
8238
static bool group_exists(const GC_Session *c, const uint8_t *chat_id)
8239
100
{
8240
100
    return gc_get_group_by_public_key(c, chat_id) != nullptr;
8241
100
}
8242
8243
/** Creates a new 32-byte session encryption keypair and puts the results in `public_key` and `secret_key`. */
8244
static void create_gc_session_keypair(const Logger *log, const Random *rng, uint8_t *public_key, uint8_t *secret_key)
8245
816
{
8246
816
    if (crypto_new_keypair(rng, public_key, secret_key) != 0) {
8247
0
        LOGGER_FATAL(log, "Failed to create group session keypair");
8248
0
    }
8249
816
}
8250
8251
/**
8252
 * Creates a new 64-byte extended keypair for `chat` and puts results in `self_public_key`
8253
 * and `self_secret_key` buffers. The first 32-bytes of the generated keys are used for
8254
 * encryption, while the remaining 32-bytes are used for signing.
8255
 *
8256
 * Return false if key generation fails.
8257
 */
8258
static bool create_new_chat_ext_keypair(GC_Chat *_Nonnull chat)
8259
231
{
8260
231
    crypto_memlock(&chat->self_secret_key, sizeof(chat->self_secret_key));
8261
8262
231
    if (!create_extended_keypair(&chat->self_public_key, &chat->self_secret_key, chat->rng)) {
8263
0
        crypto_memunlock(&chat->self_secret_key, sizeof(chat->self_secret_key));
8264
0
        return false;
8265
0
    }
8266
8267
231
    return true;
8268
231
}
8269
8270
/** @brief Handles a group announce onion response.
8271
 *
8272
 * Return true on success.
8273
 */
8274
static bool gc_handle_announce_response_callback(Onion_Client *onion_c, uint32_t sendback_num, const uint8_t *data,
8275
        size_t data_length, void *user_data)
8276
1.44k
{
8277
1.44k
    const GC_Session *c = (GC_Session *)user_data;
8278
8279
1.44k
    if (c == nullptr) {
8280
0
        return false;
8281
0
    }
8282
8283
1.44k
    if (sendback_num == 0) {
8284
0
        return false;
8285
0
    }
8286
8287
1.44k
    GC_Announce announces[GCA_MAX_SENT_ANNOUNCES];
8288
1.44k
    const uint8_t *gc_public_key = onion_friend_get_gc_public_key_num(onion_c, sendback_num - 1);
8289
1.44k
    GC_Chat *chat = gc_get_group_by_public_key(c, gc_public_key);
8290
8291
1.44k
    if (chat == nullptr) {
8292
0
        return false;
8293
0
    }
8294
8295
1.44k
    const int gc_announces_count = gca_unpack_announces_list(chat->log, data, data_length,
8296
1.44k
                                   announces, GCA_MAX_SENT_ANNOUNCES);
8297
8298
1.44k
    if (gc_announces_count == -1) {
8299
0
        return false;
8300
0
    }
8301
8302
1.44k
    const int added_peers = gc_add_peers_from_announces(chat, announces, gc_announces_count);
8303
8304
1.44k
    return added_peers >= 0;
8305
1.44k
}
8306
8307
/** @brief Adds TCP relays from `announce` to the TCP relays list for `gconn`.
8308
 *
8309
 * Returns the number of relays successfully added.
8310
 */
8311
static uint32_t add_gc_tcp_relays_from_announce(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull gconn, const GC_Announce *_Nonnull announce)
8312
181
{
8313
181
    uint32_t added_relays = 0;
8314
8315
181
    for (uint8_t j = 0; j < announce->tcp_relays_count; ++j) {
8316
0
        const int add_tcp_result = add_tcp_relay_connection(chat->tcp_conn, gconn->tcp_connection_num,
8317
0
                                   &announce->tcp_relays[j].ip_port,
8318
0
                                   announce->tcp_relays[j].public_key);
8319
8320
0
        if (add_tcp_result == -1) {
8321
0
            continue;
8322
0
        }
8323
8324
0
        if (gcc_save_tcp_relay(chat->rng, gconn, &announce->tcp_relays[j]) == -1) {
8325
0
            continue;
8326
0
        }
8327
8328
0
        if (added_relays == 0) {
8329
0
            memcpy(gconn->oob_relay_pk, announce->tcp_relays[j].public_key, CRYPTO_PUBLIC_KEY_SIZE);
8330
0
        }
8331
8332
0
        ++added_relays;
8333
0
    }
8334
8335
181
    return added_relays;
8336
181
}
8337
8338
int gc_add_peers_from_announces(GC_Chat *chat, const GC_Announce *announces, uint8_t gc_announces_count)
8339
1.44k
{
8340
1.44k
    if (chat == nullptr || announces == nullptr) {
8341
0
        return -1;
8342
0
    }
8343
8344
1.44k
    if (!is_public_chat(chat)) {
8345
0
        return 0;
8346
0
    }
8347
8348
1.44k
    int added_peers = 0;
8349
8350
5.96k
    for (uint8_t i = 0; i < gc_announces_count; ++i) {
8351
4.51k
        const GC_Announce *announce = &announces[i];
8352
8353
4.51k
        if (!gca_is_valid_announce(announce)) {
8354
0
            continue;
8355
0
        }
8356
8357
4.51k
        const bool ip_port_set = announce->ip_port_is_set;
8358
4.51k
        const IP_Port *ip_port = ip_port_set ? &announce->ip_port : nullptr;
8359
4.51k
        const int peer_number = peer_add(chat, ip_port, announce->peer_public_key);
8360
8361
4.51k
        GC_Connection *gconn = get_gc_connection(chat, peer_number);
8362
8363
4.51k
        if (gconn == nullptr) {
8364
4.33k
            continue;
8365
4.33k
        }
8366
8367
181
        const uint32_t added_tcp_relays = add_gc_tcp_relays_from_announce(chat, gconn, announce);
8368
8369
181
        if (!ip_port_set && added_tcp_relays == 0) {
8370
0
            LOGGER_ERROR(chat->log, "Got invalid announcement: %u relays, IPP set: %d",
8371
0
                         added_tcp_relays, ip_port_set);
8372
0
            continue;
8373
0
        }
8374
8375
181
        gconn->pending_handshake_type = HS_INVITE_REQUEST;
8376
8377
181
        if (!ip_port_set) {
8378
0
            gconn->is_oob_handshake = true;
8379
0
        }
8380
8381
181
        ++added_peers;
8382
181
    }
8383
8384
1.44k
    return added_peers;
8385
1.44k
}