From 844825f190f8651da36100d2a50cef54eaac14c1 Mon Sep 17 00:00:00 2001 From: default Date: Thu, 19 Dec 2024 04:24:25 +0100 Subject: content_search() also checks for the post id. --- data.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'data.c') diff --git a/data.c b/data.c index 4e5851a..038d7fd 100644 --- a/data.c +++ b/data.c @@ -2742,6 +2742,14 @@ xs_list *content_search(snac *user, const char *regex, if (id == NULL || is_hidden(user, id)) continue; + /* test for the post URL */ + if (strcmp(id, regex) == 0) { + if (xs_set_add(&seen, md5) == 1) + show--; + + continue; + } + xs *c = xs_str_new(NULL); const char *content = xs_dict_get(post, "content"); const char *name = xs_dict_get(post, "name"); -- cgit From 103dc7d4f2ba729737fd0ca768146247022a4b59 Mon Sep 17 00:00:00 2001 From: default Date: Thu, 19 Dec 2024 05:19:04 +0100 Subject: In content_search(), also test the 'url' post field (if it exists). --- data.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'data.c') diff --git a/data.c b/data.c index 038d7fd..f9dd76b 100644 --- a/data.c +++ b/data.c @@ -2750,6 +2750,15 @@ xs_list *content_search(snac *user, const char *regex, continue; } + /* test for the alternate post id */ + const char *url = xs_dict_get(post, "url"); + if (!xs_is_null(url) && strcmp(url, regex) == 0) { + if (xs_set_add(&seen, md5) == 1) + show--; + + continue; + } + xs *c = xs_str_new(NULL); const char *content = xs_dict_get(post, "content"); const char *name = xs_dict_get(post, "name"); -- cgit From 7e028f6b50bb0959f09185c1076285a2cf475c03 Mon Sep 17 00:00:00 2001 From: default Date: Thu, 19 Dec 2024 14:37:52 +0100 Subject: Minor search tweak. --- data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'data.c') diff --git a/data.c b/data.c index f9dd76b..74861b8 100644 --- a/data.c +++ b/data.c @@ -2752,7 +2752,7 @@ xs_list *content_search(snac *user, const char *regex, /* test for the alternate post id */ const char *url = xs_dict_get(post, "url"); - if (!xs_is_null(url) && strcmp(url, regex) == 0) { + if (xs_type(url) == XSTYPE_STRING && strcmp(url, regex) == 0) { if (xs_set_add(&seen, md5) == 1) show--; -- cgit From 57a8716f72dd5c75c98ead085fbd8d7f12660da6 Mon Sep 17 00:00:00 2001 From: default Date: Thu, 19 Dec 2024 18:54:15 +0100 Subject: Added bad login throttling. --- data.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ html.c | 15 ++++++++-- snac.h | 3 ++ 3 files changed, 120 insertions(+), 3 deletions(-) (limited to 'data.c') diff --git a/data.c b/data.c index 74861b8..6394d1c 100644 --- a/data.c +++ b/data.c @@ -3821,3 +3821,108 @@ xs_str *make_url(const char *href, const char *proxy, int by_token) return url; } + + +/** bad login throttle **/ + +xs_str *_badlogin_fn(const char *addr) +{ + xs *md5 = xs_md5_hex(addr, strlen(addr)); + xs *dir = xs_fmt("%s/badlogin", srv_basedir); + + mkdirx(dir); + + return xs_fmt("%s/%s", dir, md5); +} + + +int _badlogin_read(const char *fn, int *failures) +/* reads a badlogin file */ +{ + int ok = 0; + FILE *f; + + pthread_mutex_lock(&data_mutex); + + if ((f = fopen(fn, "r")) != NULL) { + xs *l = xs_readline(f); + fclose(f); + + if (sscanf(l, "%d", failures) == 1) + ok = 1; + } + + pthread_mutex_unlock(&data_mutex); + + return ok; +} + + +int badlogin_check(const char *user, const char *addr) +/* checks if this address is authorized to try a login */ +{ + int valid = 1; + + if (xs_type(addr) == XSTYPE_STRING) { + xs *fn = _badlogin_fn(addr); + double mt = mtime(fn); + + if (mt > 0) { + int badlogin_expire = xs_number_get(xs_dict_get_def(srv_config, + "badlogin_expire", "300")); + + mt += badlogin_expire; + + /* if file is expired, delete and give pass */ + if (mt < time(NULL)) { + srv_debug(1, xs_fmt("Login from %s for %s allowed again", addr, user)); + unlink(fn); + } + else { + int failures; + + if (_badlogin_read(fn, &failures)) { + int badlogin_max = xs_number_get(xs_dict_get_def(srv_config, + "badlogin_retries", "5")); + + if (failures >= badlogin_max) { + valid = 0; + + xs *d = xs_str_iso_date((time_t) mt); + + srv_debug(1, + xs_fmt("Login from %s for %s forbidden until %s", addr, user, d)); + } + } + } + } + } + + return valid; +} + + +void badlogin_inc(const char *user, const char *addr) +/* increments a bad login from this address */ +{ + if (xs_type(addr) == XSTYPE_STRING) { + int failures = 0; + xs *fn = _badlogin_fn(addr); + FILE *f; + + _badlogin_read(fn, &failures); + + pthread_mutex_lock(&data_mutex); + + if ((f = fopen(fn, "w")) != NULL) { + failures++; + + fprintf(f, "%d %s %s\n", failures, addr, user); + fclose(f); + + srv_log(xs_fmt("Registered %d login failure(s) from %s for %s", failures, addr, user)); + } + + pthread_mutex_unlock(&data_mutex); + } +} diff --git a/html.c b/html.c index f2b1252..8c00961 100644 --- a/html.c +++ b/html.c @@ -29,9 +29,18 @@ int login(snac *snac, const xs_dict *headers) 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")); + const char *user = xs_list_get(l1, 0); + const char *pwd = xs_list_get(l1, 1); + const char *addr = xs_or(xs_dict_get(headers, "remote-addr"), + xs_dict_get(headers, "x-forwarded-for")); + + if (badlogin_check(user, addr)) { + logged_in = check_password(user, pwd, + xs_dict_get(snac->config, "passwd")); + + if (!logged_in) + badlogin_inc(user, addr); + } } } diff --git a/snac.h b/snac.h index be271ae..dc3fa0a 100644 --- a/snac.h +++ b/snac.h @@ -425,3 +425,6 @@ typedef struct { t_announcement *announcement(double after); xs_str *make_url(const char *href, const char *proxy, int by_token); + +int badlogin_check(const char *user, const char *addr); +void badlogin_inc(const char *user, const char *addr); -- cgit From fa253f008a0f4d028dbb9ef14c83d6699a133614 Mon Sep 17 00:00:00 2001 From: Paul Martin Date: Thu, 19 Dec 2024 19:55:56 +0000 Subject: Implement mastoapi markers for notifications and home. --- data.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ mastoapi.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++------- snac.h | 3 +++ 3 files changed, 120 insertions(+), 7 deletions(-) (limited to 'data.c') diff --git a/data.c b/data.c index 6394d1c..823975e 100644 --- a/data.c +++ b/data.c @@ -2840,6 +2840,72 @@ xs_str *notify_check_time(snac *snac, int reset) return t; } +xs_dict *markers_get(snac *snac, const xs_list *markers) +{ + xs_dict *data = NULL; + xs_dict *returns = xs_dict_new(); + xs *fn = xs_fmt("%s/markers.json", snac->basedir); + const xs_str *v = NULL; + FILE *f; + + if ((f = fopen(fn, "r")) != NULL) { + data = xs_json_load(f); + fclose(f); + } + + if (xs_is_null(data)) + data = xs_dict_new(); + + xs_list_foreach(markers, v) { + const xs_dict *mark = xs_dict_get(data, v); + if (!xs_is_null(mark)) { + returns = xs_dict_append(returns, v, mark); + } + } + return returns; +} + +xs_dict *markers_set(snac *snac, const char *home_marker, const char *notify_marker) +/* gets or sets notification marker */ +{ + xs_dict *data = NULL; + xs_dict *written = xs_dict_new(); + xs *fn = xs_fmt("%s/markers.json", snac->basedir); + FILE *f; + + if ((f = fopen(fn, "r")) != NULL) { + data = xs_json_load(f); + fclose(f); + } + + if (xs_is_null(data)) + data = xs_dict_new(); + + if (!xs_is_null(home_marker)) { + xs_dict *home = xs_dict_new(); + home = xs_dict_append(home, "last_read_id", home_marker); + home = xs_dict_append(home, "version", xs_stock(0)); + home = xs_dict_append(home, "updated_at", tid(0)); + data = xs_dict_set(data, "home", home); + written = xs_dict_append(written, "home", home); + } + + if (!xs_is_null(notify_marker)) { + xs_dict *notify = xs_dict_new(); + notify = xs_dict_append(notify, "last_read_id", notify_marker); + notify = xs_dict_append(notify, "version", xs_stock(0)); + notify = xs_dict_append(notify, "updated_at", tid(0)); + data = xs_dict_set(data, "notifications", notify); + written = xs_dict_append(written, "notifications", notify); + } + + if ((f = fopen(fn, "w")) != NULL) { + xs_json_dump(data, 4, f); + fclose(f); + } + + return written; +} void notify_add(snac *snac, const char *type, const char *utype, const char *actor, const char *objid, const xs_dict *msg) diff --git a/mastoapi.c b/mastoapi.c index 2c8c04d..c78c380 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -1788,6 +1788,7 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, xs *out = xs_list_new(); const xs_dict *v; const xs_list *excl = xs_dict_get(args, "exclude_types[]"); + const char *min_id = xs_dict_get(args, "min_id"); const char *max_id = xs_dict_get(args, "max_id"); xs_list_foreach(l, v) { @@ -1814,10 +1815,14 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, continue; if (max_id) { - if (strcmp(fid, max_id) == 0) - max_id = NULL; + if (strcmp(fid, max_id) > 0) + continue; + } - continue; + if (min_id) { + if (strcmp(fid, min_id) <= 0) { + continue; + } } /* convert the type */ @@ -2298,9 +2303,22 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, } else if (strcmp(cmd, "/v1/markers") == 0) { /** **/ - *body = xs_dup("{}"); - *ctype = "application/json"; - status = HTTP_STATUS_OK; + if (logged_in) { + const xs_list *timeline = xs_dict_get(args, "timeline[]"); + xs_str *json = NULL; + if (!xs_is_null(timeline)) + json = xs_json_dumps(markers_get(&snac1, timeline), 4); + + if (!xs_is_null(json)) + *body = json; + else + *body = xs_dup("{}"); + + *ctype = "application/json"; + status = HTTP_STATUS_OK; + } + else + status = HTTP_STATUS_UNAUTHORIZED; } else if (strcmp(cmd, "/v1/followed_tags") == 0) { /** **/ @@ -2997,9 +3015,35 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path, } } } + } + else if (strcmp(cmd, "/v1/markers") == 0) { /** **/ + xs_str *json = NULL; + if (logged_in) { + const xs_str *home_marker = xs_dict_get(args, "home[last_read_id]"); + if (xs_is_null(home_marker)) { + const xs_dict *home = xs_dict_get(args, "home"); + if (!xs_is_null(home)) + home_marker = xs_dict_get(home, "last_read_id"); + } + + const xs_str *notify_marker = xs_dict_get(args, "notifications[last_read_id]"); + if (xs_is_null(notify_marker)) { + const xs_dict *notify = xs_dict_get(args, "notifications"); + if (!xs_is_null(notify)) + notify_marker = xs_dict_get(notify, "last_read_id"); + } + json = xs_json_dumps(markers_set(&snac, home_marker, notify_marker), 4); + } + if (!xs_is_null(json)) + *body = json; else - status = HTTP_STATUS_UNPROCESSABLE_CONTENT; + *body = xs_dup("{}"); + + *ctype = "application/json"; + status = HTTP_STATUS_OK; } + else + status = HTTP_STATUS_UNPROCESSABLE_CONTENT; /* user cleanup */ if (logged_in) diff --git a/snac.h b/snac.h index dc3fa0a..2b58669 100644 --- a/snac.h +++ b/snac.h @@ -236,6 +236,9 @@ int notify_new_num(snac *snac); xs_list *notify_list(snac *snac, int skip, int show); void notify_clear(snac *snac); +xs_dict *markers_get(snac *snac, const xs_list *markers); +xs_dict *markers_set(snac *snac, const char *home_marker, const char *notify_marker); + void inbox_add(const char *inbox); void inbox_add_by_actor(const xs_dict *actor); xs_list *inbox_list(void); -- cgit From 156d5280196c948369b186999a74c7062272b5b2 Mon Sep 17 00:00:00 2001 From: default Date: Fri, 20 Dec 2024 09:04:17 +0100 Subject: Add contact metrics to og:description. --- data.c | 14 ++++++++------ html.c | 11 +++++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) (limited to 'data.c') diff --git a/data.c b/data.c index 823975e..36c41f3 100644 --- a/data.c +++ b/data.c @@ -2842,7 +2842,7 @@ xs_str *notify_check_time(snac *snac, int reset) xs_dict *markers_get(snac *snac, const xs_list *markers) { - xs_dict *data = NULL; + xs *data = NULL; xs_dict *returns = xs_dict_new(); xs *fn = xs_fmt("%s/markers.json", snac->basedir); const xs_str *v = NULL; @@ -2868,7 +2868,7 @@ xs_dict *markers_get(snac *snac, const xs_list *markers) xs_dict *markers_set(snac *snac, const char *home_marker, const char *notify_marker) /* gets or sets notification marker */ { - xs_dict *data = NULL; + xs *data = NULL; xs_dict *written = xs_dict_new(); xs *fn = xs_fmt("%s/markers.json", snac->basedir); FILE *f; @@ -2882,19 +2882,21 @@ xs_dict *markers_set(snac *snac, const char *home_marker, const char *notify_mar data = xs_dict_new(); if (!xs_is_null(home_marker)) { - xs_dict *home = xs_dict_new(); + xs *home = xs_dict_new(); + xs *s_tid = tid(0); home = xs_dict_append(home, "last_read_id", home_marker); home = xs_dict_append(home, "version", xs_stock(0)); - home = xs_dict_append(home, "updated_at", tid(0)); + home = xs_dict_append(home, "updated_at", s_tid); data = xs_dict_set(data, "home", home); written = xs_dict_append(written, "home", home); } if (!xs_is_null(notify_marker)) { - xs_dict *notify = xs_dict_new(); + xs *notify = xs_dict_new(); + xs *s_tid = tid(0); notify = xs_dict_append(notify, "last_read_id", notify_marker); notify = xs_dict_append(notify, "version", xs_stock(0)); - notify = xs_dict_append(notify, "updated_at", tid(0)); + notify = xs_dict_append(notify, "updated_at", s_tid); data = xs_dict_set(data, "notifications", notify); written = xs_dict_append(written, "notifications", notify); } diff --git a/html.c b/html.c index 8c00961..d85c673 100644 --- a/html.c +++ b/html.c @@ -642,6 +642,17 @@ xs_html *html_user_head(snac *user, const char *desc, const char *url) else s_desc = xs_dup(desc); + /* show metrics in og:description? */ + if (xs_is_true(xs_dict_get(user->config, "show_contact_metrics"))) { + xs *fwers = follower_list(user); + xs *fwing = following_list(user); + + xs *s1 = xs_fmt(L("%d following, %d followers ยท "), + xs_list_len(fwing), xs_list_len(fwers)); + + s_desc = xs_str_prepend_i(s_desc, s1); + } + /* shorten desc to a reasonable size */ for (n = 0; s_desc[n]; n++) { if (n > 512 && (s_desc[n] == ' ' || s_desc[n] == '\n')) -- cgit