From b6107c8777a6f98dd89218ede1020a27ee83be70 Mon Sep 17 00:00:00 2001
From: Giacomo Tesio
Date: Wed, 20 Nov 2024 21:51:43 +0100
Subject: Makefile: enable static compilation with musl
Assuming a Debian GNU/Linux system with wget, tar, git, make
and musl-gcc
```
mkdir build
cd build
export BUILD_TARGET=$PWD
export CC="musl-gcc"
echo download and build zlib
wget http://zlib.net/current/zlib.tar.gz
tar xvf zlib.tar.gz
cd zlib-1.3.1/
./configure --prefix=$BUILD_TARGET --static
make
make install
cd ..
echo download and build openssl
wget https://github.com/openssl/openssl/releases/download/openssl-3.4.0/openssl-3.4.0.tar.gz
tar xvf openssl-3.4.0.tar.gz
cd openssl-3.4.0
CC="musl-gcc -fPIE -pie -static -idirafter /usr/include/ -idirafter /usr/include/x86_64-linux-gnu/" ./Configure no-shared no-async --prefix=$BUILD_TARGET --openssldir=$BUILD_TARGET/ssl linux-x86_64
make depend
make
make install
cd ..
echo download and build curl
wget https://curl.se/download/curl-7.88.1.tar.gz
tar xvf curl-7.88.1.tar.gz
cd curl-7.88.1
./configure --disable-shared --enable-static --disable-silent-rules --disable-debug --disable-warnings --disable-werror --disable-curldebug --disable-symbol-hiding --disable-ares --disable-rt --disable-ech --disable-dependency-tracking --disable-libtool-lock --enable-http --disable-ftp --disable-file --disable-ldap --disable-ldaps --disable-rtsp --disable-proxy --disable-dict --disable-telnet --disable-tftp --disable-pop3 --disable-imap --disable-smb --disable-smtp --disable-gopher --disable-mqtt --disable-manual --disable-libcurl-option --disable-ipv6 --disable-openssl-auto-load-config --disable-versioned-symbols --disable-verbose --disable-sspi --disable-crypto-auth --disable-ntlm --disable-ntlm-wb --disable-tls-srp --enable-unix-sockets --disable-cookies --disable-socketpair --disable-http-auth --disable-doh --disable-mime --disable-dateparse --disable-netrc --disable-progress-meter --disable-dnsshuffle --disable-get-easy-options --disable-alt-svc --disable-websockets --without-brotli --without-zstd --without-libpsl --without-libgsasl --without-librtmp --without-winidn --with-openssl=$BUILD_TARGET/ --disable-threaded-resolver --with-zlib=$BUILD_TARGET/ --prefix=$BUILD_TARGET/
make
make install
cd ..
echo download and build snac2
git clone https://codeberg.org/grunfink/snac2.git
cd snac2 # assuming this commit in master
make CFLAGS="-g -Wall -Wextra -pedantic -static -DWITHOUT_SHM" PREFIX=$BUILD_TARGET LDFLAGS="-L$BUILD_TARGET/lib64 -lcurl -lssl -lcrypto -lz"
make install PREFIX=$BUILD_TARGET
cd ..
echo a statically linked snac is ready at $BUILD_TARGET/bin
```
---
Makefile | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/Makefile b/Makefile
index 600419d..05e65f5 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-PREFIX=/usr/local
+PREFIX?=/usr/local
PREFIX_MAN=$(PREFIX)/man
CFLAGS?=-g -Wall -Wextra -pedantic
@@ -6,16 +6,16 @@ all: snac
snac: snac.o main.o data.o http.o httpd.o webfinger.o \
activitypub.o html.o utils.o format.o upgrade.o mastoapi.o
- $(CC) $(CFLAGS) -L/usr/local/lib *.o -lcurl -lcrypto $(LDFLAGS) -pthread -o $@
+ $(CC) $(CFLAGS) -L$(PREFIX)/lib *.o -lcurl -lcrypto $(LDFLAGS) -pthread -o $@
.c.o:
- $(CC) $(CFLAGS) $(CPPFLAGS) -I/usr/local/include -c $<
+ $(CC) $(CFLAGS) $(CPPFLAGS) -I$(PREFIX)/include -c $<
clean:
rm -rf *.o *.core snac makefile.depend
dep:
- $(CC) -I/usr/local/include -MM *.c > makefile.depend
+ $(CC) -I$(PREFIX)/include -MM *.c > makefile.depend
install:
mkdir -p -m 755 $(PREFIX)/bin
--
cgit v1.2.3
From 41081dd0d5918c6a82e1e6213de88c285f1b8158 Mon Sep 17 00:00:00 2001
From: Giacomo Tesio
Date: Thu, 12 Dec 2024 19:33:49 +0100
Subject: examples: add instructions to statically link snac with musl libc
---
examples/static-linking-with-musl.md | 77 ++++++++++++++++++++++++++++++++++++
1 file changed, 77 insertions(+)
create mode 100644 examples/static-linking-with-musl.md
diff --git a/examples/static-linking-with-musl.md b/examples/static-linking-with-musl.md
new file mode 100644
index 0000000..b14132c
--- /dev/null
+++ b/examples/static-linking-with-musl.md
@@ -0,0 +1,77 @@
+# How to build a statically linked Snac with musl
+
+Prepare the environment
+```
+mkdir build
+cd build
+export BUILD_TARGET=$PWD
+export CC="musl-gcc"
+```
+
+Download and build latest zlib
+```
+wget http://zlib.net/current/zlib.tar.gz
+tar xvf zlib.tar.gz
+cd zlib-1.3.1/
+./configure --prefix=$BUILD_TARGET --static
+make
+make install
+cd ..
+```
+
+Download and build latest openssl
+```
+wget https://github.com/openssl/openssl/releases/download/openssl-3.4.0/openssl-3.4.0.tar.gz
+tar xvf openssl-3.4.0.tar.gz
+cd openssl-3.4.0
+CC="musl-gcc -fPIE -pie -static -idirafter /usr/include/ -idirafter /usr/include/x86_64-linux-gnu/" \
+ ./Configure no-shared no-async --prefix=$BUILD_TARGET --openssldir=$BUILD_TARGET/ssl linux-x86_64
+make depend
+make
+make install
+cd ..
+```
+
+Download and build latest curl
+```
+wget https://curl.se/download/curl-7.88.1.tar.gz
+tar xvf curl-7.88.1.tar.gz
+cd curl-7.88.1
+./configure --disable-shared --enable-static --disable-silent-rules \
+ --disable-debug --disable-warnings --disable-werror \
+ --disable-curldebug --disable-symbol-hiding --disable-ares \
+ --disable-rt --disable-ech --disable-dependency-tracking \
+ --disable-libtool-lock --enable-http --disable-ftp \
+ --disable-file --disable-ldap --disable-ldaps \
+ --disable-rtsp --disable-proxy --disable-dict \
+ --disable-telnet --disable-tftp --disable-pop3 \
+ --disable-imap --disable-smb --disable-smtp --disable-gopher \
+ --disable-mqtt --disable-manual --disable-libcurl-option --disable-ipv6 \
+ --disable-openssl-auto-load-config --disable-versioned-symbols
+ --disable-verbose --disable-sspi --disable-crypto-auth \
+ --disable-ntlm --disable-ntlm-wb --disable-tls-srp \
+ --disable-unix-sockets --disable-cookies --disable-socketpair \
+ --disable-http-auth --disable-doh --disable-mime --disable-dateparse \
+ --disable-netrc --disable-progress-meter --disable-dnsshuffle \
+ --disable-get-easy-options --disable-alt-svc --disable-websockets \
+ --without-brotli --without-zstd --without-libpsl --without-libgsasl \
+ --without-librtmp --without-winidn --disable-threaded-resolver \
+ --with-openssl=$BUILD_TARGET/ --with-zlib=$BUILD_TARGET/ \
+ --prefix=$BUILD_TARGET/
+make
+make install
+cd ..
+```
+
+Download and build latest snac2
+```
+git clone https://codeberg.org/grunfink/snac2.git # or cd to your existing repo
+cd snac2
+make CFLAGS="-g -Wall -Wextra -pedantic -static -DWITHOUT_SHM" \
+ LDFLAGS="-L$BUILD_TARGET/lib64 -lcurl -lssl -lcrypto -lz" \
+ PREFIX=$BUILD_TARGET
+make install PREFIX=$BUILD_TARGET
+cd ..
+```
+
+Finally a statically linked snac is ready at $BUILD_TARGET/bin
--
cgit v1.2.3
From ee607734d8effdfb3a1a163e59153546a6ae9506 Mon Sep 17 00:00:00 2001
From: default
Date: Sun, 15 Dec 2024 15:17:38 +0100
Subject: mastoapi: fixed incorrect field 'bot' for newly created accounts.
---
mastoapi.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/mastoapi.c b/mastoapi.c
index 990898b..d844b42 100644
--- a/mastoapi.c
+++ b/mastoapi.c
@@ -1193,10 +1193,13 @@ int process_auth_token(snac *snac, const xs_dict *req)
return logged_in;
}
+
void credentials_get(char **body, char **ctype, int *status, snac snac)
{
xs *acct = xs_dict_new();
+ const xs_val *bot = xs_dict_get(snac.config, "bot");
+
acct = xs_dict_append(acct, "id", snac.md5);
acct = xs_dict_append(acct, "username", xs_dict_get(snac.config, "uid"));
acct = xs_dict_append(acct, "acct", xs_dict_get(snac.config, "uid"));
@@ -1206,7 +1209,7 @@ void credentials_get(char **body, char **ctype, int *status, snac snac)
acct = xs_dict_append(acct, "note", xs_dict_get(snac.config, "bio"));
acct = xs_dict_append(acct, "url", snac.actor);
acct = xs_dict_append(acct, "locked", xs_stock(XSTYPE_FALSE));
- acct = xs_dict_append(acct, "bot", xs_dict_get(snac.config, "bot"));
+ acct = xs_dict_append(acct, "bot", xs_stock(xs_is_true(bot) ? XSTYPE_TRUE : XSTYPE_FALSE));
acct = xs_dict_append(acct, "emojis", xs_stock(XSTYPE_LIST));
xs *src = xs_json_loads("{\"privacy\":\"public\", \"language\":\"en\","
@@ -1220,7 +1223,7 @@ void credentials_get(char **body, char **ctype, int *status, snac snac)
src = xs_dict_set(src, "sensitive",
strcmp(cw, "open") == 0 ? xs_stock(XSTYPE_TRUE) : xs_stock(XSTYPE_FALSE));
- src = xs_dict_set(src, "bot", xs_dict_get(snac.config, "bot"));
+ src = xs_dict_set(src, "bot", xs_stock(xs_is_true(bot) ? XSTYPE_TRUE : XSTYPE_FALSE));
xs *avatar = NULL;
const char *av = xs_dict_get(snac.config, "avatar");
--
cgit v1.2.3
From b2d301de2d5956b17ee0e26201bca952c4269e27 Mon Sep 17 00:00:00 2001
From: default
Date: Sun, 15 Dec 2024 15:23:28 +0100
Subject: mastoapi: deleted useless code.
---
mastoapi.c | 9 +--------
1 file changed, 1 insertion(+), 8 deletions(-)
diff --git a/mastoapi.c b/mastoapi.c
index d844b42..4d0c063 100644
--- a/mastoapi.c
+++ b/mastoapi.c
@@ -1322,7 +1322,7 @@ xs_list *mastoapi_timeline(snac *user, const xs_dict *args, const char *index_fn
const char *max_id = xs_dict_get(args, "max_id");
const char *since_id = xs_dict_get(args, "since_id");
- const char *min_id = xs_dict_get(args, "min_id");
+// const char *min_id = xs_dict_get(args, "min_id"); /* unsupported old-to-new navigation */
const char *limit_s = xs_dict_get(args, "limit");
int limit = 0;
int cnt = 0;
@@ -1351,13 +1351,6 @@ xs_list *mastoapi_timeline(snac *user, const xs_dict *args, const char *index_fn
break;
}
- /* only returns entries newer than min_id */
- /* what does really "Return results immediately newer than ID" mean? */
- if (min_id) {
- if (strcmp(md5, MID_TO_MD5(min_id)) == 0)
- break;
- }
-
/* get the entry */
if (user) {
if (!valid_status(timeline_get_by_md5(user, md5, &msg)))
--
cgit v1.2.3
From e8ae4920f6758c064bccba63f0a74d09ab57b751 Mon Sep 17 00:00:00 2001
From: default
Date: Sun, 15 Dec 2024 15:47:27 +0100
Subject: Fixed crash in mastoapi_status() Emoji list.
---
mastoapi.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/mastoapi.c b/mastoapi.c
index 4d0c063..be8be80 100644
--- a/mastoapi.c
+++ b/mastoapi.c
@@ -990,7 +990,7 @@ xs_dict *mastoapi_status(snac *snac, const xs_dict *msg)
const char *o_url = xs_dict_get(icon, "url");
if (!xs_is_null(o_url)) {
- xs *url = make_url(o_url, snac->actor, 1);
+ xs *url = make_url(o_url, snac ? snac->actor : NULL, 1);
xs *nm = xs_strip_chars_i(xs_dup(name), ":");
d1 = xs_dict_append(d1, "shortcode", nm);
@@ -1322,7 +1322,7 @@ xs_list *mastoapi_timeline(snac *user, const xs_dict *args, const char *index_fn
const char *max_id = xs_dict_get(args, "max_id");
const char *since_id = xs_dict_get(args, "since_id");
-// const char *min_id = xs_dict_get(args, "min_id"); /* unsupported old-to-new navigation */
+ const char *min_id = xs_dict_get(args, "min_id"); /* unsupported old-to-new navigation */
const char *limit_s = xs_dict_get(args, "limit");
int limit = 0;
int cnt = 0;
@@ -1333,7 +1333,7 @@ xs_list *mastoapi_timeline(snac *user, const xs_dict *args, const char *index_fn
if (limit == 0)
limit = 20;
- if (index_desc_first(f, md5, 0)) {
+ if (min_id == NULL && index_desc_first(f, md5, 0)) {
do {
xs *msg = NULL;
--
cgit v1.2.3
From c6562fa39bc3b609429fea9064a94cf080922da5 Mon Sep 17 00:00:00 2001
From: default
Date: Sun, 15 Dec 2024 22:52:41 +0100
Subject: New function timeline_link_header().
---
httpd.c | 5 ++++-
mastoapi.c | 31 ++++++++++++++++++++++++++++++-
snac.h | 2 +-
3 files changed, 35 insertions(+), 3 deletions(-)
diff --git a/httpd.c b/httpd.c
index 81d2f9e..0eff657 100644
--- a/httpd.c
+++ b/httpd.c
@@ -279,6 +279,7 @@ void httpd_connection(FILE *f)
xs *payload = NULL;
xs *etag = NULL;
xs *last_modified = NULL;
+ xs *link = NULL;
int p_size = 0;
const char *p;
int fcgi_id;
@@ -326,7 +327,7 @@ void httpd_connection(FILE *f)
status = oauth_get_handler(req, q_path, &body, &b_size, &ctype);
if (status == 0)
- status = mastoapi_get_handler(req, q_path, &body, &b_size, &ctype);
+ status = mastoapi_get_handler(req, q_path, &body, &b_size, &ctype, &link);
#endif /* NO_MASTODON_API */
if (status == 0)
@@ -426,6 +427,8 @@ void httpd_connection(FILE *f)
headers = xs_dict_append(headers, "etag", etag);
if (!xs_is_null(last_modified))
headers = xs_dict_append(headers, "last-modified", last_modified);
+ if (!xs_is_null(link))
+ headers = xs_dict_append(headers, "Link", link);
/* if there are any additional headers, add them */
const xs_dict *more_headers = xs_dict_get(srv_config, "http_headers");
diff --git a/mastoapi.c b/mastoapi.c
index be8be80..6b816f4 100644
--- a/mastoapi.c
+++ b/mastoapi.c
@@ -1434,8 +1434,35 @@ xs_list *mastoapi_timeline(snac *user, const xs_dict *args, const char *index_fn
}
+xs_str *timeline_link_header(const char *endpoint, xs_list *timeline)
+/* returns a Link header with paging information */
+{
+ xs_str *s = NULL;
+
+ if (xs_list_len(timeline) == 0)
+ return NULL;
+
+ const xs_dict *first_st = xs_list_get(timeline, 0);
+ const xs_dict *last_st = xs_list_get(timeline, -1);
+ const char *first_id = xs_dict_get(first_st, "id");
+ const char *last_id = xs_dict_get(last_st, "id");
+ const char *host = xs_dict_get(srv_config, "host");
+ const char *protocol = xs_dict_get_def(srv_config, "protocol", "https");
+
+ s = xs_fmt(
+ "<%s:/" "/%s%s?max_id=%s>; rel=\"next\", "
+ "<%s:/" "/%s%s?since_id=%s>; rel=\"prev\"",
+ protocol, host, endpoint, last_id,
+ protocol, host, endpoint, first_id);
+
+ srv_debug(1, xs_fmt("timeline_link_header %s", s));
+
+ return s;
+}
+
+
int mastoapi_get_handler(const xs_dict *req, const char *q_path,
- char **body, int *b_size, char **ctype)
+ char **body, int *b_size, char **ctype, xs_str **link)
{
(void)b_size;
@@ -1695,6 +1722,8 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path,
xs *ifn = user_index_fn(&snac1, "private");
xs *out = mastoapi_timeline(&snac1, args, ifn);
+ *link = timeline_link_header(cmd, out);
+
*body = xs_json_dumps(out, 4);
*ctype = "application/json";
status = HTTP_STATUS_OK;
diff --git a/snac.h b/snac.h
index acc175f..5b8b2f8 100644
--- a/snac.h
+++ b/snac.h
@@ -384,7 +384,7 @@ int oauth_post_handler(const xs_dict *req, const char *q_path,
const char *payload, int p_size,
char **body, int *b_size, char **ctype);
int mastoapi_get_handler(const xs_dict *req, const char *q_path,
- char **body, int *b_size, char **ctype);
+ char **body, int *b_size, char **ctype, xs_str **link);
int mastoapi_post_handler(const xs_dict *req, const char *q_path,
const char *payload, int p_size,
char **body, int *b_size, char **ctype);
--
cgit v1.2.3
From e79cd9f71fa4b453e07018497370c5bb072a3987 Mon Sep 17 00:00:00 2001
From: default
Date: Sun, 15 Dec 2024 23:08:17 +0100
Subject: Bumped version.
---
snac.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/snac.h b/snac.h
index 5b8b2f8..be271ae 100644
--- a/snac.h
+++ b/snac.h
@@ -1,7 +1,7 @@
/* snac - A simple, minimalistic ActivityPub instance */
/* copyright (c) 2022 - 2024 grunfink et al. / MIT license */
-#define VERSION "2.66"
+#define VERSION "2.67-dev"
#define USER_AGENT "snac/" VERSION
--
cgit v1.2.3
From b010be81807295e4336443a4f8b12d0513b436a5 Mon Sep 17 00:00:00 2001
From: default
Date: Sun, 15 Dec 2024 23:25:11 +0100
Subject: Fixed bad url in timeline link.
---
mastoapi.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mastoapi.c b/mastoapi.c
index 6b816f4..2c8c04d 100644
--- a/mastoapi.c
+++ b/mastoapi.c
@@ -1722,7 +1722,7 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path,
xs *ifn = user_index_fn(&snac1, "private");
xs *out = mastoapi_timeline(&snac1, args, ifn);
- *link = timeline_link_header(cmd, out);
+ *link = timeline_link_header("/api/v1/timelines/home", out);
*body = xs_json_dumps(out, 4);
*ctype = "application/json";
--
cgit v1.2.3
From 1aab3c5739a689f5288d576fa5148d001a9a56c6 Mon Sep 17 00:00:00 2001
From: default
Date: Sun, 15 Dec 2024 23:34:01 +0100
Subject: Updated RELEASE_NOTES.
---
RELEASE_NOTES.md | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 4630352..08fb219 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,5 +1,11 @@
# Release Notes
+## UNRELEASED
+
+Mastodon API: fixed a crash, fixed an incorrect value for the `bot` field, added a `Link` header to improve timeline pagination in some clients.
+
+Added documentation and some tweaks to enable static compilation with musl (contributed by Shamar).
+
## 2.66
As many users have asked for it, there is now an option to make the number of followed and following accounts public (still disabled by default). These are only the numbers; the lists themselves are never published.
--
cgit v1.2.3
From b9e0c6e74205ee43bea54fe91a9151053f107235 Mon Sep 17 00:00:00 2001
From: default
Date: Mon, 16 Dec 2024 19:47:27 +0100
Subject: Added pidfile locking.
---
httpd.c | 31 ++++++++++++++++++++-----------
1 file changed, 20 insertions(+), 11 deletions(-)
diff --git a/httpd.c b/httpd.c
index 0eff657..11e4d17 100644
--- a/httpd.c
+++ b/httpd.c
@@ -778,6 +778,26 @@ void httpd(void)
xs *shm_name = NULL;
sem_t anon_job_sem;
xs *pidfile = xs_fmt("%s/server.pid", srv_basedir);
+ int pidfd;
+
+ {
+ /* do some pidfile locking acrobatics */
+ if ((pidfd = open(pidfile, O_RDWR | O_CREAT, 0660)) == -1) {
+ srv_log(xs_fmt("Cannot create pidfile %s -- cannot continue", pidfile));
+ return;
+ }
+
+ if (lockf(pidfd, F_TLOCK, 1) == -1) {
+ srv_log(xs_fmt("Cannot lock pidfile %s -- server already running?", pidfile));
+ close(pidfd);
+ return;
+ }
+
+ ftruncate(pidfd, 0);
+
+ xs *s = xs_fmt("%d\n", (int)getpid());
+ write(pidfd, s, strlen(s));
+ }
address = xs_dict_get(srv_config, "address");
@@ -813,17 +833,6 @@ void httpd(void)
srv_log(xs_fmt("httpd%s start %s %s", p_state->use_fcgi ? " (FastCGI)" : "",
full_address, USER_AGENT));
- {
- FILE *f;
-
- if ((f = fopen(pidfile, "w")) != NULL) {
- fprintf(f, "%d\n", getpid());
- fclose(f);
- }
- else
- srv_log(xs_fmt("Cannot create %s: %s", pidfile, strerror(errno)));
- }
-
/* show the number of usable file descriptors */
struct rlimit r;
getrlimit(RLIMIT_NOFILE, &r);
--
cgit v1.2.3
From 7fe80a80cace768b981e42b945b2afeca7498152 Mon Sep 17 00:00:00 2001
From: default
Date: Tue, 17 Dec 2024 04:44:39 +0100
Subject: Updated RELEASE_NOTES.
---
RELEASE_NOTES.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 08fb219..e193d12 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -2,7 +2,7 @@
## UNRELEASED
-Mastodon API: fixed a crash, fixed an incorrect value for the `bot` field, added a `Link` header to improve timeline pagination in some clients.
+Mastodon API: Improved timeline pagination in some clients (details: a `Link` header has been added), fixed an incorrect value for the `bot` field in newly created accounts, fixed a crash.
Added documentation and some tweaks to enable static compilation with musl (contributed by Shamar).
--
cgit v1.2.3
From e9f3d5120c23406d0e395bea9daf23b2a1300c88 Mon Sep 17 00:00:00 2001
From: default
Date: Tue, 17 Dec 2024 04:45:35 +0100
Subject: Updated RELEASE_NOTES.
---
RELEASE_NOTES.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index e193d12..0031dce 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -4,6 +4,8 @@
Mastodon API: Improved timeline pagination in some clients (details: a `Link` header has been added), fixed an incorrect value for the `bot` field in newly created accounts, fixed a crash.
+When running in server mode, the pidfile is locked to avoid concurrent running of the same server instance.
+
Added documentation and some tweaks to enable static compilation with musl (contributed by Shamar).
## 2.66
--
cgit v1.2.3
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(+)
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 v1.2.3
From 7b8f766feb35629c7db6e9392dbe9de2dd6f7239 Mon Sep 17 00:00:00 2001
From: default
Date: Thu, 19 Dec 2024 05:00:23 +0100
Subject: Searching for URLs brings a post to the user timeline.
---
html.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/html.c b/html.c
index 2c353d2..f2b1252 100644
--- a/html.c
+++ b/html.c
@@ -2996,6 +2996,51 @@ int html_get_handler(const xs_dict *req, const char *q_path,
}
else {
const char *q = xs_dict_get(q_vars, "q");
+ xs *url_acct = NULL;
+
+ /* searching for an URL? */
+ if (q && xs_match(q, "https://*|http://*")) {
+ /* may by an actor; try a webfinger */
+ xs *actor_obj = NULL;
+
+ if (valid_status(webfinger_request(q, &actor_obj, &url_acct))) {
+ /* it's an actor; do the dirty trick of changing q to the account name */
+ q = url_acct;
+ }
+ else {
+ /* if it's not already here, try to bring it to the user's timeline */
+ xs *md5 = xs_md5_hex(q, strlen(q));
+
+ if (!timeline_here(&snac, md5)) {
+ xs *object = NULL;
+ int status;
+
+ status = activitypub_request(&snac, q, &object);
+ snac_debug(&snac, 1, xs_fmt("Request searched URL %s %d", q, status));
+
+ if (valid_status(status)) {
+ /* got it; also request the actor */
+ const char *attr_to = get_atto(object);
+
+ if (!xs_is_null(attr_to)) {
+ status = actor_request(&snac, attr_to, &actor_obj);
+
+ snac_debug(&snac, 1, xs_fmt("Request author %s of %s %d", attr_to, q, status));
+
+ if (valid_status(status)) {
+ /* add the actor */
+ actor_add(attr_to, actor_obj);
+
+ /* add the post to the timeline */
+ timeline_add(&snac, q, object);
+ }
+ }
+ }
+ }
+ }
+
+ /* fall through */
+ }
if (q && *q) {
if (xs_regex_match(q, "^@?[a-zA-Z0-9_]+@[a-zA-Z0-9-]+\\.")) {
--
cgit v1.2.3
From bcfefbe8b1c20f4a86a109b7f03ac750d40c3bbe Mon Sep 17 00:00:00 2001
From: default
Date: Thu, 19 Dec 2024 05:08:03 +0100
Subject: Updated RELEASE_NOTES.
---
RELEASE_NOTES.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 0031dce..0ccdd49 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -2,6 +2,8 @@
## UNRELEASED
+The search box also accepts post URLs; the post is requested and, if it's found, can be interacted with (liked, boosted, replied to, etc.).
+
Mastodon API: Improved timeline pagination in some clients (details: a `Link` header has been added), fixed an incorrect value for the `bot` field in newly created accounts, fixed a crash.
When running in server mode, the pidfile is locked to avoid concurrent running of the same server instance.
--
cgit v1.2.3
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(+)
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 v1.2.3
From bde5748a6e52e6f124e708a64e95827d87c8850c Mon Sep 17 00:00:00 2001
From: default
Date: Thu, 19 Dec 2024 05:37:27 +0100
Subject: Minor webfinger tweak.
---
webfinger.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/webfinger.c b/webfinger.c
index 893d777..85123bc 100644
--- a/webfinger.c
+++ b/webfinger.c
@@ -82,7 +82,11 @@ int webfinger_request_signed(snac *snac, const char *qs, xs_str **actor, xs_str
if (obj == NULL && valid_status(status) && payload) {
obj = xs_json_loads(payload);
- object_add(cached_qs, obj);
+
+ if (obj)
+ object_add(cached_qs, obj);
+ else
+ status = HTTP_STATUS_BAD_REQUEST;
}
if (obj) {
--
cgit v1.2.3
From 13d4fde316c8281e3100017b4b8eca4fc0dfc925 Mon Sep 17 00:00:00 2001
From: default
Date: Thu, 19 Dec 2024 10:05:11 +0100
Subject: Avoid adding repeated attachments.
---
activitypub.c | 29 ++++++++++++++++++++---------
format.c | 52 ++++++++++++++++++++++++++++++++++++++--------------
2 files changed, 58 insertions(+), 23 deletions(-)
diff --git a/activitypub.c b/activitypub.c
index 773df78..4d52efa 100644
--- a/activitypub.c
+++ b/activitypub.c
@@ -1476,20 +1476,31 @@ xs_dict *msg_note(snac *snac, const xs_str *content, const xs_val *rcpts,
/* create the attachment list, if there are any */
if (!xs_is_null(attach)) {
- int c = 0;
- while (xs_list_next(attach, &v, &c)) {
- xs *d = xs_dict_new();
+ xs_list_foreach(attach, v) {
const char *url = xs_list_get(v, 0);
const char *alt = xs_list_get(v, 1);
const char *mime = xs_mime_by_ext(url);
+ int add = 1;
+
+ /* check if it's already here */
+ const xs_dict *ad;
+ xs_list_foreach(atls, ad) {
+ if (strcmp(xs_dict_get_def(ad, "url", ""), url) == 0) {
+ add = 0;
+ break;
+ }
+ }
- d = xs_dict_append(d, "mediaType", mime);
- d = xs_dict_append(d, "url", url);
- d = xs_dict_append(d, "name", alt);
- d = xs_dict_append(d, "type",
- xs_startswith(mime, "image/") ? "Image" : "Document");
+ if (add) {
+ xs *d = xs_dict_new();
+ d = xs_dict_append(d, "mediaType", mime);
+ d = xs_dict_append(d, "url", url);
+ d = xs_dict_append(d, "name", alt);
+ d = xs_dict_append(d, "type",
+ xs_startswith(mime, "image/") ? "Image" : "Document");
- atls = xs_list_append(atls, d);
+ atls = xs_list_append(atls, d);
+ }
}
}
diff --git a/format.c b/format.c
index d0b535d..12783ae 100644
--- a/format.c
+++ b/format.c
@@ -163,14 +163,26 @@ static xs_str *format_line(const char *line, xs_list **attach)
const char *mime = xs_mime_by_ext(img_url);
if (attach != NULL && xs_startswith(mime, "image/")) {
- xs *d = xs_dict_new();
-
- d = xs_dict_append(d, "mediaType", mime);
- d = xs_dict_append(d, "url", img_url);
- d = xs_dict_append(d, "name", alt_text);
- d = xs_dict_append(d, "type", "Image");
-
- *attach = xs_list_append(*attach, d);
+ const xs_dict *ad;
+ int add = 1;
+
+ xs_list_foreach(*attach, ad) {
+ if (strcmp(xs_dict_get_def(ad, "url", ""), img_url) == 0) {
+ add = 0;
+ break;
+ }
+ }
+
+ if (add) {
+ xs *d = xs_dict_new();
+
+ d = xs_dict_append(d, "mediaType", mime);
+ d = xs_dict_append(d, "url", img_url);
+ d = xs_dict_append(d, "name", alt_text);
+ d = xs_dict_append(d, "type", "Image");
+
+ *attach = xs_list_append(*attach, d);
+ }
}
else {
xs *link = xs_fmt("%s", img_url, alt_text);
@@ -191,14 +203,26 @@ static xs_str *format_line(const char *line, xs_list **attach)
if (attach != NULL && xs_startswith(mime, "image/")) {
/* if it's a link to an image, insert it as an attachment */
- xs *d = xs_dict_new();
+ const xs_dict *ad;
+ int add = 1;
+
+ xs_list_foreach(*attach, ad) {
+ if (strcmp(xs_dict_get_def(ad, "url", ""), v2) == 0) {
+ add = 0;
+ break;
+ }
+ }
- d = xs_dict_append(d, "mediaType", mime);
- d = xs_dict_append(d, "url", v2);
- d = xs_dict_append(d, "name", "");
- d = xs_dict_append(d, "type", "Image");
+ if (add) {
+ xs *d = xs_dict_new();
+
+ d = xs_dict_append(d, "mediaType", mime);
+ d = xs_dict_append(d, "url", v2);
+ d = xs_dict_append(d, "name", "");
+ d = xs_dict_append(d, "type", "Image");
- *attach = xs_list_append(*attach, d);
+ *attach = xs_list_append(*attach, d);
+ }
}
else {
xs *s1 = xs_fmt("%s", v2, u);
--
cgit v1.2.3
From 39096852159775e43548fe3eaceb136f1c0260b5 Mon Sep 17 00:00:00 2001
From: default
Date: Thu, 19 Dec 2024 10:07:24 +0100
Subject: Updated RELEASE_NOTES.
---
RELEASE_NOTES.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 0ccdd49..a0ff2f8 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -4,6 +4,8 @@
The search box also accepts post URLs; the post is requested and, if it's found, can be interacted with (liked, boosted, replied to, etc.).
+Fixed a bug regarding repeated attachments when editing a post.
+
Mastodon API: Improved timeline pagination in some clients (details: a `Link` header has been added), fixed an incorrect value for the `bot` field in newly created accounts, fixed a crash.
When running in server mode, the pidfile is locked to avoid concurrent running of the same server instance.
--
cgit v1.2.3
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(-)
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 v1.2.3
From f82c7a5cdb2238e8c32649227daee05a0f885155 Mon Sep 17 00:00:00 2001
From: default
Date: Thu, 19 Dec 2024 16:14:13 +0100
Subject: Propagate FastCGI variable REMOTE_ADDR.
---
xs_fcgi.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/xs_fcgi.h b/xs_fcgi.h
index c79121f..c6ffe1f 100644
--- a/xs_fcgi.h
+++ b/xs_fcgi.h
@@ -190,7 +190,7 @@ xs_dict *xs_fcgi_request(FILE *f, xs_str **payload, int *p_size, int *fcgi_id)
q_vars = xs_url_vars(xs_list_get(pnv, 1));
}
else
- if (xs_match(k, "CONTENT_TYPE|CONTENT_LENGTH|HTTP_*")) {
+ if (xs_match(k, "CONTENT_TYPE|CONTENT_LENGTH|REMOTE_ADDR|HTTP_*")) {
if (xs_startswith(k, "HTTP_"))
k = xs_crop_i(k, 5, 0);
--
cgit v1.2.3
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(-)
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 v1.2.3
From d63106cd56db8cc1a8d1779a4fc8be2a69028ce4 Mon Sep 17 00:00:00 2001
From: default
Date: Thu, 19 Dec 2024 19:31:40 +0100
Subject: Updated RELEASE_NOTES.
---
RELEASE_NOTES.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index a0ff2f8..df11ac4 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -4,9 +4,11 @@
The search box also accepts post URLs; the post is requested and, if it's found, can be interacted with (liked, boosted, replied to, etc.).
+IP addresses for failed logins are tracked and throttled to mitigate brute force attacks (see `snac(8)` for more information).
+
Fixed a bug regarding repeated attachments when editing a post.
-Mastodon API: Improved timeline pagination in some clients (details: a `Link` header has been added), fixed an incorrect value for the `bot` field in newly created accounts, fixed a crash.
+Mastodon API: Improved timeline pagination in some clients (details: an HTTP `Link` header has been added), fixed an incorrect value for the `bot` field in newly created accounts, fixed a crash.
When running in server mode, the pidfile is locked to avoid concurrent running of the same server instance.
--
cgit v1.2.3
From 29ac9156e2301eccee492a3ec27ab8fb9168f192 Mon Sep 17 00:00:00 2001
From: default
Date: Thu, 19 Dec 2024 19:57:51 +0100
Subject: Updated documentation.
---
doc/snac.8 | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/doc/snac.8 b/doc/snac.8
index 54ae744..f5e4bd5 100644
--- a/doc/snac.8
+++ b/doc/snac.8
@@ -242,6 +242,12 @@ posts will not be direct ones, but proxied by
This way, remote media servers will not see the user's IP, but the server one,
improving privacy. Please take note that this will increase the server's incoming
and outgoing traffic.
+.It Ic badlogin_retries
+If incorrect logins from a given IP address reach this count, subsequent attempts
+from it are rejected until the lock expires (default: 5 retries).
+.It Ic badlogin_expire
+The number of seconds a blocked IP address is ignored in login attempts
+(default: 300 seconds).
.El
.Pp
You must restart the server to make effective these changes.
@@ -546,6 +552,22 @@ heavily on how all the servers involved behave. Just cross your fingers and hope
Full instances can be blocked. This operation must be done from
the command-line tool. See
.Xr snac 1 .
+.Pp
+.Ss Bad login throttling
+Since version 2.67, a simple logic to avoid brute force attacks against user passwords
+has been implemented: if, from a given IP address, the number of failed logins reaches
+a given threshold, further tries from that IP address are never successful until a timer
+expires. The maximum number of retries can be configured in the
+.Pa server.json
+file by setting the
+.Ic badlogin_retries
+variable, and the number of seconds the IP address unlock timer expires, in
+.Ic badlogin_expire .
+Please take note that, for this system to work, you must setup your web server proxy
+to pass the remote connection address in the
+.Ic X-Forwarded-For
+HTTP header (unless you use the FastCGI interface; if that's the case, you don't have
+to do anything).
.Sh ENVIRONMENT
.Bl -tag -width Ds
.It Ev DEBUG
@@ -603,35 +625,42 @@ example.com server section:
location /fedi {
proxy_pass http://localhost:8001;
proxy_set_header Host $http_host;
+ proxy_set_header X-Forwarded-For $remote_addr;
}
# webfinger
location /.well-known/webfinger {
proxy_pass http://localhost:8001;
proxy_set_header Host $http_host;
+ proxy_set_header X-Forwarded-For $remote_addr;
}
# Mastodon API (entry points)
location /api/v1/ {
proxy_pass http://localhost:8001;
proxy_set_header Host $http_host;
+ proxy_set_header X-Forwarded-For $remote_addr;
}
location /api/v2/ {
proxy_pass http://localhost:8001;
proxy_set_header Host $http_host;
+ proxy_set_header X-Forwarded-For $remote_addr;
}
# Mastodon API (OAuth support)
location /oauth {
proxy_pass http://localhost:8001;
proxy_set_header Host $http_host;
+ proxy_set_header X-Forwarded-For $remote_addr;
}
# optional
location /.well-known/nodeinfo {
proxy_pass http://localhost:8001;
proxy_set_header Host $http_host;
+ proxy_set_header X-Forwarded-For $remote_addr;
}
# optional (needed by some Mastodon API clients)
location /.well-known/host-meta {
proxy_pass http://localhost:8001;
proxy_set_header Host $http_host;
+ proxy_set_header X-Forwarded-For $remote_addr;
}
.Ed
.Pp
--
cgit v1.2.3
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(-)
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 v1.2.3
From 664f9cbeefa5af10d37b3f9f7a987e484d0ab885 Mon Sep 17 00:00:00 2001
From: default
Date: Fri, 20 Dec 2024 08:33:02 +0100
Subject: Mastoapi: added badlogin support.
---
mastoapi.c | 110 ++++++++++++++++++++++++++++++++++---------------------------
1 file changed, 62 insertions(+), 48 deletions(-)
diff --git a/mastoapi.c b/mastoapi.c
index 2c8c04d..ea550d6 100644
--- a/mastoapi.c
+++ b/mastoapi.c
@@ -293,47 +293,54 @@ int oauth_post_handler(const xs_dict *req, const char *q_path,
snac snac;
if (user_open(&snac, login)) {
- /* check the login + password */
- if (check_password(login, passwd, xs_dict_get(snac.config, "passwd"))) {
- /* success! redirect to the desired uri */
- xs *code = random_str();
+ const char *addr = xs_or(xs_dict_get(req, "remote-addr"),
+ xs_dict_get(req, "x-forwarded-for"));
- xs_free(*body);
+ if (badlogin_check(login, addr)) {
+ /* check the login + password */
+ if (check_password(login, passwd, xs_dict_get(snac.config, "passwd"))) {
+ /* success! redirect to the desired uri */
+ xs *code = random_str();
- if (strcmp(redir, "urn:ietf:wg:oauth:2.0:oob") == 0) {
- *body = xs_dup(code);
- }
- else {
- if (xs_str_in(redir, "?") != -1)
- *body = xs_fmt("%s&code=%s", redir, code);
- else
- *body = xs_fmt("%s?code=%s", redir, code);
+ xs_free(*body);
- status = HTTP_STATUS_SEE_OTHER;
- }
+ if (strcmp(redir, "urn:ietf:wg:oauth:2.0:oob") == 0) {
+ *body = xs_dup(code);
+ }
+ else {
+ if (xs_str_in(redir, "?") != -1)
+ *body = xs_fmt("%s&code=%s", redir, code);
+ else
+ *body = xs_fmt("%s?code=%s", redir, code);
- /* if there is a state, add it */
- if (!xs_is_null(state) && *state) {
- *body = xs_str_cat(*body, "&state=");
- *body = xs_str_cat(*body, state);
- }
+ status = HTTP_STATUS_SEE_OTHER;
+ }
- srv_log(xs_fmt("oauth x-snac-login: '%s' success, redirect to %s",
+ /* if there is a state, add it */
+ if (!xs_is_null(state) && *state) {
+ *body = xs_str_cat(*body, "&state=");
+ *body = xs_str_cat(*body, state);
+ }
+
+ srv_log(xs_fmt("oauth x-snac-login: '%s' success, redirect to %s",
login, *body));
- /* assign the login to the app */
- xs *app = app_get(cid);
+ /* assign the login to the app */
+ xs *app = app_get(cid);
- if (app != NULL) {
- app = xs_dict_set(app, "uid", login);
- app = xs_dict_set(app, "code", code);
- app_add(cid, app);
+ if (app != NULL) {
+ app = xs_dict_set(app, "uid", login);
+ app = xs_dict_set(app, "code", code);
+ app_add(cid, app);
+ }
+ else
+ srv_log(xs_fmt("oauth x-snac-login: error getting app %s", cid));
+ }
+ else {
+ srv_debug(1, xs_fmt("oauth x-snac-login: login '%s' incorrect", login));
+ badlogin_inc(login, addr);
}
- else
- srv_log(xs_fmt("oauth x-snac-login: error getting app %s", cid));
}
- else
- srv_debug(1, xs_fmt("oauth x-snac-login: login '%s' incorrect", login));
user_free(&snac);
}
@@ -474,29 +481,36 @@ int oauth_post_handler(const xs_dict *req, const char *q_path,
snac user;
if (user_open(&user, login)) {
- /* check the login + password */
- if (check_password(login, passwd, xs_dict_get(user.config, "passwd"))) {
- /* success! create a new token */
- xs *tokid = random_str();
+ const char *addr = xs_or(xs_dict_get(req, "remote-addr"),
+ xs_dict_get(req, "x-forwarded-for"));
+
+ if (badlogin_check(login, addr)) {
+ /* check the login + password */
+ if (check_password(login, passwd, xs_dict_get(user.config, "passwd"))) {
+ /* success! create a new token */
+ xs *tokid = random_str();
- srv_debug(1, xs_fmt("x-snac-new-token: "
+ srv_debug(1, xs_fmt("x-snac-new-token: "
"successful login for %s, new token %s", login, tokid));
- xs *token = xs_dict_new();
- token = xs_dict_append(token, "token", tokid);
- token = xs_dict_append(token, "client_id", "snac-client");
- token = xs_dict_append(token, "client_secret", "");
- token = xs_dict_append(token, "uid", login);
- token = xs_dict_append(token, "code", "");
+ xs *token = xs_dict_new();
+ token = xs_dict_append(token, "token", tokid);
+ token = xs_dict_append(token, "client_id", "snac-client");
+ token = xs_dict_append(token, "client_secret", "");
+ token = xs_dict_append(token, "uid", login);
+ token = xs_dict_append(token, "code", "");
- token_add(tokid, token);
+ token_add(tokid, token);
- *ctype = "text/plain";
- xs_free(*body);
- *body = xs_dup(tokid);
- }
+ *ctype = "text/plain";
+ xs_free(*body);
+ *body = xs_dup(tokid);
+ }
+ else
+ badlogin_inc(login, addr);
- user_free(&user);
+ user_free(&user);
+ }
}
}
}
--
cgit v1.2.3
From 55fb7dcbef819478c8d54a0161fb1330622a762e Mon Sep 17 00:00:00 2001
From: default
Date: Fri, 20 Dec 2024 08:36:42 +0100
Subject: Updated RELEASE_NOTES.
---
RELEASE_NOTES.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index df11ac4..fc7144b 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -8,7 +8,7 @@ IP addresses for failed logins are tracked and throttled to mitigate brute force
Fixed a bug regarding repeated attachments when editing a post.
-Mastodon API: Improved timeline pagination in some clients (details: an HTTP `Link` header has been added), fixed an incorrect value for the `bot` field in newly created accounts, fixed a crash.
+Mastodon API: Improved timeline pagination in some clients (details: an HTTP `Link` header has been added), fixed an incorrect value for the `bot` field in newly created accounts, fixed a crash, implemented markers (contributed by nowster).
When running in server mode, the pidfile is locked to avoid concurrent running of the same server instance.
--
cgit v1.2.3
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(-)
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 v1.2.3
From 1167b64f8ff4de9a782feba01c67fef9d75ea3a6 Mon Sep 17 00:00:00 2001
From: default
Date: Fri, 20 Dec 2024 09:45:11 +0100
Subject: mastoapi: minor tweak to notification list (Tusky was in a forever
request loop).
---
mastoapi.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/mastoapi.c b/mastoapi.c
index 59b0515..96aa3ac 100644
--- a/mastoapi.c
+++ b/mastoapi.c
@@ -1805,6 +1805,11 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path,
const char *min_id = xs_dict_get(args, "min_id");
const char *max_id = xs_dict_get(args, "max_id");
+ if (dbglevel) {
+ xs *js = xs_json_dumps(args, 0);
+ srv_debug(1, xs_fmt("mastoapi_notifications args %s", js));
+ }
+
xs_list_foreach(l, v) {
xs *noti = notify_get(&snac1, v);
@@ -1829,8 +1834,10 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path,
continue;
if (max_id) {
- if (strcmp(fid, max_id) > 0)
- continue;
+ if (strcmp(fid, max_id) == 0)
+ max_id = NULL;
+
+ continue;
}
if (min_id) {
@@ -1886,6 +1893,8 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path,
out = xs_list_append(out, mn);
}
+ srv_debug(1, xs_fmt("mastoapi_notifications count %d", xs_list_len(out)));
+
*body = xs_json_dumps(out, 4);
*ctype = "application/json";
status = HTTP_STATUS_OK;
@@ -3002,6 +3011,7 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path,
status = HTTP_STATUS_UNPROCESSABLE_CONTENT;
}
}
+ else
if (xs_startswith(cmd, "/v1/lists/")) { /** list maintenance **/
if (logged_in) {
xs *l = xs_split(cmd, "/");
--
cgit v1.2.3
From 00004500a9b56ca22cfe5e6949ea5072d0a63414 Mon Sep 17 00:00:00 2001
From: default
Date: Sat, 21 Dec 2024 16:49:45 +0100
Subject: mastoapi: fixed audio attachments.
---
mastoapi.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/mastoapi.c b/mastoapi.c
index 96aa3ac..3f8b59d 100644
--- a/mastoapi.c
+++ b/mastoapi.c
@@ -912,7 +912,7 @@ xs_dict *mastoapi_status(snac *snac, const xs_dict *msg)
const char *o_href = xs_dict_get(v, "href");
const char *name = xs_dict_get(v, "name");
- if (xs_match(type, "image/*|video/*|Image|Video")) { /* */
+ if (xs_match(type, "image/*|video/*|audio/*|Image|Video")) { /* */
xs *matteid = xs_fmt("%s_%d", id, xs_list_len(matt));
xs *href = make_url(o_href, proxy, 1);
@@ -924,7 +924,8 @@ xs_dict *mastoapi_status(snac *snac, const xs_dict *msg)
d = xs_dict_append(d, "remote_url", href);
d = xs_dict_append(d, "description", name);
- d = xs_dict_append(d, "type", (*type == 'v' || *type == 'V') ? "video" : "image");
+ d = xs_dict_append(d, "type", (*type == 'v' || *type == 'V') ? "video" :
+ (*type == 'a' || *type == 'A') ? "audio" : "image");
matt = xs_list_append(matt, d);
}
--
cgit v1.2.3
From 5ffd4435d8590d0c1f07c3d8761488eb81e88180 Mon Sep 17 00:00:00 2001
From: default
Date: Sat, 21 Dec 2024 16:50:28 +0100
Subject: Updated RELEASE_NOTES.
---
RELEASE_NOTES.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index fc7144b..9749197 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -8,7 +8,7 @@ IP addresses for failed logins are tracked and throttled to mitigate brute force
Fixed a bug regarding repeated attachments when editing a post.
-Mastodon API: Improved timeline pagination in some clients (details: an HTTP `Link` header has been added), fixed an incorrect value for the `bot` field in newly created accounts, fixed a crash, implemented markers (contributed by nowster).
+Mastodon API: Improved timeline pagination in some clients (details: an HTTP `Link` header has been added), fixed missing audio attachments, fixed an incorrect value for the `bot` field in newly created accounts, fixed a crash, implemented markers (contributed by nowster).
When running in server mode, the pidfile is locked to avoid concurrent running of the same server instance.
--
cgit v1.2.3
From 05d6e41710ed46526f42048dbf24cc3185ba3aa6 Mon Sep 17 00:00:00 2001
From: default
Date: Sat, 21 Dec 2024 17:06:01 +0100
Subject: If an attachment includes an icon, show it.
---
activitypub.c | 4 ++++
html.c | 17 +++++++++++++++++
2 files changed, 21 insertions(+)
diff --git a/activitypub.c b/activitypub.c
index 4d52efa..34cc32f 100644
--- a/activitypub.c
+++ b/activitypub.c
@@ -258,6 +258,10 @@ xs_list *get_attachments(const xs_dict *msg)
d = xs_dict_append(d, "href", href);
d = xs_dict_append(d, "name", name);
+ const xs_dict *icon = xs_dict_get(v, "icon");
+ if (xs_type(icon) == XSTYPE_DICT)
+ d = xs_dict_append(d, "icon", icon);
+
l = xs_list_append(l, d);
}
}
diff --git a/html.c b/html.c
index d85c673..4060262 100644
--- a/html.c
+++ b/html.c
@@ -2061,6 +2061,23 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only,
if (content && xs_str_in(content, o_href) != -1)
continue;
+ /* do this attachment include an icon? */
+ const xs_dict *icon = xs_dict_get(a, "icon");
+ if (xs_type(icon) == XSTYPE_DICT) {
+ const char *icon_mtype = xs_dict_get(icon, "mediaType");
+ const char *icon_url = xs_dict_get(icon, "url");
+
+ if (icon_mtype && icon_url && xs_startswith(icon_mtype, "image/")) {
+ xs_html_add(content_attachments,
+ xs_html_tag("a",
+ xs_html_attr("href", icon_url),
+ xs_html_attr("target", "_blank"),
+ xs_html_sctag("img",
+ xs_html_attr("loading", "lazy"),
+ xs_html_attr("src", icon_url))));
+ }
+ }
+
xs *href = make_url(o_href, proxy, 0);
if (xs_startswith(type, "image/") || strcmp(type, "Image") == 0) {
--
cgit v1.2.3
From 240f212252f9cc2a16d2accda7c619a90702da9c Mon Sep 17 00:00:00 2001
From: default
Date: Sat, 21 Dec 2024 18:40:09 +0100
Subject: Account names can also contain periods (in account search).
---
html.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/html.c b/html.c
index 4060262..2c0a823 100644
--- a/html.c
+++ b/html.c
@@ -3080,7 +3080,7 @@ int html_get_handler(const xs_dict *req, const char *q_path,
}
if (q && *q) {
- if (xs_regex_match(q, "^@?[a-zA-Z0-9_]+@[a-zA-Z0-9-]+\\.")) {
+ if (xs_regex_match(q, "^@?[a-zA-Z0-9._]+@[a-zA-Z0-9-]+\\.")) {
/** search account **/
xs *actor = NULL;
xs *acct = NULL;
--
cgit v1.2.3
From 0bbecf53a670202334128b1372cfc5d83273fbf1 Mon Sep 17 00:00:00 2001
From: default
Date: Sun, 22 Dec 2024 09:26:17 +0100
Subject: mastoapi: allow search for post URLs.
---
mastoapi.c | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/mastoapi.c b/mastoapi.c
index 3f8b59d..09e18a1 100644
--- a/mastoapi.c
+++ b/mastoapi.c
@@ -2377,6 +2377,37 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path,
if (xs_is_null(offset) || strcmp(offset, "0") == 0) {
/* reply something only for offset 0; otherwise,
apps like Tusky keep asking again and again */
+ if (xs_startswith(q, "https://")) {
+ xs *md5 = xs_md5_hex(q, strlen(q));
+
+ if (!timeline_here(&snac1, md5)) {
+ xs *object = NULL;
+ int status;
+
+ status = activitypub_request(&snac1, q, &object);
+ snac_debug(&snac1, 1, xs_fmt("Request searched URL %s %d", q, status));
+
+ if (valid_status(status)) {
+ /* got it; also request the actor */
+ const char *attr_to = get_atto(object);
+ xs *actor_obj = NULL;
+
+ if (!xs_is_null(attr_to)) {
+ status = actor_request(&snac1, attr_to, &actor_obj);
+
+ snac_debug(&snac1, 1, xs_fmt("Request author %s of %s %d", attr_to, q, status));
+
+ if (valid_status(status)) {
+ /* add the actor */
+ actor_add(attr_to, actor_obj);
+
+ /* add the post to the timeline */
+ timeline_add(&snac1, q, object);
+ }
+ }
+ }
+ }
+ }
if (!xs_is_null(q)) {
if (xs_is_null(type) || strcmp(type, "accounts") == 0) {
--
cgit v1.2.3
From bba997c11aae9d81a07ca4457499a387e8d7c3c1 Mon Sep 17 00:00:00 2001
From: default
Date: Sun, 22 Dec 2024 09:36:10 +0100
Subject: Updated RELEASE_NOTES.
---
RELEASE_NOTES.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 9749197..073985b 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,6 +1,6 @@
# Release Notes
-## UNRELEASED
+## 2.67
The search box also accepts post URLs; the post is requested and, if it's found, can be interacted with (liked, boosted, replied to, etc.).
--
cgit v1.2.3
From 89a8c2e0cc4fcd1f9450dfeb13bf5d83730c52ae Mon Sep 17 00:00:00 2001
From: default
Date: Sun, 22 Dec 2024 09:36:48 +0100
Subject: Version 2.67 RELEASED.
---
snac.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/snac.h b/snac.h
index 2b58669..af6e597 100644
--- a/snac.h
+++ b/snac.h
@@ -1,7 +1,7 @@
/* snac - A simple, minimalistic ActivityPub instance */
/* copyright (c) 2022 - 2024 grunfink et al. / MIT license */
-#define VERSION "2.67-dev"
+#define VERSION "2.67"
#define USER_AGENT "snac/" VERSION
--
cgit v1.2.3