snac.h (19634B)
1 /* snac - A simple, minimalistic ActivityPub instance */ 2 /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ 3 4 #define VERSION "2.78" 5 6 #define USER_AGENT "snac/" VERSION 7 8 #define WHAT_IS_SNAC_URL "https:/" "/comam.es/what-is-snac" 9 10 #define DIR_PERM 00770 11 #define DIR_PERM_ADD 02770 12 13 #define ISO_DATE_SPEC "%Y-%m-%dT%H:%M:%SZ" 14 15 #ifndef MAX_THREADS 16 #define MAX_THREADS 256 17 #endif 18 19 #ifndef MAX_JSON_DEPTH 20 #define MAX_JSON_DEPTH 8 21 #endif 22 23 #ifndef MAX_CONVERSATION_LEVELS 24 #define MAX_CONVERSATION_LEVELS 48 25 #endif 26 27 #define MD5_HEX_SIZE 33 28 29 #define MD5_ALREADY_SEEN_MARK "00000000000000000000000000000000" 30 31 extern double disk_layout; 32 extern xs_str *srv_basedir; 33 extern xs_dict *srv_config; 34 extern xs_str *srv_baseurl; 35 extern xs_str *srv_proxy_token_seed; 36 extern xs_dict *srv_langs; 37 38 extern int dbglevel; 39 40 #define L(s) lang_str((s), user) 41 42 #define POSTLIKE_OBJECT_TYPE "Note|Question|Page|Article|Video|Audio|Event" 43 44 int mkdirx(const char *pathname); 45 int mkdiratx(int base, const char *pathname); 46 47 int valid_status(int status); 48 xs_str *tid(int offset); 49 double ftime(void); 50 51 void srv_log(xs_str *str); 52 #define srv_debug(level, str) do { if (dbglevel >= (level)) \ 53 { srv_log((str)); } } while (0) 54 55 typedef struct { 56 xs_str *uid; /* uid */ 57 xs_str *basedir; /* user base directory */ 58 xs_dict *config; /* user configuration */ 59 xs_dict *config_o; /* user configuration admin override */ 60 xs_dict *key; /* keypair */ 61 xs_dict *links; /* validated links */ 62 xs_str *actor; /* actor url */ 63 xs_str *md5; /* actor url md5 */ 64 const xs_dict *lang;/* string translation dict */ 65 const char *tz; /* configured timezone */ 66 int basedfd; 67 } snac; 68 69 typedef struct { 70 int s_size; /* struct size (for double checking) */ 71 int srv_running; /* server running on/off */ 72 int use_fcgi; /* FastCGI use on/off */ 73 time_t srv_start_time; /* start time */ 74 int job_fifo_size; /* job fifo size */ 75 int peak_job_fifo_size; /* maximum job fifo size seen */ 76 int n_threads; /* number of configured threads */ 77 enum { THST_STOP, THST_WAIT, THST_IN, THST_QUEUE } th_state[MAX_THREADS]; 78 } srv_state; 79 80 extern srv_state *p_state; 81 82 void snac_log(snac *user, xs_str *str); 83 #define snac_debug(user, level, str) do { if (dbglevel >= (level)) \ 84 { snac_log((user), (str)); } } while (0) 85 86 int srv_open(const char *basedir, int auto_upgrade); 87 void srv_free(void); 88 89 void sbox_enter(const char *basedir); 90 91 int user_open(snac *snac, const char *uid); 92 void user_free(snac *snac); 93 xs_list *user_list(void); 94 int user_open_by_md5(snac *snac, const char *md5); 95 int user_persist(snac *snac, int publish); 96 FILE *user_open_file(snac *snac, const char *file, int wr); 97 FILE *user_open_subfile(snac *snac, const char *sub, const char *file, int wr); 98 99 int validate_uid(const char *uid); 100 101 xs_str *hash_password(const char *uid, const char *passwd, const char *nonce); 102 int check_password(const char *uid, const char *passwd, const char *hash); 103 104 void srv_archive(const char *direction, const char *url, xs_dict *req, 105 const char *payload, int p_size, 106 int status, xs_dict *headers, 107 const char *body, int b_size); 108 void srv_archive_error(const char *prefix, const xs_str *err, 109 const xs_dict *req, const xs_val *data); 110 void srv_archive_qitem(const char *prefix, xs_dict *q_item); 111 112 double mtime_nl(const char *fn, int *n_link); 113 double mtime_f_nl(FILE *f, int *n_link); 114 #define mtime(fn) mtime_nl(fn, NULL) 115 #define mtime_f(f) mtime_f_nl(f, NULL) 116 double f_ctime(const char *fn); 117 118 int index_add_md5(const char *fn, const char *md5); 119 int index_add(const char *fn, const char *id); 120 int index_gc(const char *fn); 121 int index_first(const char *fn, char md5[MD5_HEX_SIZE]); 122 int index_len(const char *fn); 123 xs_list *index_list(const char *fn, int max); 124 int index_desc_next(FILE *f, char md5[MD5_HEX_SIZE]); 125 int index_desc_first(FILE *f, char md5[MD5_HEX_SIZE], int skip); 126 int index_asc_next(FILE *f, char md5[MD5_HEX_SIZE]); 127 int index_asc_first(FILE *f, char md5[MD5_HEX_SIZE], const char *seek_md5); 128 xs_list *index_list_desc(const char *fn, int skip, int show); 129 130 int object_add(const char *id, const xs_dict *obj); 131 int object_add_ow(const char *id, const xs_dict *obj); 132 int object_here_by_md5(const char *id); 133 int object_here(const char *id); 134 int object_get_by_md5(const char *md5, xs_dict **obj); 135 int object_get(const char *id, xs_dict **obj); 136 int object_del(const char *id); 137 int object_del_if_unref(const char *id); 138 double object_ctime_by_md5(const char *md5); 139 double object_ctime(const char *id); 140 double object_mtime_by_md5(const char *md5); 141 double object_mtime(const char *id); 142 void object_touch(const char *id); 143 144 int object_admire(const char *id, const char *actor, int like); 145 int object_unadmire(const char *id, const char *actor, int like); 146 147 int object_likes_len(const char *id); 148 int object_announces_len(const char *id); 149 150 xs_list *object_children(const char *id); 151 xs_list *object_likes(const char *id); 152 xs_list *object_announces(const char *id); 153 int object_parent(const char *md5, char parent[MD5_HEX_SIZE]); 154 155 int object_user_cache_add(snac *snac, const char *id, const char *cachedir); 156 int object_user_cache_del(snac *snac, const char *id, const char *cachedir); 157 158 int follower_add(snac *snac, const char *actor); 159 int follower_del(snac *snac, const char *actor); 160 int follower_check(snac *snac, const char *actor); 161 xs_list *follower_list(snac *snac); 162 int follower_list_len(snac *snac); 163 164 int pending_add(snac *user, const char *actor, const xs_dict *msg); 165 int pending_check(snac *user, const char *actor); 166 xs_dict *pending_get(snac *user, const char *actor); 167 void pending_del(snac *user, const char *actor); 168 xs_list *pending_list(snac *user); 169 int pending_count(snac *user); 170 171 double timeline_mtime(snac *snac); 172 int timeline_touch(snac *snac); 173 int timeline_here_by_md5(snac *snac, const char *md5); 174 int timeline_here(snac *snac, const char *id); 175 int timeline_get_by_md5(snac *snac, const char *md5, xs_dict **msg); 176 int timeline_del(snac *snac, const char *id); 177 xs_str *user_index_fn(snac *user, const char *idx_name); 178 xs_list *timeline_simple_list(snac *user, const char *idx_name, int skip, int show, int *more); 179 xs_list *timeline_list(snac *snac, const char *idx_name, int skip, int show, int *more); 180 int timeline_add(snac *snac, const char *id, const xs_dict *o_msg); 181 int timeline_admire(snac *snac, const char *id, const char *admirer, int like); 182 183 xs_list *timeline_top_level(snac *snac, const xs_list *list); 184 void timeline_add_mark(snac *user); 185 186 xs_list *local_list(snac *snac, int max); 187 xs_str *instance_index_fn(void); 188 xs_list *timeline_instance_list(int skip, int show); 189 190 int following_add(snac *snac, const char *actor, const xs_dict *msg); 191 int following_del(snac *snac, const char *actor); 192 int following_check(snac *snac, const char *actor); 193 int following_get(snac *snac, const char *actor, xs_dict **data); 194 xs_list *following_list(snac *snac); 195 int following_list_len(snac *snac); 196 197 void mute(snac *snac, const char *actor); 198 void unmute(snac *snac, const char *actor); 199 int is_muted(snac *snac, const char *actor); 200 xs_list *muted_list(snac *user); 201 202 int is_bookmarked(snac *user, const char *id); 203 int bookmark(snac *user, const char *id); 204 int unbookmark(snac *user, const char *id); 205 xs_list *bookmark_list(snac *user); 206 xs_str *bookmark_index_fn(snac *user); 207 208 int pin(snac *user, const char *id); 209 int unpin(snac *user, const char *id); 210 int is_pinned(snac *user, const char *id); 211 int is_pinned_by_md5(snac *user, const char *md5); 212 xs_list *pinned_list(snac *user); 213 214 int is_draft(snac *user, const char *id); 215 void draft_del(snac *user, const char *id); 216 void draft_add(snac *user, const char *id, const xs_dict *msg); 217 xs_list *draft_list(snac *user); 218 219 int is_scheduled(snac *user, const char *id); 220 void schedule_del(snac *user, const char *id); 221 void schedule_add(snac *user, const char *id, const xs_dict *msg); 222 xs_list *scheduled_list(snac *user); 223 void scheduled_process(snac *user); 224 225 int limited(snac *user, const char *id, int cmd); 226 #define is_limited(user, id) limited((user), (id), 0) 227 #define limit(user, id) limited((user), (id), 1) 228 #define unlimit(user, id) limited((user), (id), 2) 229 230 void hide(snac *snac, const char *id); 231 int is_hidden(snac *snac, const char *id); 232 233 void tag_index(const char *id, const xs_dict *obj); 234 xs_str *tag_fn(const char *tag); 235 xs_list *tag_search(const char *tag, int skip, int show); 236 237 xs_val *list_maint(snac *user, const char *list, int op); 238 xs_str *list_timeline_fn(snac *user, const char *list); 239 xs_list *list_timeline(snac *user, const char *list, int skip, int show); 240 xs_val *list_content(snac *user, const char *list_id, const char *actor_md5, int op); 241 void list_distribute(snac *user, const char *who, const xs_dict *post); 242 243 int actor_add(const char *actor, const xs_dict *msg); 244 int actor_get(const char *actor, xs_dict **data); 245 int actor_get_refresh(snac *user, const char *actor, xs_dict **data); 246 247 int static_get(snac *snac, const char *id, xs_val **data, int *size, const char *inm, xs_str **etag, int *mmapped); 248 int static_get_partial(snac *snac, const char *id, xs_val **data, int *size, const char *inm, xs_str **etag, int start, int *end); 249 void static_put(snac *snac, const char *id, const char *data, int size); 250 void static_put_meta(snac *snac, const char *id, const char *str); 251 xs_str *static_get_meta(snac *snac, const char *id); 252 253 double history_mtime(snac *snac, const char *id); 254 void history_add(snac *snac, const char *id, const char *content, int size, 255 xs_str **etag); 256 int history_get(snac *snac, const char *id, xs_str **content, int *size, 257 const char *inm, xs_str **etag, int *mmapped); 258 int history_del(snac *snac, const char *id); 259 xs_list *history_list(snac *snac); 260 261 void lastlog_write(snac *snac, const char *source); 262 263 xs_str *notify_check_time(snac *snac, int reset); 264 void notify_add(snac *snac, const char *type, const char *utype, 265 const char *actor, const char *objid, const xs_dict *msg); 266 xs_dict *notify_get(snac *snac, const char *id); 267 int notify_new_num(snac *snac); 268 xs_list *notify_list(snac *snac, int skip, int show); 269 void notify_clear(snac *snac); 270 271 xs_dict *markers_get(snac *snac, const xs_list *markers); 272 xs_dict *markers_set(snac *snac, const char *home_marker, const char *notify_marker); 273 274 void inbox_add(const char *inbox); 275 void inbox_add_by_actor(const xs_dict *actor); 276 xs_list *inbox_list(void); 277 278 int is_instance_blocked(const char *instance); 279 int instance_block(const char *instance); 280 int instance_unblock(const char *instance); 281 282 int content_match(const char *file, const xs_dict *msg); 283 xs_list *content_search(snac *user, const char *regex, 284 int priv, int skip, int show, int max_secs, int *timeout); 285 286 void enqueue_input(snac *snac, const xs_dict *msg, const xs_dict *req, int retries); 287 void enqueue_shared_input(const xs_dict *msg, const xs_dict *req, int retries); 288 void enqueue_output_raw(const char *keyid, const char *seckey, 289 const xs_dict *msg, const xs_str *inbox, 290 int retries, int p_status); 291 void enqueue_output(snac *snac, const xs_dict *msg, 292 const xs_str *inbox, int retries, int p_status); 293 void enqueue_output_by_actor(snac *snac, const xs_dict *msg, 294 const xs_str *actor, int retries); 295 void enqueue_email(const xs_str *msg, int retries); 296 void enqueue_telegram(const xs_str *msg, const char *bot, const char *chat_id); 297 void enqueue_ntfy(const xs_str *msg, const char *ntfy_server, const char *ntfy_token); 298 void enqueue_message(snac *snac, const xs_dict *msg); 299 void enqueue_close_question(snac *user, const char *id, int end_secs); 300 void enqueue_object_request(snac *user, const char *id, int forward_secs); 301 void enqueue_verify_links(snac *user); 302 void enqueue_actor_refresh(snac *user, const char *actor, int forward_secs); 303 void enqueue_webmention(const xs_dict *msg); 304 void enqueue_notify_webhook(snac *user, const xs_dict *noti, int retries); 305 306 int was_question_voted(snac *user, const char *id); 307 308 xs_list *user_queue(snac *snac); 309 xs_list *queue(void); 310 xs_dict *queue_get(const char *fn); 311 xs_dict *dequeue(const char *fn); 312 313 void purge(snac *snac); 314 void purge_all(void); 315 316 xs_dict *http_signed_request_raw(const char *keyid, const char *seckey, 317 const char *method, const char *url, 318 const xs_dict *headers, 319 const char *body, int b_size, 320 int *status, xs_str **payload, int *p_size, 321 int timeout); 322 xs_dict *http_signed_request(snac *snac, const char *method, const char *url, 323 const xs_dict *headers, 324 const char *body, int b_size, 325 int *status, xs_str **payload, int *p_size, 326 int timeout); 327 int check_signature(const xs_dict *req, xs_str **err); 328 int parse_range(const xs_dict *req, int *start, int *end); 329 330 srv_state *srv_state_op(xs_str **fname, int op); 331 void httpd(void); 332 333 int webfinger_request_signed(snac *snac, const char *qs, xs_str **actor, xs_str **user); 334 int webfinger_request(const char *qs, xs_str **actor, xs_str **user); 335 int webfinger_request_fake(const char *qs, xs_str **actor, xs_str **user); 336 int webfinger_get_handler(xs_dict *req, const char *q_path, 337 xs_val **body, int *b_size, char **ctype); 338 339 const char *default_avatar_base64(void); 340 341 xs_str *process_tags(snac *snac, const char *content, xs_list **tag); 342 343 const char *get_atto(const xs_dict *msg); 344 const char *get_in_reply_to(const xs_dict *msg); 345 xs_list *get_attachments(const xs_dict *msg); 346 347 xs_dict *msg_admiration(snac *snac, const char *object, const char *type); 348 xs_dict *msg_repulsion(snac *user, const char *id, const char *type); 349 xs_dict *msg_create(snac *snac, const xs_dict *object); 350 xs_dict *msg_follow(snac *snac, const char *actor); 351 352 xs_dict *msg_note(snac *snac, const xs_str *content, const xs_val *rcpts, 353 const xs_str *in_reply_to, const xs_list *attach, 354 int scope, const char *lang_str, const char *msg_date); 355 356 xs_dict *msg_undo(snac *snac, const xs_val *object); 357 xs_dict *msg_delete(snac *snac, const char *id); 358 xs_dict *msg_actor(snac *snac); 359 xs_dict *msg_update(snac *snac, const xs_dict *object); 360 xs_dict *msg_ping(snac *user, const char *rcpt); 361 xs_dict *msg_pong(snac *user, const char *rcpt, const char *object); 362 xs_dict *msg_move(snac *user, const char *new_account); 363 xs_dict *msg_accept(snac *snac, const xs_val *object, const char *to); 364 xs_dict *msg_question(snac *user, const char *content, xs_list *attach, 365 const xs_list *opts, int multiple, int end_secs); 366 367 int activitypub_request(snac *snac, const char *url, xs_dict **data); 368 int actor_request(snac *user, const char *actor, xs_dict **data); 369 int send_to_inbox_raw(const char *keyid, const char *seckey, 370 const xs_str *inbox, const xs_dict *msg, 371 xs_val **payload, int *p_size, int timeout); 372 int send_to_inbox(snac *snac, const xs_str *inbox, const xs_dict *msg, 373 xs_val **payload, int *p_size, int timeout); 374 xs_str *get_actor_inbox(const char *actor, int shared); 375 int send_to_actor(snac *snac, const char *actor, const xs_dict *msg, 376 xs_val **payload, int *p_size, int timeout); 377 int is_msg_public(const xs_dict *msg); 378 int is_msg_from_private_user(const xs_dict *msg); 379 int is_msg_for_me(snac *snac, const xs_dict *msg); 380 381 int process_user_queue(snac *snac); 382 void process_queue_item(xs_dict *q_item); 383 int process_queue(void); 384 385 int activitypub_get_handler(const xs_dict *req, const char *q_path, 386 char **body, int *b_size, char **ctype); 387 int activitypub_post_handler(const xs_dict *req, const char *q_path, 388 char *payload, int p_size, 389 char **body, int *b_size, char **ctype); 390 391 xs_dict *emojis(void); 392 xs_str *format_text_with_emoji(snac *user, const char *text, int ems, const char *proxy); 393 xs_str *not_really_markdown(const char *content, xs_list **attach, xs_list **tag); 394 xs_str *sanitize(const char *content); 395 xs_str *encode_html(const char *str); 396 397 xs_str *html_timeline(snac *user, const xs_list *list, int read_only, 398 int skip, int show, int show_more, 399 const char *title, const char *page, int utl, const char *error); 400 401 int html_get_handler(const xs_dict *req, const char *q_path, 402 char **body, int *b_size, char **ctype, 403 xs_str **etag, xs_str **last_modified, 404 xs_dict **headers, 405 int *mmapped); 406 407 int html_post_handler(const xs_dict *req, const char *q_path, 408 char *payload, int p_size, 409 char **body, int *b_size, char **ctype); 410 411 int write_default_css(void); 412 int snac_init(const char *_basedir); 413 int adduser(const char *uid); 414 int resetpwd(snac *snac); 415 int deluser(snac *user); 416 417 extern const char *snac_blurb; 418 419 void job_post(const xs_val *job, int urgent); 420 void job_wait(xs_val **job); 421 422 int oauth_get_handler(const xs_dict *req, const char *q_path, 423 char **body, int *b_size, char **ctype); 424 int oauth_post_handler(const xs_dict *req, const char *q_path, 425 const char *payload, int p_size, 426 char **body, int *b_size, char **ctype); 427 int mastoapi_get_handler(const xs_dict *req, const char *q_path, 428 char **body, int *b_size, char **ctype, xs_str **link); 429 int mastoapi_post_handler(const xs_dict *req, const char *q_path, 430 const char *payload, int p_size, 431 char **body, int *b_size, char **ctype); 432 int mastoapi_delete_handler(const xs_dict *req, const char *q_path, 433 const char *payload, int p_size, 434 char **body, int *b_size, char **ctype); 435 int mastoapi_put_handler(const xs_dict *req, const char *q_path, 436 const char *payload, int p_size, 437 char **body, int *b_size, char **ctype); 438 void persist_image(const char *key, const xs_val *data, const char *payload, snac *snac); 439 int mastoapi_patch_handler(const xs_dict *req, const char *q_path, 440 const char *payload, int p_size, 441 char **body, int *b_size, char **ctype); 442 void mastoapi_purge(void); 443 444 void verify_links(snac *user); 445 446 void export_csv(snac *user); 447 int migrate_account(snac *user); 448 449 void import_blocked_accounts_csv(snac *user, const char *fn); 450 void import_following_accounts_csv(snac *user, const char *fn); 451 void import_list_csv(snac *user, const char *fn); 452 void import_csv(snac *user); 453 int parse_port(const char *url, const char **errstr); 454 455 typedef enum { 456 #define HTTP_STATUS(code, name, text) HTTP_STATUS_ ## name = code, 457 #include "http_codes.h" 458 #undef HTTP_STATUS 459 } http_status; 460 461 const char *http_status_text(int status); 462 463 typedef struct { 464 double timestamp; 465 char *text; 466 } t_announcement; 467 t_announcement *announcement(double after); 468 469 xs_str *make_url(const char *href, const char *proxy, int by_token); 470 471 int badlogin_check(const char *user, const char *addr); 472 void badlogin_inc(const char *user, const char *addr); 473 474 const char *lang_str(const char *str, const snac *user); 475 476 xs_str *rss_from_timeline(snac *user, const xs_list *timeline, 477 const char *title, const char *link, const char *desc); 478 void rss_to_timeline(snac *user, const char *url); 479 void rss_poll_hashtags(void);