open Wormhole let (fake_post : Post.t) = { link = "https://mccd.space"; summary = "My personal blog"; tags = [ "cool"; "article" ]; published = "2020-01-01T00:00:00Z"; author = "Marc"; } let (fake_post_2 : Post.t) = { link = "https://google.com"; summary = "Some other cool article that I just made"; tags = [ "cool"; "something" ]; published = "2020-01-02T00:00:00Z"; author = "Bob"; } let webfinger = {| { "subject": "acct:wormhole@galaxy.mccd.space", "links": [ { "rel": "self", "type": "application/activity+json", "href": "https://galaxy.mccd.space/actor" } ] } |} let actor = {| { "@context": [ "https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1" ], "id": "https://galaxy.mccd.space/actor", "type": "Person", "preferredUsername": "wormhole", "inbox": "https://galaxy.mccd.space/inbox", "publicKey": { "id": "https://galaxy.mccd.space/actor#main-key", "owner": "https://galaxy.mccd.space/actor", "publicKeyPem": "-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvqa9W2PjNYB6FDuRewSR\nAUyH2TK5iprbfuKWvCGEYq2FRccjmoluMEb0a16AyqqMeZ8J+pI7cPvqpdXm/VVV\niZx3Q5W4H8kIC3I84qAAzVs3wOQWnudk+D+hEE1Il9+yFBFvF7IoyER9axqJEb88\nYQ5okLU/346SMpMrk4wsUFnwaxdVXQPBQ0tVxqVJiLGSMlGXX/1Vl0+lnhgg+5rH\n8rfIbFX4qQC/gYbEU+VS2nzhYjdqn0maL94OrFHYNdrMBgSBOtbBFSJ+kMgojqES\n7Xhf+G9JcuCIqm0T3dHqo50MUSx8lrS78S3uO7WgPAby8qXjcL8sQEfNvJT16sjk\ndwIDAQAB\n-----END PUBLIC KEY-----" } } |} let () = Post.add fake_post; Post.add fake_post_2; let port = Sys.getenv_opt "PORT" |> Option.map int_of_string |> Option.value ~default:8080 in let env = Sys.getenv_opt "ENV" |> Option.value ~default:"PROD" in let interface = if env = "DEV" then "localhost" else "0.0.0.0" in Dream.run ~port ~interface @@ Dream.logger @@ Dream.router [ Dream.get "/actor" (fun _ -> Dream.log "Sending actor"; Dream.respond actor ~headers:[ ("Content-Type", "application/activity+json") ]); Dream.get "/.well-known/webfinger" (fun _ -> Dream.log "Sending webfinger"; Dream.respond webfinger ~headers:[ ("Content-Type", "application/activity+json") ]); Dream.get "/" (fun request -> Dream.log "Sending greeting to %s!" (Dream.client request); let posts = Post.get_all () in Template.render posts |> Dream.html); Dream.post "/inbox" (fun request -> let%lwt body = Dream.body request in Dream.log "Got body: %s" body; let signature = Dream.headers request "signature" in Dream.log "Got signature: %s" (String.concat " " signature); let message_object = Yojson.Safe.from_string body |> Post.mastodon_post_of_yojson in let%lwt actor = User.get_user (Post.mastodon_actor message_object) in match actor with | Error e -> Dream.log "User not found %s" (Printexc.to_string e); let code = Some 400 in Dream.json ?code "User not found" | Ok actor -> Dream.log "User found"; let pem = User.get_public_pem actor |> Result.to_option in let%lwt valid_request = Sig.verify_request pem request in (match valid_request with | Error e -> Dream.log "Error verifying request %s" Printexc.(to_string e); let code = Some 500 in Dream.json ?code "Invalid request" | Ok false -> Dream.log "Unauthorized request"; let code = Some 501 in Dream.json ?code "Unauthorized" | Ok true -> message_object |> Post.post_of_mastodon_post (User.name actor) |> Post.add; message_object |> Post.yojson_of_mastodon_post |> Yojson.Safe.to_string |> Dream.log "Added post %s"; Dream.json "Added user")); ]