/* snac - A simple, minimalistic ActivityPub instance */ /* copyright (c) 2022 - 2023 grunfink / MIT license */ #include "xs.h" #include "xs_io.h" #include "xs_json.h" #include "xs_regex.h" #include "xs_set.h" #include "xs_openssl.h" #include "xs_time.h" #include "xs_mime.h" #include "snac.h" int login(snac *snac, const xs_dict *headers) /* tries a login */ { int logged_in = 0; const char *auth = xs_dict_get(headers, "authorization"); if (auth && xs_startswith(auth, "Basic ")) { int sz; xs *s1 = xs_crop_i(xs_dup(auth), 6, 0); xs *s2 = xs_base64_dec(s1, &sz); xs *l1 = xs_split_n(s2, ":", 1); if (xs_list_len(l1) == 2) { logged_in = check_password( xs_list_get(l1, 0), xs_list_get(l1, 1), xs_dict_get(snac->config, "passwd")); } } if (logged_in) lastlog_write(snac, "web"); return logged_in; } xs_str *actor_name(xs_dict *actor) /* gets the actor name */ { xs_list *p; char *v; xs_str *name; if (xs_is_null((v = xs_dict_get(actor, "name"))) || *v == '\0') { if (xs_is_null(v = xs_dict_get(actor, "preferredUsername")) || *v == '\0') { v = "anonymous"; } } name = xs_dup(v); /* replace the :shortnames: */ if (!xs_is_null(p = xs_dict_get(actor, "tag"))) { /* iterate the tags */ while (xs_list_iter(&p, &v)) { char *t = xs_dict_get(v, "type"); if (t && strcmp(t, "Emoji") == 0) { char *n = xs_dict_get(v, "name"); char *i = xs_dict_get(v, "icon"); if (n && i) { char *u = xs_dict_get(i, "url"); xs *img = xs_fmt("", u); name = xs_replace_i(name, n, img); } } } } return name; } xs_str *html_actor_icon(xs_str *os, char *actor, const char *date, const char *udate, const char *url, int priv) { xs *s = xs_str_new("
\n", avatar);
s = xs_str_cat(s, s1);
}
{
xs *s1 = xs_fmt("%s",
xs_dict_get(actor, "id"), name);
s = xs_str_cat(s, s1);
}
if (!xs_is_null(url)) {
xs *s1 = xs_fmt(" »", url);
s = xs_str_cat(s, s1);
}
if (priv)
s = xs_str_cat(s, " 🔒");
if (strcmp(xs_dict_get(actor, "type"), "Service") == 0)
s = xs_str_cat(s, " 🤖");
if (xs_is_null(date)) {
s = xs_str_cat(s, "\n \n");
}
else {
xs *date_label = xs_crop_i(xs_dup(date), 0, 10);
xs *date_title = xs_dup(date);
if (!xs_is_null(udate)) {
xs *sd = xs_crop_i(xs_dup(udate), 0, 10);
date_label = xs_str_cat(date_label, " / ");
date_label = xs_str_cat(date_label, sd);
date_title = xs_str_cat(date_title, " / ");
date_title = xs_str_cat(date_title, udate);
}
xs *s1 = xs_fmt(
"\n\n",
date_title, date_label);
s = xs_str_cat(s, s1);
}
{
char *username, *id;
xs *s1;
if (xs_is_null(username = xs_dict_get(actor, "preferredUsername")) || *username == '\0') {
/* This should never be reached */
username = "anonymous";
}
if (xs_is_null(id = xs_dict_get(actor, "id")) || *id == '\0') {
/* This should never be reached */
id = "https://social.example.org/anonymous";
}
/* "LIKE AN ANIMAL" */
xs *domain = xs_split(id, "/");
xs *user = xs_fmt("@%s@%s", username, xs_list_get(domain, 2));
s1 = xs_fmt(
"
%s",
xs_dict_get(actor, "id"), user);
s = xs_str_cat(s, s1);
}
s = xs_str_cat(s, "
%s
\n" "@%s@%s
\n"; xs *s1 = xs_fmt(_tmpl, xs_dict_get(snac->config, "name"), xs_dict_get(snac->config, "uid"), xs_dict_get(srv_config, "host") ); s = xs_str_cat(s, s1); if (local) { xs *bio = not_really_markdown(xs_dict_get(snac->config, "bio"), NULL); xs *s1 = xs_fmt("\n" "
\n" "
\n"
"%s
\n"
"
%s
\n"
"
" "\n", L("Edit..."), md5, snac->actor, md5, prev_src, id, L("Sensitive content"), L("Only for mentioned people"), L("Attach..."), L("File"), L("File description"), md5, L("Post") ); s = xs_str_cat(s, s1); } { /* the post textarea */ xs *ct = build_mentions(snac, msg); xs *s1 = xs_fmt( "
%s
\n"
"
" "\n", L("Reply..."), md5, snac->actor, md5, ct, id, L("Sensitive content"), L("Only for mentioned people"), L("Attach..."), L("File"), L("File description"), md5, L("Post") ); s = xs_str_cat(s, s1); } s = xs_str_cat(s, "
%s
"); if (!xs_startswith(c, "
")) { xs *s1 = c; c = xs_fmt("
%s
", s1); } /* replace the :shortnames: */ if (!xs_is_null(p = xs_dict_get(msg, "tag"))) { /* iterate the tags */ while (xs_list_iter(&p, &v)) { char *t = xs_dict_get(v, "type"); if (t && strcmp(t, "Emoji") == 0) { char *n = xs_dict_get(v, "name"); char *i = xs_dict_get(v, "icon"); if (n && i) { char *u = xs_dict_get(i, "url"); xs *img = xs_fmt("", u, n); c = xs_replace_i(c, n, img); } } } } if (strcmp(type, "Question") == 0) { /** question content **/ xs_list *oo = xs_dict_get(msg, "oneOf"); xs_list *ao = xs_dict_get(msg, "anyOf"); xs_list *p; xs_dict *v; int closed = 0; if (xs_dict_get(msg, "closed")) closed = 2; else if (xs_startswith(id, snac->actor)) closed = 1; /* we questioned; closed for us */ else if (was_question_voted(snac, id)) closed = 1; /* we already voted; closed for us */ /* get the appropriate list of options */ p = oo != NULL ? oo : ao; if (closed) { /* closed poll */ c = xs_str_cat(c, "%s: | %d |
%s
\n", L("Closed")); c = xs_str_cat(c, s1); } else { /* show when the poll closes */ const char *end_time = xs_dict_get(msg, "endTime"); if (!xs_is_null(end_time)) { time_t t0 = time(NULL); time_t t1 = xs_parse_iso_date(end_time, 0); if (t1 > 0 && t1 > t0) { time_t diff_time = t1 - t0; xs *tf = xs_str_time_diff(diff_time); char *p = tf; /* skip leading zeros */ for (; *p == '0' || *p == ':'; p++); xs *s1 = xs_fmt("%s %s
", L("Closes in"), p); c = xs_str_cat(c, s1); } } } } s = xs_str_cat(s, c); } s = xs_str_cat(s, "\n"); /* add the attachments */ char *attach; if ((attach = xs_dict_get(msg, "attachment")) != NULL) { /** **/ char *v; /* make custom css for attachments easier */ s = xs_str_cat(s, " \n"); } if (sensitive) s = xs_str_cat(s, "\n"); s = xs_str_cat(s, "
\n"); if (level < 4) ss = xs_str_cat(ss, "
%s
" "%s" "
\n", snac->actor, local ? "" : "/admin", skip + show, show, L("Load more...")); s = xs_str_cat(s, s1); } s = html_user_footer(s); s = xs_str_cat(s, "\n\n"); return s; } d_char *html_people_list(snac *snac, d_char *os, d_char *list, const char *header, const char *t) { xs *s = xs_str_new(NULL); xs *h = xs_fmt("")) s = xs_str_cat(s, sc); else { xs *s1 = xs_fmt("
%s
", sc); s = xs_str_cat(s, s1); } s = xs_str_cat(s, "%s
\n"
"
\n", L("Direct Message..."), md5, t, snac->actor, md5, actor_id, L("Post") ); s = xs_str_cat(s, s2); s = xs_str_cat(s, "