1 /* SPDX-License-Identifier: GPL-3.0-or-later
2 * Copyright © 2016-2018 The TokTok team.
3 * Copyright © 2013 Tox project.
4 */
5
6 /*
7 * Handle friend requests.
8 */
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
12
13 #include "friend_requests.h"
14
15 #include <stdlib.h>
16 #include <string.h>
17
18 #include "util.h"
19
20 /* NOTE: The following is just a temporary fix for the multiple friend requests received at the same time problem.
21 * TODO(irungentoo): Make this better (This will most likely tie in with the way we will handle spam.)
22 */
23 #define MAX_RECEIVED_STORED 32
24
25 struct Received_Requests {
26 uint8_t requests[MAX_RECEIVED_STORED][CRYPTO_PUBLIC_KEY_SIZE];
27 uint16_t requests_index;
28 };
29
30 struct Friend_Requests {
31 uint32_t nospam;
32 fr_friend_request_cb *handle_friendrequest;
33 uint8_t handle_friendrequest_isset;
34 void *handle_friendrequest_object;
35
36 filter_function_cb *filter_function;
37 void *filter_function_userdata;
38
39 struct Received_Requests received;
40 };
41
42 /* Set and get the nospam variable used to prevent one type of friend request spam. */
set_nospam(Friend_Requests * fr,uint32_t num)43 void set_nospam(Friend_Requests *fr, uint32_t num)
44 {
45 fr->nospam = num;
46 }
47
get_nospam(const Friend_Requests * fr)48 uint32_t get_nospam(const Friend_Requests *fr)
49 {
50 return fr->nospam;
51 }
52
53
54 /* Set the function that will be executed when a friend request is received. */
callback_friendrequest(Friend_Requests * fr,fr_friend_request_cb * function,void * object)55 void callback_friendrequest(Friend_Requests *fr, fr_friend_request_cb *function, void *object)
56 {
57 fr->handle_friendrequest = function;
58 fr->handle_friendrequest_isset = 1;
59 fr->handle_friendrequest_object = object;
60 }
61
62 /* Set the function used to check if a friend request should be displayed to the user or not. */
set_filter_function(Friend_Requests * fr,filter_function_cb * function,void * userdata)63 void set_filter_function(Friend_Requests *fr, filter_function_cb *function, void *userdata)
64 {
65 fr->filter_function = function;
66 fr->filter_function_userdata = userdata;
67 }
68
69 /* Add to list of received friend requests. */
addto_receivedlist(Friend_Requests * fr,const uint8_t * real_pk)70 static void addto_receivedlist(Friend_Requests *fr, const uint8_t *real_pk)
71 {
72 if (fr->received.requests_index >= MAX_RECEIVED_STORED) {
73 fr->received.requests_index = 0;
74 }
75
76 id_copy(fr->received.requests[fr->received.requests_index], real_pk);
77 ++fr->received.requests_index;
78 }
79
80 /* Check if a friend request was already received.
81 *
82 * return false if it did not.
83 * return true if it did.
84 */
request_received(const Friend_Requests * fr,const uint8_t * real_pk)85 static bool request_received(const Friend_Requests *fr, const uint8_t *real_pk)
86 {
87 for (uint32_t i = 0; i < MAX_RECEIVED_STORED; ++i) {
88 if (id_equal(fr->received.requests[i], real_pk)) {
89 return true;
90 }
91 }
92
93 return false;
94 }
95
96 /* Remove real pk from received.requests list.
97 *
98 * return 0 if it removed it successfully.
99 * return -1 if it didn't find it.
100 */
remove_request_received(Friend_Requests * fr,const uint8_t * real_pk)101 int remove_request_received(Friend_Requests *fr, const uint8_t *real_pk)
102 {
103 for (uint32_t i = 0; i < MAX_RECEIVED_STORED; ++i) {
104 if (id_equal(fr->received.requests[i], real_pk)) {
105 crypto_memzero(fr->received.requests[i], CRYPTO_PUBLIC_KEY_SIZE);
106 return 0;
107 }
108 }
109
110 return -1;
111 }
112
113
friendreq_handlepacket(void * object,const uint8_t * source_pubkey,const uint8_t * packet,uint16_t length,void * userdata)114 static int friendreq_handlepacket(void *object, const uint8_t *source_pubkey, const uint8_t *packet, uint16_t length,
115 void *userdata)
116 {
117 Friend_Requests *const fr = (Friend_Requests *)object;
118
119 if (length <= 1 + sizeof(fr->nospam) || length > ONION_CLIENT_MAX_DATA_SIZE) {
120 return 1;
121 }
122
123 ++packet;
124 --length;
125
126 if (fr->handle_friendrequest_isset == 0) {
127 return 1;
128 }
129
130 if (request_received(fr, source_pubkey)) {
131 return 1;
132 }
133
134 if (memcmp(packet, &fr->nospam, sizeof(fr->nospam)) != 0) {
135 return 1;
136 }
137
138 if (fr->filter_function) {
139 if (fr->filter_function(source_pubkey, fr->filter_function_userdata) != 0) {
140 return 1;
141 }
142 }
143
144 addto_receivedlist(fr, source_pubkey);
145
146 const uint32_t message_len = length - sizeof(fr->nospam);
147 VLA(uint8_t, message, message_len + 1);
148 memcpy(message, packet + sizeof(fr->nospam), message_len);
149 message[SIZEOF_VLA(message) - 1] = 0; /* Be sure the message is null terminated. */
150
151 fr->handle_friendrequest(fr->handle_friendrequest_object, source_pubkey, message, message_len, userdata);
152 return 0;
153 }
154
friendreq_init(Friend_Requests * fr,Friend_Connections * fr_c)155 void friendreq_init(Friend_Requests *fr, Friend_Connections *fr_c)
156 {
157 set_friend_request_callback(fr_c, &friendreq_handlepacket, fr);
158 }
159
friendreq_new(void)160 Friend_Requests *friendreq_new(void)
161 {
162 return (Friend_Requests *)calloc(1, sizeof(Friend_Requests));
163 }
164
friendreq_kill(Friend_Requests * fr)165 void friendreq_kill(Friend_Requests *fr)
166 {
167 free(fr);
168 }
169