upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/components/wisp_relay/deletion.c
diff options
context:
space:
mode:
Diffstat (limited to 'components/wisp_relay/deletion.c')
-rw-r--r--components/wisp_relay/deletion.c190
1 files changed, 190 insertions, 0 deletions
diff --git a/components/wisp_relay/deletion.c b/components/wisp_relay/deletion.c
new file mode 100644
index 0000000..7ad3c22
--- /dev/null
+++ b/components/wisp_relay/deletion.c
@@ -0,0 +1,190 @@
1#include "deletion.h"
2#include "relay_types.h"
3#include "cJSON.h"
4#include "esp_log.h"
5#include <inttypes.h>
6#include <stdlib.h>
7#include <string.h>
8
9static const char *TAG = "deletion";
10
11static int extract_event_id_field(const char *event_json, size_t len,
12 uint8_t id_out[32])
13{
14 cJSON *obj = cJSON_ParseWithLength(event_json, len);
15 if (!obj) return -1;
16 cJSON *id_item = cJSON_GetObjectItem(obj, "id");
17 if (!id_item || !cJSON_IsString(id_item) || strlen(id_item->valuestring) != 64) {
18 cJSON_Delete(obj);
19 return -1;
20 }
21 int ret = relay_hex_to_bytes(id_item->valuestring, 64, id_out, 32);
22 cJSON_Delete(obj);
23 return ret;
24}
25
26static char *extract_pubkey_hex(const char *event_json, size_t len)
27{
28 cJSON *obj = cJSON_ParseWithLength(event_json, len);
29 if (!obj) return NULL;
30 cJSON *pk = cJSON_GetObjectItem(obj, "pubkey");
31 char *result = NULL;
32 if (pk && cJSON_IsString(pk)) result = strdup(pk->valuestring);
33 cJSON_Delete(obj);
34 return result;
35}
36
37static int delete_by_e_tags(storage_engine_t *storage, const char *event_json,
38 size_t len, const char *deleter_pubkey)
39{
40 cJSON *obj = cJSON_ParseWithLength(event_json, len);
41 if (!obj) return 0;
42
43 cJSON *tags = cJSON_GetObjectItem(obj, "tags");
44 if (!tags || !cJSON_IsArray(tags)) { cJSON_Delete(obj); return 0; }
45
46 int deleted = 0;
47 int array_size = cJSON_GetArraySize(tags);
48
49 for (int i = 0; i < array_size; i++) {
50 cJSON *tag = cJSON_GetArrayItem(tags, i);
51 if (!cJSON_IsArray(tag)) continue;
52 cJSON *tag_name = cJSON_GetArrayItem(tag, 0);
53 if (!tag_name || !cJSON_IsString(tag_name)) continue;
54 if (strcmp(tag_name->valuestring, "e") != 0) continue;
55
56 cJSON *tag_val = cJSON_GetArrayItem(tag, 1);
57 if (!tag_val || !cJSON_IsString(tag_val)) continue;
58
59 uint8_t event_id[32];
60 if (relay_hex_to_bytes(tag_val->valuestring, 64, event_id, 32) != 0) continue;
61
62 storage_error_t err = storage_delete_event(storage, event_id);
63 if (err == STORAGE_OK) {
64 deleted++;
65 ESP_LOGI(TAG, "Deleted event: %.16s...", tag_val->valuestring);
66 }
67 }
68
69 cJSON_Delete(obj);
70 return deleted;
71}
72
73static int delete_by_a_tags(storage_engine_t *storage, const char *event_json,
74 size_t len, const char *deleter_pubkey,
75 uint64_t created_at)
76{
77 cJSON *obj = cJSON_ParseWithLength(event_json, len);
78 if (!obj) return 0;
79
80 cJSON *tags = cJSON_GetObjectItem(obj, "tags");
81 if (!tags || !cJSON_IsArray(tags)) { cJSON_Delete(obj); return 0; }
82
83 int deleted = 0;
84 int array_size = cJSON_GetArraySize(tags);
85
86 for (int i = 0; i < array_size; i++) {
87 cJSON *tag = cJSON_GetArrayItem(tags, i);
88 if (!cJSON_IsArray(tag)) continue;
89 cJSON *tag_name = cJSON_GetArrayItem(tag, 0);
90 if (!tag_name || !cJSON_IsString(tag_name)) continue;
91 if (strcmp(tag_name->valuestring, "a") != 0) continue;
92
93 cJSON *tag_val = cJSON_GetArrayItem(tag, 1);
94 if (!tag_val || !cJSON_IsString(tag_val)) continue;
95
96 int32_t kind;
97 char pubkey[65] = {0};
98 char d_tag[256] = "";
99 if (sscanf(tag_val->valuestring, "%" SCNd32 ":%64[^:]:%255s",
100 &kind, pubkey, d_tag) < 2)
101 continue;
102
103 if (strcmp(pubkey, deleter_pubkey) != 0) continue;
104
105 char **results = NULL;
106 uint16_t count = 0;
107 storage_query_events_json(storage, kind, pubkey, 100, &results, &count);
108 for (uint16_t e = 0; e < count; e++) {
109 if (storage_delete_event(storage, (const uint8_t *)results[e]) == STORAGE_OK) {
110 deleted++;
111 }
112 }
113 storage_free_query_results(results, count);
114 }
115
116 cJSON_Delete(obj);
117 return deleted;
118}
119
120static int delete_by_k_tags(storage_engine_t *storage, const char *event_json,
121 size_t len, const char *deleter_pubkey,
122 uint64_t created_at)
123{
124 cJSON *obj = cJSON_ParseWithLength(event_json, len);
125 if (!obj) return 0;
126
127 cJSON *tags = cJSON_GetObjectItem(obj, "tags");
128 if (!tags || !cJSON_IsArray(tags)) { cJSON_Delete(obj); return 0; }
129
130 int deleted = 0;
131 int array_size = cJSON_GetArraySize(tags);
132
133 for (int i = 0; i < array_size; i++) {
134 cJSON *tag = cJSON_GetArrayItem(tags, i);
135 if (!cJSON_IsArray(tag)) continue;
136 cJSON *tag_name = cJSON_GetArrayItem(tag, 0);
137 if (!tag_name || !cJSON_IsString(tag_name)) continue;
138 if (strcmp(tag_name->valuestring, "k") != 0) continue;
139
140 cJSON *tag_val = cJSON_GetArrayItem(tag, 1);
141 if (!tag_val || !cJSON_IsString(tag_val)) continue;
142
143 int kind = atoi(tag_val->valuestring);
144
145 char **results = NULL;
146 uint16_t count = 0;
147 storage_query_events_json(storage, kind, deleter_pubkey, 500, &results, &count);
148 for (uint16_t e = 0; e < count; e++) {
149 uint8_t eid[32];
150 if (extract_event_id_field(results[e], strlen(results[e]), eid) == 0) {
151 storage_delete_event(storage, eid);
152 deleted++;
153 }
154 }
155 storage_free_query_results(results, count);
156 }
157
158 cJSON_Delete(obj);
159 return deleted;
160}
161
162int deletion_process_json(storage_engine_t *storage, const char *event_json,
163 size_t event_len)
164{
165 if (!storage || !event_json) return 0;
166
167 cJSON *obj = cJSON_ParseWithLength(event_json, event_len);
168 if (!obj) return 0;
169 cJSON *kind_item = cJSON_GetObjectItem(obj, "kind");
170 int kind = kind_item ? kind_item->valueint : 0;
171 cJSON *pk_item = cJSON_GetObjectItem(obj, "pubkey");
172 const char *pubkey = pk_item ? pk_item->valuestring : "";
173 cJSON *ca_item = cJSON_GetObjectItem(obj, "created_at");
174 uint64_t created_at = ca_item ? (uint64_t)ca_item->valuedouble : 0;
175 cJSON_Delete(obj);
176
177 if (kind != NOSTR_KIND_DELETION) return 0;
178
179 char *deleter_pk = strdup(pubkey);
180 if (!deleter_pk) return 0;
181
182 int deleted = 0;
183 deleted += delete_by_e_tags(storage, event_json, event_len, deleter_pk);
184 deleted += delete_by_a_tags(storage, event_json, event_len, deleter_pk, created_at);
185 deleted += delete_by_k_tags(storage, event_json, event_len, deleter_pk, created_at);
186
187 free(deleter_pk);
188 ESP_LOGI(TAG, "Deletion processed: %d events removed", deleted);
189 return deleted;
190}