Coverage Report

Created: 2026-10-24 08:16

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