diff --git a/Makefile b/Makefile index 8fc8eb1..eec1008 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ CFLAGS=-g -Wall all: snac -snac: snac.o main.o data.o http.o httpd.o +snac: snac.o main.o data.o http.o httpd.o webfinger.o $(CC) -L/usr/local/lib *.o -lcurl -lcrypto -o $@ .c.o: @@ -21,3 +21,4 @@ httpd.o: httpd.c xs.h xs_io.h xs_encdec.h xs_json.h xs_socket.h \ main.o: main.c xs.h xs_encdec.h xs_json.h snac.h snac.o: snac.c xs.h xs_io.h xs_encdec.h xs_json.h xs_curl.h \ xs_openssl.h xs_socket.h xs_httpd.h snac.h +webfinger.o: webfinger.c xs.h xs_encdec.h xs_json.h snac.h diff --git a/httpd.c b/httpd.c index 7cd73cc..8e798a4 100644 --- a/httpd.c +++ b/httpd.c @@ -109,6 +109,9 @@ void httpd_connection(int rs) /* cascade through */ if (status == 0) server_get_handler(req, q_path, &status, &body, &b_size, &ctype); + + if (status == 0) + webfinger_get_handler(req, q_path, &status, &body, &b_size, &ctype); } else if (strcmp(method, "POST") == 0) { diff --git a/snac.h b/snac.h index 0aaeeed..238fcac 100644 --- a/snac.h +++ b/snac.h @@ -69,3 +69,6 @@ d_char *http_signed_request(snac *snac, char *method, char *url, int *status, d_char **payload, int *p_size); void httpd(void); + +void webfinger_get_handler(d_char *req, char *q_path, int *status, + char **body, int *b_size, char **ctype); diff --git a/webfinger.c b/webfinger.c new file mode 100644 index 0000000..be89ea9 --- /dev/null +++ b/webfinger.c @@ -0,0 +1,94 @@ +/* snac - A simple, minimalistic ActivityPub instance */ +/* copyright (c) 2022 grunfink - MIT license */ + +#include "xs.h" +#include "xs_encdec.h" +#include "xs_json.h" + +#include "snac.h" + +void webfinger_get_handler(d_char *req, char *q_path, int *status, + char **body, int *b_size, char **ctype) +/* serves webfinger queries */ +{ + if (strcmp(q_path, "/.well-known/webfinger") != 0) + return; + + char *q_vars = xs_dict_get(req, "q_vars"); + char *resource = xs_dict_get(q_vars, "resource"); + + if (resource == NULL) { + *status = 400; + return; + } + + snac snac; + int found = 0; + + if (xs_startswith(resource, "https:/" "/")) { + /* actor search: find a user with this actor */ + xs *list = user_list(); + char *p, *uid; + + p = list; + while (xs_list_iter(&p, &uid)) { + if (user_open(&snac, uid)) { + if (strcmp(snac.actor, resource) == 0) { + found = 1; + break; + } + + user_free(&snac); + } + } + } + else + if (xs_startswith(resource, "acct:")) { + /* it's an account name */ + xs *an = xs_replace(resource, "acct:", ""); + xs *l = NULL; + + /* strip a possible leading @ */ + if (xs_startswith(an, "@")) + an = xs_crop(an, 1, 0); + + l = xs_split_n(an, "@", 1); + + if (xs_list_len(l) == 2) { + char *uid = xs_list_get(l, 0); + char *host = xs_list_get(l, 1); + + if (strcmp(host, xs_dict_get(srv_config, "host")) == 0) + found = user_open(&snac, uid); + } + } + + if (found) { + /* build the object */ + xs *acct; + xs *aaj = xs_dict_new(); + xs *links = xs_list_new(); + xs *obj = xs_dict_new(); + d_char *j; + + acct = xs_fmt("acct:%s@%s", + xs_dict_get(snac.config, "uid"), xs_dict_get(srv_config, "host")); + + aaj = xs_dict_append(aaj, "rel", "self"); + aaj = xs_dict_append(aaj, "type", "application/activity+json"); + aaj = xs_dict_append(aaj, "href", snac.actor); + + links = xs_list_append(links, aaj); + + obj = xs_dict_append(obj, "subject", acct); + obj = xs_dict_append(obj, "links", links); + + j = xs_json_dumps_pp(obj, 4); + + user_free(&snac); + + *status = 200; + *body = j; + *ctype = "application/json"; + } +}