commit 9a39254b3de99148c6509e7c4d52f769a303e255
parent 3dd0ec81b9f72f86005f543ac8fe577bb3ad09a0
Author: William Casarin <jb55@jb55.com>
Date: Sun, 17 Jan 2021 11:26:08 -0800
remove remaining wolfsocks references
Diffstat:
M | Makefile | | | 6 | +++--- |
M | default.nix | | | 2 | +- |
A | src/chibipub.c | | | 493 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
D | src/wolfsocks.c | | | 493 | ------------------------------------------------------------------------------- |
4 files changed, 497 insertions(+), 497 deletions(-)
diff --git a/Makefile b/Makefile
@@ -23,7 +23,7 @@ BLAKE3_OBJS = deps/blake3/blake3.o \
HEADERS = $(wildcard src/*.h) deps/sha256/sha256.h
-all: wolfsocks
+all: chibipub
%.o: %.c
@echo "cc $<"
@@ -44,7 +44,7 @@ deps/blake3/blake3.a: $(BLAKE3_OBJS)
corpus/math.json:
curl --compressed -sL 'https://jb55.com/s/5aaaae6d64be61fd.json' > $@
-wolfsocks: src/wolfsocks.c $(OBJS) $(HEADERS)
+chibipub: src/chibipub.c $(OBJS) $(HEADERS)
@echo "ld $@"
@$(CC) $(CFLAGS) $< $(OBJS) $(LDFLAGS) -o $@
@@ -55,7 +55,7 @@ check: src/test_json
./src/test_json
clean: fake
- rm -f $(OBJS) $(BLAKE3_OBJS) deps/blake3/blake3.a wolfsocks src/test_json
+ rm -f $(OBJS) $(BLAKE3_OBJS) deps/blake3/blake3.a chibipub src/test_json
tags: fake
ctags src/*.c deps/sha256/sha256.c $(HEADERS)
diff --git a/default.nix b/default.nix
@@ -1,7 +1,7 @@
{ pkgs ? import <nixpkgs> {} }:
with pkgs;
stdenv.mkDerivation {
- name = "wolfsocks";
+ name = "chibipub";
nativeBuildInputs = [ gdb pkg-config ngrok clib ];
buildInputs = [ openssl ];
}
diff --git a/src/chibipub.c b/src/chibipub.c
@@ -0,0 +1,493 @@
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <assert.h>
+#include <base64.h>
+
+#include "http.h"
+#include "ap_json.h"
+#include "inbox.h"
+#include "json.h"
+#include "sigcheck.h"
+
+#define BUF_SIZE 1048576
+#define ARENA_SIZE 134217728 /* 128 MB virtual mem arena */
+#define streq(a,b) (!strcmp(a,b))
+#define patheq(req, x) (streq(x, req->path) || streq(x "/", req->path))
+
+struct webfinger {
+ const char *acct;
+ const char *alias;
+ const char *profile_page;
+ const char *self;
+};
+
+static void error(char *msg)
+{
+ perror(msg);
+ exit(1);
+}
+
+static inline const char *get_hostname()
+{
+ return getenv("CHIBIPUB_HOST");
+}
+
+
+#define SCHEMA "https://"
+
+static void init_test_webfinger(struct webfinger *finger)
+{
+ static unsigned char buf[512];
+ struct cursor c;
+ make_cursor(buf, buf+sizeof(buf), &c);
+
+ const char *host = get_hostname();
+ assert(host);
+
+ finger->acct = (char*)c.p;
+
+ assert(
+ push_str(&c, "jb55@") && push_c_str(&c, host)
+ );
+
+ finger->alias = (char*)c.p;
+
+ assert(
+ push_str(&c, SCHEMA) && push_str(&c, host) &&
+ push_c_str(&c, "/alias")
+ );
+
+ finger->profile_page = (char*)c.p;
+
+ assert(
+ push_str(&c, SCHEMA) && push_str(&c, host) &&
+ push_c_str(&c, "/profile")
+ );
+
+ finger->self = (char*)c.p;
+
+ assert(
+ push_str(&c, SCHEMA) && push_str(&c, host) &&
+ push_c_str(&c, "/")
+ );
+}
+
+static inline void write_status(struct http_req *req, const char *status)
+{
+ fprintf(req->client.socket_file, "HTTP/1.1 %s\r\n", status);
+}
+
+static inline void write_resp_header(struct http_req *req, const char *status)
+{
+ write_status(req, status);
+ fprintf(req->client.socket_file, "Connection: close\r\n");
+ fprintf(req->client.socket_file, "\r\n");
+}
+
+static int handle_webfinger(struct http_req *req)
+{
+ struct webfinger finger;
+
+ init_test_webfinger(&finger);
+
+ write_resp_header(req, "200 OK");
+
+ fprintf(req->client.socket_file,
+ "{\"subject\": \"acct:%s\","
+ " \"aliases\": [\"%s\"],"
+ " \"links\": [{"
+ " \"rel\": \"http://webfinger.net/rel/profile-page\","
+ " \"type\": \"text/html\","
+ " \"href\": \"%s\""
+ " },{"
+ " \"rel\":\"self\","
+ " \"type\": \"application/activity+json\","
+ " \"href\": \"%s\""
+ " }]}\r\n",
+ finger.acct,
+ finger.alias,
+ finger.profile_page,
+ finger.self);
+
+ return 1;
+}
+
+
+static inline int starts_with(const char *str, const char *prefix)
+{
+ unsigned int prefix_size;
+ prefix_size = strlen(prefix);
+
+ if (prefix_size > strlen(str)) {
+ return 0;
+ }
+
+ return !memcmp(str, prefix, prefix_size);
+}
+
+static void http_log(struct http_req *req)
+{
+ printf("%s - \"%s %s %s\"\n",
+ req->client.addr_str,
+ req->method,
+ req->path,
+ req->ver);
+}
+
+static int handle_inbox_request(struct http_req *req, struct cursor *arena)
+{
+ const char *signature;
+ unsigned char *start;
+ FILE *out;
+ int len;
+ struct sig_header sig;
+ struct json_parser pull;
+ struct json_pusher push;
+ struct ap_json apjson;
+
+ struct json_handlers compact;
+ struct json_handlers ap_handler;
+
+ make_compact_handlers(&compact, &push);
+ make_ap_json_pusher(&ap_handler, &apjson);
+ init_ap_json(&apjson, &compact);
+
+ memset(&sig, 0, sizeof(sig));
+
+ if (!get_header(req->headers, "signature", &signature)) {
+ note_error(&req->errs, "signature");
+ return 0;
+ }
+
+ printf("signature: %s\n", signature);
+
+ if (!parse_signature_header(&req->errs, arena, signature, strlen(signature), &sig)) {
+ note_error(&req->errs, "parse signature header");
+ return 0;
+ }
+
+ apjson.sig = &sig;
+ apjson.req = req;
+
+ // TODO: defer this check
+ if (!verify_signature_header(&sig)) {
+ note_error(&req->errs, "verify");
+ return 0;
+ }
+
+ start = arena->p;
+ init_json_pusher_with(&push, arena);
+
+ init_json_parser(&pull, req->body, req->body_len, &ap_handler);
+ if (!parse_json(&pull)) {
+ note_error(&req->errs, "json parse failed");
+ return 0;
+ }
+
+ if (!(out = fopen("activities.json", "a"))) {
+ note_error(&req->errs, "could not open activities.json");
+ return 0;
+ }
+
+ len = push.cur.p - start;
+
+ // 128 KB
+ if (len >= 131072) {
+ note_error(&req->errs, "ActivityPub message too big");
+ return 0;
+ }
+
+ fwrite(start, len, 1, out);
+ fwrite("\n", 1, 1, out);
+ fclose(out);
+
+ write_resp_header(req, "200 OK");
+ return 1;
+}
+
+static inline int is_get(struct http_req *req)
+{
+ return streq(req->method, "GET");
+}
+
+static inline int is_post(struct http_req *req)
+{
+ return streq(req->method, "POST");
+}
+
+
+static inline int is_accept_activity(struct http_req *req)
+{
+ const char *accept;
+
+ if (!get_header(req->headers, "accept", &accept)) {
+ note_error(&req->errs, "accept");
+ return 0;
+ }
+
+ if (!strstr(accept, "application/activity+json")) {
+ note_error(&req->errs, "not accept: '%s'", accept);
+ return 0;
+ }
+
+ return 1;
+}
+
+struct profile
+{
+ const char *id;
+ const char *type;
+ const char *username;
+ const char *name;
+ const char *summary;
+ const char *url;
+ int manually_approves_followers;
+ const char *image_mime_type;
+ const char *image_url;
+ const char *key_id;
+ const char *pubkey_pem;
+};
+
+static void test_profile(struct profile *p)
+{
+ static unsigned char buf[128];
+ struct cursor c;
+ make_cursor(buf, buf + sizeof(buf), &c);
+
+ const char *host = get_hostname();
+ assert(host);
+
+ p->id = (char*)c.p;
+ assert(
+ push_str(&c, SCHEMA) && push_str(&c, host) && push_c_str(&c, "/")
+ );
+
+ p->type = "Person";
+ p->username = "jb55";
+ p->name = "William Casarin";
+ p->summary = "chibipub prototype";
+ p->url = p->id;
+ p->manually_approves_followers = 0;
+ p->image_mime_type = "image/jpeg";
+ p->image_url = "https://jb55.com/s/blue-me.jpg";
+ p->key_id = "main-key";
+ p->pubkey_pem = "-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnJOPxwmRGBBQYm7YgHRubTaYaKbMoEQiui+37nizXA73CRNeKblSXIaJnfOKfz/ttRG0GH43GzHTpghUDuZX+QBpyOk8UMmCW5gM0Y5c3IOv0zLezqLXrVEM8UXMUHE3hxf61r1NKl1+IG9MwhtHayx0Kaz6vT/V8nkotCSlb91lMT8X28bButwN86RCclZncecQXuVvgXnFeZCeBLM+qV2tBPnn14Ws+AqVvVnBW8xXwVfSPFHQchSLAusdWI7Kw/oWN/on2CqfRASoaVASqKG+uPuJ+1f92iH0ZY1wLB2/ITl7HKTiIMKNikXTWcUudkMlKxc5Iqb7HMHuaPZ9IQIDAQAB-----END PUBLIC KEY-----";
+}
+
+static int handle_self(struct http_req *req)
+{
+ struct profile profile;
+ test_profile(&profile);
+
+ write_resp_header(req, "200 OK");
+
+ fprintf(req->client.socket_file,
+ "{"
+ "\"@context\": ["
+ "\"https://www.w3.org/ns/activitystreams\""
+ "],"
+ "\"inbox\": \"%sinbox\","
+ "\"id\": \"%s\","
+ "\"type\": \"%s\","
+ "\"preferredUsername\": \"%s\","
+ "\"name\": \"%s\","
+ "\"summary\": \"%s\","
+ "\"url\": \"%s\","
+ "\"manuallyApprovesFollowers\": %s,"
+ "\"icon\": {"
+ "\"type\": \"Image\","
+ "\"mediaType\": \"%s\","
+ "\"url\": \"%s\""
+ "},"
+ "\"publicKey\": {"
+ "\"id\": \"%s#%s\","
+ "\"owner\": \"%s\","
+ "\"publicKeyPem\": \"%s\""
+ "}"
+ "}\n",
+ profile.id,
+ profile.id,
+ profile.type,
+ profile.username,
+ profile.name,
+ profile.summary,
+ profile.url,
+ profile.manually_approves_followers ? "true" : "false",
+ profile.image_mime_type,
+ profile.image_url,
+ profile.id, profile.key_id,
+ profile.id,
+ profile.pubkey_pem);
+
+ return 1;
+}
+
+static int handle_request(struct http_req *req, struct cursor *arena)
+{
+ http_log(req);
+
+ if (starts_with(req->path, "/.well-known/webfinger?resource=acct:")) {
+ return handle_webfinger(req);
+ } else if (is_post(req) && patheq(req, "/inbox")) {
+ return handle_inbox_request(req, arena);
+ } else if (is_get(req) &&
+ is_accept_activity(req) &&
+ streq(req->path, "/")) {
+ return handle_self(req);
+ }
+
+ return 0;
+}
+
+static int http_accept_client(struct http_req *req, int parent)
+{
+ struct sockaddr_in *addr;
+ socklen_t client_len;
+ struct hostent *client_host;
+
+ client_len = sizeof(addr);
+
+ addr = &req->client.sockaddr;
+
+ req->client.socket =
+ accept(parent, (struct sockaddr *) &req->client.sockaddr,
+ &client_len);
+
+ if (req->client.socket < 0) {
+ note_error(&req->errs, "bad socket");
+ return 0;
+ }
+
+ req->client.socket_file = fdopen(req->client.socket, "wb");
+
+ client_host = gethostbyaddr((const char *)&addr->sin_addr.s_addr,
+ sizeof(addr->sin_addr.s_addr), AF_INET);
+
+ if (!client_host) {
+ note_error(&req->errs, "gethostbyaddr");
+ return 0;
+ }
+
+ req->client.addr_str = inet_ntoa(addr->sin_addr);
+
+ if (!req->client.addr_str) {
+ note_error(&req->errs, "inet_htoa");
+ return 0;
+ }
+
+ return 1;
+}
+
+void run_http_server()
+{
+ static unsigned char buffer[BUF_SIZE];
+ unsigned char *arena;
+
+ ssize_t len, size;
+
+ int parent;
+ struct sockaddr_in server_addr;
+ int optval;
+
+ struct http_req req;
+
+ struct parser parser;
+
+ const int port = 5188;
+ arena = malloc(ARENA_SIZE);
+ assert(arena);
+
+ if ((parent = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ error("socket");
+ }
+
+ optval = 1;
+ setsockopt(parent, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval,
+ sizeof(optval));
+
+ memset(&server_addr, 0, sizeof(server_addr));
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ server_addr.sin_port = htons(port);
+
+ if (bind(parent, (struct sockaddr *)&server_addr,
+ sizeof(server_addr)) < 0) {
+ error("bind");
+ }
+
+ printf("listening for activities on 0.0.0.0:%d\n", port);
+
+ if (listen(parent, 5) < 0) {
+ error("listen");
+ }
+
+ while (1) {
+ init_http_req(&req);
+ make_cursor(buffer, buffer + BUF_SIZE, &parser.cur);
+ make_cursor(arena, arena + ARENA_SIZE, &parser.arena);
+
+ http_accept_client(&req, parent);
+
+ for(size = 0;1;) {
+ len = read(req.client.socket, (void*)(buffer+size), BUF_SIZE-size);
+ size += len;
+ if (len == 0) {
+ break;
+ }
+
+ if (len != (BUF_SIZE-size)) {
+ break;
+ }
+ }
+
+ if (parse_http_request(&req, &parser, size)) {
+ handle_request(&req, &parser.arena);
+ }
+
+ fclose(req.client.socket_file);
+ close(req.client.socket);
+ }
+
+ free(arena);
+}
+
+static void load_config()
+{
+ if (!get_hostname()) {
+ printf("CHIBIPUB_HOST env not set\n");
+ exit(2);
+ }
+}
+
+static int checksigs()
+{
+ struct sigcheck check;
+ check.activity_file = "activities.json";
+ if (!sigcheck(&check)) {
+ printf("sigcheck failed\n");
+ return 1;
+ }
+ printf("ok\n");
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ if (argc >= 2 && !strcmp(argv[1], "checksigs")) {
+ return checksigs();
+ }
+
+ load_config();
+ run_http_server();
+
+ return 0;
+}
diff --git a/src/wolfsocks.c b/src/wolfsocks.c
@@ -1,493 +0,0 @@
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <netdb.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <ctype.h>
-#include <assert.h>
-#include <base64.h>
-
-#include "http.h"
-#include "ap_json.h"
-#include "inbox.h"
-#include "json.h"
-#include "sigcheck.h"
-
-#define BUF_SIZE 1048576
-#define ARENA_SIZE 134217728 /* 128 MB virtual mem arena */
-#define streq(a,b) (!strcmp(a,b))
-#define patheq(req, x) (streq(x, req->path) || streq(x "/", req->path))
-
-struct webfinger {
- const char *acct;
- const char *alias;
- const char *profile_page;
- const char *self;
-};
-
-static void error(char *msg)
-{
- perror(msg);
- exit(1);
-}
-
-static inline const char *get_hostname()
-{
- return getenv("CHIBIPUB_HOST");
-}
-
-
-#define SCHEMA "https://"
-
-static void init_test_webfinger(struct webfinger *finger)
-{
- static unsigned char buf[512];
- struct cursor c;
- make_cursor(buf, buf+sizeof(buf), &c);
-
- const char *host = get_hostname();
- assert(host);
-
- finger->acct = (char*)c.p;
-
- assert(
- push_str(&c, "jb55@") && push_c_str(&c, host)
- );
-
- finger->alias = (char*)c.p;
-
- assert(
- push_str(&c, SCHEMA) && push_str(&c, host) &&
- push_c_str(&c, "/alias")
- );
-
- finger->profile_page = (char*)c.p;
-
- assert(
- push_str(&c, SCHEMA) && push_str(&c, host) &&
- push_c_str(&c, "/profile")
- );
-
- finger->self = (char*)c.p;
-
- assert(
- push_str(&c, SCHEMA) && push_str(&c, host) &&
- push_c_str(&c, "/")
- );
-}
-
-static inline void write_status(struct http_req *req, const char *status)
-{
- fprintf(req->client.socket_file, "HTTP/1.1 %s\r\n", status);
-}
-
-static inline void write_resp_header(struct http_req *req, const char *status)
-{
- write_status(req, status);
- fprintf(req->client.socket_file, "Connection: close\r\n");
- fprintf(req->client.socket_file, "\r\n");
-}
-
-static int handle_webfinger(struct http_req *req)
-{
- struct webfinger finger;
-
- init_test_webfinger(&finger);
-
- write_resp_header(req, "200 OK");
-
- fprintf(req->client.socket_file,
- "{\"subject\": \"acct:%s\","
- " \"aliases\": [\"%s\"],"
- " \"links\": [{"
- " \"rel\": \"http://webfinger.net/rel/profile-page\","
- " \"type\": \"text/html\","
- " \"href\": \"%s\""
- " },{"
- " \"rel\":\"self\","
- " \"type\": \"application/activity+json\","
- " \"href\": \"%s\""
- " }]}\r\n",
- finger.acct,
- finger.alias,
- finger.profile_page,
- finger.self);
-
- return 1;
-}
-
-
-static inline int starts_with(const char *str, const char *prefix)
-{
- unsigned int prefix_size;
- prefix_size = strlen(prefix);
-
- if (prefix_size > strlen(str)) {
- return 0;
- }
-
- return !memcmp(str, prefix, prefix_size);
-}
-
-static void http_log(struct http_req *req)
-{
- printf("%s - \"%s %s %s\"\n",
- req->client.addr_str,
- req->method,
- req->path,
- req->ver);
-}
-
-static int handle_inbox_request(struct http_req *req, struct cursor *arena)
-{
- const char *signature;
- unsigned char *start;
- FILE *out;
- int len;
- struct sig_header sig;
- struct json_parser pull;
- struct json_pusher push;
- struct ap_json apjson;
-
- struct json_handlers compact;
- struct json_handlers ap_handler;
-
- make_compact_handlers(&compact, &push);
- make_ap_json_pusher(&ap_handler, &apjson);
- init_ap_json(&apjson, &compact);
-
- memset(&sig, 0, sizeof(sig));
-
- if (!get_header(req->headers, "signature", &signature)) {
- note_error(&req->errs, "signature");
- return 0;
- }
-
- printf("signature: %s\n", signature);
-
- if (!parse_signature_header(&req->errs, arena, signature, strlen(signature), &sig)) {
- note_error(&req->errs, "parse signature header");
- return 0;
- }
-
- apjson.sig = &sig;
- apjson.req = req;
-
- // TODO: defer this check
- if (!verify_signature_header(&sig)) {
- note_error(&req->errs, "verify");
- return 0;
- }
-
- start = arena->p;
- init_json_pusher_with(&push, arena);
-
- init_json_parser(&pull, req->body, req->body_len, &ap_handler);
- if (!parse_json(&pull)) {
- note_error(&req->errs, "json parse failed");
- return 0;
- }
-
- if (!(out = fopen("activities.json", "a"))) {
- note_error(&req->errs, "could not open activities.json");
- return 0;
- }
-
- len = push.cur.p - start;
-
- // 128 KB
- if (len >= 131072) {
- note_error(&req->errs, "ActivityPub message too big");
- return 0;
- }
-
- fwrite(start, len, 1, out);
- fwrite("\n", 1, 1, out);
- fclose(out);
-
- write_resp_header(req, "200 OK");
- return 1;
-}
-
-static inline int is_get(struct http_req *req)
-{
- return streq(req->method, "GET");
-}
-
-static inline int is_post(struct http_req *req)
-{
- return streq(req->method, "POST");
-}
-
-
-static inline int is_accept_activity(struct http_req *req)
-{
- const char *accept;
-
- if (!get_header(req->headers, "accept", &accept)) {
- note_error(&req->errs, "accept");
- return 0;
- }
-
- if (!strstr(accept, "application/activity+json")) {
- note_error(&req->errs, "not accept: '%s'", accept);
- return 0;
- }
-
- return 1;
-}
-
-struct profile
-{
- const char *id;
- const char *type;
- const char *username;
- const char *name;
- const char *summary;
- const char *url;
- int manually_approves_followers;
- const char *image_mime_type;
- const char *image_url;
- const char *key_id;
- const char *pubkey_pem;
-};
-
-static void test_profile(struct profile *p)
-{
- static unsigned char buf[128];
- struct cursor c;
- make_cursor(buf, buf + sizeof(buf), &c);
-
- const char *host = get_hostname();
- assert(host);
-
- p->id = (char*)c.p;
- assert(
- push_str(&c, SCHEMA) && push_str(&c, host) && push_c_str(&c, "/")
- );
-
- p->type = "Person";
- p->username = "jb55";
- p->name = "William Casarin";
- p->summary = "wolfsocks prototype";
- p->url = p->id;
- p->manually_approves_followers = 0;
- p->image_mime_type = "image/jpeg";
- p->image_url = "https://jb55.com/s/blue-me.jpg";
- p->key_id = "main-key";
- p->pubkey_pem = "-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnJOPxwmRGBBQYm7YgHRubTaYaKbMoEQiui+37nizXA73CRNeKblSXIaJnfOKfz/ttRG0GH43GzHTpghUDuZX+QBpyOk8UMmCW5gM0Y5c3IOv0zLezqLXrVEM8UXMUHE3hxf61r1NKl1+IG9MwhtHayx0Kaz6vT/V8nkotCSlb91lMT8X28bButwN86RCclZncecQXuVvgXnFeZCeBLM+qV2tBPnn14Ws+AqVvVnBW8xXwVfSPFHQchSLAusdWI7Kw/oWN/on2CqfRASoaVASqKG+uPuJ+1f92iH0ZY1wLB2/ITl7HKTiIMKNikXTWcUudkMlKxc5Iqb7HMHuaPZ9IQIDAQAB-----END PUBLIC KEY-----";
-}
-
-static int handle_self(struct http_req *req)
-{
- struct profile profile;
- test_profile(&profile);
-
- write_resp_header(req, "200 OK");
-
- fprintf(req->client.socket_file,
- "{"
- "\"@context\": ["
- "\"https://www.w3.org/ns/activitystreams\""
- "],"
- "\"inbox\": \"%sinbox\","
- "\"id\": \"%s\","
- "\"type\": \"%s\","
- "\"preferredUsername\": \"%s\","
- "\"name\": \"%s\","
- "\"summary\": \"%s\","
- "\"url\": \"%s\","
- "\"manuallyApprovesFollowers\": %s,"
- "\"icon\": {"
- "\"type\": \"Image\","
- "\"mediaType\": \"%s\","
- "\"url\": \"%s\""
- "},"
- "\"publicKey\": {"
- "\"id\": \"%s#%s\","
- "\"owner\": \"%s\","
- "\"publicKeyPem\": \"%s\""
- "}"
- "}\n",
- profile.id,
- profile.id,
- profile.type,
- profile.username,
- profile.name,
- profile.summary,
- profile.url,
- profile.manually_approves_followers ? "true" : "false",
- profile.image_mime_type,
- profile.image_url,
- profile.id, profile.key_id,
- profile.id,
- profile.pubkey_pem);
-
- return 1;
-}
-
-static int handle_request(struct http_req *req, struct cursor *arena)
-{
- http_log(req);
-
- if (starts_with(req->path, "/.well-known/webfinger?resource=acct:")) {
- return handle_webfinger(req);
- } else if (is_post(req) && patheq(req, "/inbox")) {
- return handle_inbox_request(req, arena);
- } else if (is_get(req) &&
- is_accept_activity(req) &&
- streq(req->path, "/")) {
- return handle_self(req);
- }
-
- return 0;
-}
-
-static int http_accept_client(struct http_req *req, int parent)
-{
- struct sockaddr_in *addr;
- socklen_t client_len;
- struct hostent *client_host;
-
- client_len = sizeof(addr);
-
- addr = &req->client.sockaddr;
-
- req->client.socket =
- accept(parent, (struct sockaddr *) &req->client.sockaddr,
- &client_len);
-
- if (req->client.socket < 0) {
- note_error(&req->errs, "bad socket");
- return 0;
- }
-
- req->client.socket_file = fdopen(req->client.socket, "wb");
-
- client_host = gethostbyaddr((const char *)&addr->sin_addr.s_addr,
- sizeof(addr->sin_addr.s_addr), AF_INET);
-
- if (!client_host) {
- note_error(&req->errs, "gethostbyaddr");
- return 0;
- }
-
- req->client.addr_str = inet_ntoa(addr->sin_addr);
-
- if (!req->client.addr_str) {
- note_error(&req->errs, "inet_htoa");
- return 0;
- }
-
- return 1;
-}
-
-void run_http_server()
-{
- static unsigned char buffer[BUF_SIZE];
- unsigned char *arena;
-
- ssize_t len, size;
-
- int parent;
- struct sockaddr_in server_addr;
- int optval;
-
- struct http_req req;
-
- struct parser parser;
-
- const int port = 5188;
- arena = malloc(ARENA_SIZE);
- assert(arena);
-
- if ((parent = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- error("socket");
- }
-
- optval = 1;
- setsockopt(parent, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval,
- sizeof(optval));
-
- memset(&server_addr, 0, sizeof(server_addr));
- server_addr.sin_family = AF_INET;
- server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
- server_addr.sin_port = htons(port);
-
- if (bind(parent, (struct sockaddr *)&server_addr,
- sizeof(server_addr)) < 0) {
- error("bind");
- }
-
- printf("listening for activities on 0.0.0.0:%d\n", port);
-
- if (listen(parent, 5) < 0) {
- error("listen");
- }
-
- while (1) {
- init_http_req(&req);
- make_cursor(buffer, buffer + BUF_SIZE, &parser.cur);
- make_cursor(arena, arena + ARENA_SIZE, &parser.arena);
-
- http_accept_client(&req, parent);
-
- for(size = 0;1;) {
- len = read(req.client.socket, (void*)(buffer+size), BUF_SIZE-size);
- size += len;
- if (len == 0) {
- break;
- }
-
- if (len != (BUF_SIZE-size)) {
- break;
- }
- }
-
- if (parse_http_request(&req, &parser, size)) {
- handle_request(&req, &parser.arena);
- }
-
- fclose(req.client.socket_file);
- close(req.client.socket);
- }
-
- free(arena);
-}
-
-static void load_config()
-{
- if (!get_hostname()) {
- printf("CHIBIPUB_HOST env not set\n");
- exit(2);
- }
-}
-
-static int checksigs()
-{
- struct sigcheck check;
- check.activity_file = "activities.json";
- if (!sigcheck(&check)) {
- printf("sigcheck failed\n");
- return 1;
- }
- printf("ok\n");
- return 0;
-}
-
-int main(int argc, char *argv[])
-{
- if (argc >= 2 && !strcmp(argv[1], "checksigs")) {
- return checksigs();
- }
-
- load_config();
- run_http_server();
-
- return 0;
-}