Coverage Report

Created: 2024-01-26 01:52

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