summaryrefslogtreecommitdiff
path: root/docs/Avatars.md
blob: f0d7a1eb1f5eadebf4e94dfbf9cc11ac30946fe9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
# User avatars in Tox



## Introduction and rationale

User avatars are small icons or images used to identify users in the friend
list; they exists in virtually all VoIP and IM protocols and provide an easy
way to an user identify another in the friend list.

This document describes the implementation of avatars in the Tox protocol,
according to the following design considerations:

  - Avatars are handled as private information, ie., only exchanged over
    Tox encrypted channels among previously authenticated friends;

  - The library treats all images as blobs and does not interpret or
    understands image formats, only ensures that the avatar data sent by
    an user is correctly received by the other. The client application is
    responsible for validating, decoding, resizing, and presenting the
    image to the user.

  - There is a strict limit of 16 KiB to the avatar raw data size -- this
    seems suitable for practical use as, for example, the raw data of an
    uncompressed 64 x 64 pixels 24 bpp RGB bitmap is 12288 bytes long; the
    data limit provides enough space for larger bitmaps if the usual
    compressed formats are used.

    **Notice:** As designed, this limit can be changed in the future without
    breaking the protocol compatibility, but clients using the original
    limit will reject larger avatars;

  - The protocol MUST provide means to allow caching and avoid unnecessary
    data transfers;

  - Avatars are transfered between clients in a background operation;

  - Avatars are served in a "best effort" basis, without breaking clients
    who do not support them;

  - The protocol MUST resist to malicious users;

  - The protocol MUST work with both UDP and TCP networks.


The Single Tox Standard Draft v.0.1.0 recommends implementing avatars as
a purely client-side feature through a procedure that can be summarized as
sending a specially named file as a file transfer request and accepting
it silently. This procedure can be improved to provide the previously stated
design considerations, but this requires a higher integration with the core
protocol. Moving this feature to the core protocol also:

  - Provides a simpler and cleaner interfaces for client applications;

  - Hides protocol complexities from the client;

  - Avoids code duplication and ad-hoc protocols in the clients;

  - Avoids incompatibility between client implementations;

  - Allows important optimizations such as lightweight notification of
    removed and updated avatars;

  - Plays well with cache schemes;

  - Makes avatar transfer an essentially background operation.






## High level description

The avatar exchange is implemented with the following new elements in the
Tox protocol. This is a very high level description and the usage patterns
expected from client applications are described in Section "Using Avatars
in Client Applications" and a low level protocol description is available
in Section "Internal Protocol Description".

  - **Avatar Information Notifications** are events which may be sent by
    an user to another anytime, but are usually sent after one of them
    connects to the network, changes his avatar, or in reply to an **avatar
    information request**. They are delivered by a very lightweight message
    but with information enough to allow an user to validate or discard an
    avatar from the local cache and decide if is interesting to request the
    avatar data from the peer.

    This event contain two data fields: (1) the image format and (2) the
    cryptographic hash of the actual image data. Image format may be NONE
    (for users who have no avatar or removed their avatars) or PNG. The
    cryptographic hash is intended to be compared with the hash o the
    currently cached avatar (if any) and check if it stills up to date.

  - **Avatar Information Requests** are very lightweight messages sent by an
    user asking for an **avatar information notification**. They may be sent
    as part of the login process or when the client thinks the currently
    cached avatar is outdated. The receiver may or may not answer to this
    request. This message contains no data fields;

  - An **Avatar Data Request** is sent by an user asking another for his
    complete avatar data. It is sent only when the requesting user decides
    the avatar do not exists in the local cache or is outdated. The receiver
    may or may not answer to this request. This message contains no data
    fields.

  - An **Avatar Data Notification** is an event signaling the client that
    the complete avatar image data of another user is available. The actual
    data transfer is implemented using several data and control messages,
    but the details are hidden from the client applications. This event can
    only arrive in reply to an **avatar data request**.

    This event contains three data fields: (1) the image format, (2) the
    cryptographic hash of the image data, and (3) the raw image data. If the
    image format is NONE (i.e. no avatar) the hash is zeroed and the image
    data is empty. The raw image data is locally validated and ensured to
    match the hash (the event is **not** triggered otherwise).





## API

To implement this feature, the following public symbols were added. The
complete API documentation is available in `tox.h`.


```
#define TOX_MAX_AVATAR_DATA_LENGTH 16384
#define TOX_AVATAR_HASH_LENGTH 32


/* Data formats for user avatar images */
typedef enum {
    TOX_AVATARFORMAT_NONE,
    TOX_AVATARFORMAT_PNG
}
TOX_AVATARFORMAT;



/* Set the user avatar image data. */
int tox_set_avatar(Tox *tox, uint8_t format, const uint8_t *data, uint32_t length);

/* Get avatar data from the current user. */
int tox_get_self_avatar(const Tox *tox, uint8_t *format, uint8_t *buf, uint32_t *length, uint32_t maxlen, uint8_t *hash);

/* Generates a cryptographic hash of the given avatar data. */
int tox_avatar_hash(const Tox *tox, uint8_t *hash, const uint8_t *data, const uint32_t datalen);

/* Request avatar information from a friend. */
int tox_request_avatar_info(const Tox *tox, const int32_t friendnumber);

/* Send an unrequested avatar information to a friend. */
int tox_send_avatar_info(Tox *tox, const int32_t friendnumber);

/* Request the avatar data from a friend. */
int tox_request_avatar_data(const Tox *tox, const int32_t friendnumber);

/* Set the callback function for avatar data. */
void tox_callback_avatar_info(Tox *tox, void (*function)(Tox *tox, int32_t, uint8_t, uint8_t*, void *), void *userdata);

/* Set the callback function for avatar data.  */
void tox_callback_avatar_data(Tox *tox, void (*function)(Tox *tox, int32_t, uint8_t, uint8_t*, uint8_t*, uint32_t, void *), void *userdata);
```




## Using Avatars in Client Applications


### General recommendations

  - Clients MUST NOT imply the availability of avatars in other users.
    Avatars are an optional feature and not all users and clients may
    support them;

  - Clients MUST NOT block waiting for avatar information and avatar data
    packets;

  - Clients MUST treat avatar data as insecure and potentially malicious;
    For example, users may accidentally use corrupted images as avatars,
    a malicious user may send a specially crafted image to exploit a know
    vulnerability in an image decoding library, etc. It is recommended to
    handle the avatar image data in the same way as an image downloaded
    from an unknown Internet source;

  - The peers MUST NOT assume any coupling between the operations of
    receiving an avatar information packet, sending unrequested avatar
    information packets, requesting avatar data, or receiving avatar data.

    For example, the following situations are valid:

      * A text-mode client may send avatars to other users, but never
        request them;

      * A client may not understand a particular image format and ignore
        avatars using it, but request and handle other formats;

  - Clients SHOULD implement a local cache of avatars and do not request
    avatar data from other peers unless necessary;

  - When an avatar information is received, the client should delete the
    avatar if the new avatar format is NONE or compare the hash received
    from the peer with the hash of the currently cached avatar. If they
    differ, send an avatar data request;

  - If the cached avatar is older than a given threshold, the client may
    also send an avatar info request to that friend once he is online and
    mark the avatar as updated *before* any avatar information is received
    (to not spam the peer with such requests);

  - When an avatar data notification is received, the client must update
    the cached avatar with the new one;

  - Clients should resize or crop the image to the way it better adapts
    to the client user interface;

  - If the user already have an avatar defined in the client configuration,
    it must be set before connecting to the network to avoid spurious avatar
    change notifications and unnecessary data transfers.

  - If no avatar data is available for a given friend, the client should
    show a placeholder image.



### Interoperability and sharing avatars among different clients

**This section is a tentative recommendation of how clients should store
avatars to ensure local interoperability and should be revised if this
code is accepted into Tox core.**

It is desirable that the user avatar and the cached friends avatars could be
shared among different Tox clients in the same system, in the spirit of the
proposed Single Tox Standard. This not only makes switching from one client
to another easier, but also minimizes the need of data transfers, as avatars
already downloaded by other clients can be reused.

Given the Tox data directory described in STS Draft v0.1.0:

  - The user avatar is stored in a file named "avatar.png". As more formats
    may be used in the future, another extensions are reserved and clients
    should keep just one file named "avatar.*", with the data of the last
    avatar set by the user. If the user have no avatar, no such files should
    be kept in the data directory;

  - Friends avatars are stored in a directory called "avatars" and named
    as "xxxxx.png", where "xxxxx" is the complete client id encoded as an
    uppercase hexadecimal string and "png" is the extension for the PNG
    avatar. As new image formats may be used in the future, clients should
    ensure no other file "xxxxx.*" exists. No file should be kept for an user
    who have no avatar.

    **To be discussed:** User keys are usually presented in Tox clients as
    upper case strings, but lower case file names are more usual.


Example for Linux and other Unix systems, assuming an user called "gildor":

    Tox data directory: /home/gildor/.config/tox/
    Tox data file:      /home/gildor/.config/tox/data
    Gildor's avatar:    /home/gildor/.config/tox/avatar.png
    Avatar data dir:    /home/gildor/.config/tox/avatars/
    Elrond's avatar:    /home/gildor/.config/tox/avatars/43656C65627269616E20646F6E277420546F782E426164206D656D6F72696573.png
    Elladan's avatar:   /home/gildor/.config/tox/avatars/49486174655768656E48756D616E735468696E6B49416D4D7942726F74686572.png
    Elrohir's avatar    /home/gildor/.config/tox/avatars/726568746F7242794D6D41496B6E696854736E616D75486E6568576574614849.png
    Arwen's avatar:     /home/gildor/.config/tox/avatars/53686520746F6F6B20476C6F7266696E64656C277320706C6163652068657265.png
    Lindir's avatar:    /home/gildor/.config/tox/avatars/417070735772697474656E42794D6F7274616C734C6F6F6B54686553616D652E.png

This recommendation is partially implemented by "testing/test_avatars.c".





### Common operations

These are minimal examples of how perform common operations with avatar
functions. For a complete, working, example, see `testing/test_avatars.c`.


#### Setting an avatar for the current user

In this example `load_data_file` is just an hypothetical function that loads
data from a file into the buffer and sets the length accordingly.

    uint8_t buf[TOX_MAX_AVATAR_DATA_LENGTH];
    uint32_t len;

    if (load_data_file("avatar.png", buf, &len) == 0)
        if (tox_set_avatar(tox, TOX_AVATARFORMAT_PNG, buf, len) != 0)
            fprintf(stderr, "Failed to set avatar.\n");

If the user is connected, this function will also notify all connected
friends about the avatar change.

If the user already have an avatar defined in the client configuration, it
must be set before connecting to the network to avoid spurious avatar change
notifications and unnecessary data transfers.




#### Removing the avatar from the current user

To remove an avatar, an application must set it to `TOX_AVATARFORMAT_NONE`.

    tox_set_avatar(tox, TOX_AVATARFORMAT_NONE, NULL, 0);

If the user is connected, this function will also notify all connected
friends about the avatar change.





#### Receiving avatar information from friends

All avatar information is passed to a callback function with the prototype:

    void function(Tox *tox, int32_t friendnumber, uint8_t format,
        uint8_t *hash, uint8_t *data, uint32_t datalen, void *userdata)

As in this example:

    static void avatar_info_cb(Tox *tox, int32_t friendnumber, uint8_t format,
            uint8_t *hash, void *userdata)
    {
        printf("Receiving avatar information from friend %d. Format = %d\n",
            friendnumber, format);
        printf("Data hash: ");
        hex_printf(hash, TOX_AVATAR_HASH_LENGTH);   /* Hypothetical function */
        printf("\n");
    }

And, somewhere in the Tox initialization calls, set if as the callback to be
triggered when an avatar information event arrives:

    tox_callback_avatar_info(tox, avatar_info_cb, NULL);


A typical client will test the currently cached avatar against the hash given
in the avatar information event and, if needed, request the avatar data.



#### Receiving avatar data from friends

Avatar data events are only delivered in reply of avatar data requests which
**should** only be sent after getting the user avatar information (format
and hash) from an avatar information event and checking it against a local
cache.

For this, an application must define an avatar information callback which
checks the local avatar cache and emits an avatar data request if necessary:

    static void avatar_info_cb(Tox *tox, int32_t friendnumber, uint8_t format,
            uint8_t *hash, void *userdata)
    {
        printf("Receiving avatar information from friend %d. Format = %d\n",
            friendnumber, format);
        if (format = TOX_AVATARFORMAT_NONE) {
            /* User have no avatar or removed the avatar */
            delete_avatar_from_cache(tox, friendnumber);
        } else {
            /* Use the received hash to check if the cached avatar is
               still updated. */
            if (!is_user_cached_avatar_updated(tox, friendnumber, hash)) {
                /* User avatar is outdated, send data request */
                tox_request_avatar_data(tox, friendnumber);
            }
        }
    }


Then define an avatar data callback to store the received data in the local
cache:

    static void avatar_data_cb(Tox *tox, int32_t friendnumber, uint8_t format,
        uint8_t *hash, uint8_t *data, uint32_t datalen, void *userdata)
    {
        if (format = TOX_AVATARFORMAT_NONE) {
            /* User have no avatar or removed the avatar */
            delete_avatar_from_cache(tox, friendnumber);
        } else {
            save_avatar_data_to_cache(tox, friendnumber, format, hash,
                data, datalen);
        }
    }


And, finally, register both callbacks somewhere in the Tox initialization
calls:

    tox_callback_avatar_info(tox, avatar_info_cb, NULL);
    tox_callback_avatar_data(tox, avatar_data_cb, NULL);


In the previous examples, implementation of the functions to check, store
and retrieve data from the cache were omitted for brevity. These functions
will also need to get the friend client ID (public key) from they friend
number and, usually, convert it from a byte string to a hexadecimal
string. A complete, yet more complex, example is available in the file
`testing/test_avatars.c`.











## Internal Protocol Description

### New packet types

The avatar transfer protocol adds the following new packet types and ids:

    PACKET_ID_AVATAR_INFO_REQ = 52
    PACKET_ID_AVATAR_INFO = 53
    PACKET_ID_AVATAR_DATA_CONTROL = 54
    PACKET_ID_AVATAR_DATA_START = 55
    PACKET_ID_AVATAR_DATA_PUSH = 56




### Requesting avatar information

To request avatar information, an user must send a packet of type
`PACKET_ID_AVATAR_INFO_REQ`. This packet have no data fields. Upon
receiving this packet, a client which supports avatars should answer with
a `PACKET_ID_AVATAR_INFO`. The sender must accept that the friend may
not answer at all.




### Receiving avatar information

Avatar information arrives in a packet of type `PACKET_ID_AVATAR_INFO` with
the following structure:

    PACKET_ID_AVATAR_INFO (53)
    Packet data size: 33 bytes
    [1: uint8_t format][32: uint8_t hash]

Where 'format' is the image data format, one of the following:

    0 = AVATARFORMAT_NONE  (no avatar set)
    1 = AVATARFORMAT_PNG

and 'hash' is the SHA-256 message digest of the avatar data.

This packet may be sent at any time and no previous request is required.
Clients should send this packet upon connection or when a friend
connects, in the same way Tox sends name, status and action information.





### Requesting avatar data

Transmission of avatar data is a multi-step procedure using three new packet
types.

  - Packet `PACKET_ID_AVATAR_DATA_CONTROL` have the format:

        PACKET_ID_AVATAR_DATA_CONTROL (54)
        Packet data size: 5 bytes
        [1: uint8_t op][1: uint32_t bytes_received]

    where 'op' is a code signaling both an operation request or a status
    return, which semantics are explained bellow. The following values are
    defined:

        0 = AVATARDATACONTROL_REQ
        1 = AVATARDATACONTROL_MORE
        2 = AVATARDATACONTROL_ERROR

    and 'bytes_received' is the number of bytes already received by the
    client when the operation is `MORE` or zero otherwise.


  - Packet `PACKET_ID_AVATAR_DATA_START` have the following format:

        PACKET_ID_AVATAR_DATA_START (55)
        Packet data size: 37 bytes
        [1: uint8_t format][32: uint8_t hash][1: uint32_t data_length]


    where 'format' is the image format, with the same values accepted for
    the field 'format' in packet type `PACKET_ID_AVATAR_INFO`, 'hash' is
    the SHA-256 cryptographic hash of the avatar raw data and 'data_length'
    is the total number of bytes the raw avatar data.


  - Packet `PACKET_ID_AVATAR_DATA_PUSH` have no format structure, just up
    to `AVATAR_DATA_MAX_CHUNK_SIZE` (56) bytes of raw avatar image data.



The following procedure assumes that a client "A" is requesting avatar data
from a client "B":

  - "A" must initialize its control structures and mark its data transfer
    as not yet started. Then it requests avatar data from "B" by sending a
    packet `PACKET_ID_AVATAR_DATA_CONTROL` with 'op' set to
    `AVATARDATACONTROL_REQ`. The field 'bytes_received' must be present, but
    should be set to zero and is ignored in this step.

  - If "B" accepts this transfer, it answers by sending an
    `PACKET_ID_AVATAR_DATA_START` with the fields 'format', 'hash' and
    'data_length' set to the respective values from the current avatar.
    If "B" have no avatar set, 'format' must be `AVATARFORMAT_NONE`, 'hash'
    must be zeroed and 'data_length' must be zero.

    If "B" does not accept sending the avatar, it may send a packet
    `PACKET_ID_AVATAR_DATA_CONTROL` with the field 'op' set to
    `AVATARDATACONTROL_ERROR` or simply ignore this request. "A" must cope
    with this.

  - Upon receiving a `PACKET_ID_AVATAR_DATA_START`, "A" checks if it
    has sent a data request to "B". If not, just ignores the packet.

    If "A" really sent a request to "B", checks if the request was already
    started. If true, it is an error and it just ignores the request.

    Otherwise, "A" decodes the message data and checks if the avatar data
    length stated in the field 'data_length' is acceptable (ie. less or
    equal than `TOX_MAX_AVATAR_DATA_LENGTH`). If not, it replies with an
    `PACKET_ID_AVATAR_DATA_CONTROL` with the field 'op' set to
    `AVATARDATACONTROL_ERROR` (or just ignores this, "A" holds no state).

    If the size is acceptable, "A" marks the request as stated, stores the
    format, hash, and data length in the local state for user "B", sets a
    counter for the number of bytes received from the peer and replies with
    a `PACKET_ID_AVATAR_DATA_CONTROL` with the field 'op' set to
    `AVATARDATACONTROL_MORE` and 'bytes_received' set to zero (as no data
    was received yet).

  - Upon receiving a `PACKET_ID_AVATAR_DATA_CONTROL` with op
    `AVATARDATACONTROL_MORE`, "B" sends an `PACKET_ID_AVATAR_DATA_PUSH`
    with up to `AVATAR_DATA_MAX_CHUNK_SIZE` bytes of data from the avatar,
    starting from the offset stated in the field 'bytes_received'.

    If the requested offset is invalid, "B" replies with a
    `PACKET_ID_AVATAR_DATA_CONTROL` with the field 'op' set to
    `AVATARDATACONTROL_ERROR`.

    "B" must have full control of the amount of data it sends to "A" and
    may, at any time, abort the transfer by sending a
    `PACKET_ID_AVATAR_DATA_CONTROL` with the field 'op' set to
    `AVATARDATACONTROL_ERROR`. This may happens, for example, if some limit
    was hit or a network data usage throttle enabled. A rationale for this
    procedures is available in section "Security considerations".

  - Upon receiving a `PACKET_ID_AVATAR_DATA_PUSH`, "A" checks if the total
    length of the data already stored in the receiving buffer plus the data
    present in the push packet is still less or equal than
    `TOX_MAX_AVATAR_DATA_LENGTH`. If invalid, it replies with a
    `PACKET_ID_AVATAR_DATA_CONTROL` with the field 'op' set to
    `AVATARDATACONTROL_ERROR`.

    If valid, "A" updates the 'bytes_received' counter and concatenates the
    newly arrived data to the buffer.

    The "A" checks if all the data was already received by comparing the
    counter 'bytes_received' with the field 'total_length'. If they are
    equal, "A" takes a SHA-256 hash of the data and compares it with the
    hash stored in the field 'hash' received from the first
    `PACKET_ID_AVATAR_DATA_START`.

    If the hashes match, the avatar data was correctly received and "A"
    triggers the avatar data callback, and clears all the temporary data,
    finishing the process.

    If not all data was received, "A" requests more data by sending a
    `PACKET_ID_AVATAR_DATA_CONTROL` with the field 'op' set to
    `AVATARDATACONTROL_MORE` and 'bytes_received' set to the new offset.

    Client "A" is always responsible for controlling the transfer and
    validating the data received. "B" don't need to keep any state for the
    protocol, have full control over the data sent and should implement
    some transfer limit for the data it sends.

    This "chatty" protocol mitigates a potential amplification attack,
    i.e., a malicious friend sending a very small data packet that causes
    another user to send a larger amount of data.  The hash validation
    ensures that the avatar data is correct even if "B" changed its avatar
    data in the middle of the transfer. A rationale for this procedures is
    available in section "Security considerations".

  - Any peer receiving a `PACKET_ID_AVATAR_DATA_CONTROL` with the field 'op'
    set to `AVATARDATACONTROL_ERROR` clears any existing control state and
    finishes sending or receiving data.





## Security considerations

The major security implication of background data transfers of large objects,
like avatars, is the possibility of exhausting the network resources from a
client. This problem is exacerbated when there is the possibility of an
amplification attack as happens, for example, when sending a very small
avatar request message will force the user to reply with a larger avatar
data message.

The present proposal mitigates this situation by:

  - Only transferring data between previously authenticated friends;

  - Enforcing strict limits on the avatar data size;

  - Providing an alternate, smaller, message to cooperative users refresh
    avatar information when nothing has changed (`PACKET_ID_AVATAR_INFO`);

  - Making the avatar data transfer chatty: The user requesting avatar data
    can not force a peer to send large amounts of data in a single shot and
    must request new chunks as needed. The sender will never send more that
    1 kB of data in a single push and have ultimate control over the amount
    of data sent in a chunk;

  - Having per-friend data transfer limit. As the current protocol still
    allows an user to request an infinite data stream by asking the the
    same offset of the avatar again and again, the implementation limits
    the amount of data a single user can request for some time. For now,
    the library will not allow an user to request more than
    `10*TOX_MAX_AVATAR_DATA_LENGTH` in less than 20 minutes;

  - Making the requester responsible for storing partial data and state
    information;

  - (currently not implemented) Treating avatar data transfers as a low
    priority operation, handled only if no other packets are being
    processed.

Another problem present in the avatars is the possibility of a friend send
a maliciously crafted image intended to exploit vulnerabilities in image
decoders. Without an intermediate server to recompress and validate and
convert the images to neutral formats, the client applications must handle
this situation by themselves using stable and secure image libraries and
imposing limits on the maximum amount of system resources the decoding
process can take. Images coming from Tox friends must be treated in the same
way as images coming from random Internet sources.