snac2

Fork of https://codeberg.org/grunfink/snac2
git clone https://git.inz.fi/snac2
Log | Files | Refs | README | LICENSE

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);