diff --git a/data.go b/data.go
new file mode 100644
index 0000000..176c710
--- /dev/null
+++ b/data.go
@@ -0,0 +1,75 @@
+package main
+
+import (
+ "crypto/rsa"
+ "time"
+)
+
+type appDef struct {
+ Name string
+ WebhookURL string
+ PublicKey *rsa.PublicKey
+}
+
+var apps map[string]appDef
+
+type profileLink struct {
+ Rel string `json:"rel"`
+ Type string `json:"type"`
+ Href string `json:"href"`
+}
+
+type profileWebFingerData struct {
+ Subject string `json:"subject"`
+ Links []profileLink `json:"links"`
+}
+
+type pubKeyBlock struct {
+ ID string `json:"id"`
+ Owner string `json:"owner"`
+ PEM string `json:"publicKeyPem"`
+}
+
+type profilePage struct {
+ Context []string `json:"@context"`
+ ID string `json:"id"`
+ Type string `json:"type"`
+ PreferredUsername string `json:"preferredUsername"`
+ Name string `json:"name"`
+ Inbox string `json:"inbox"`
+ Followers string `json:"followers"`
+ PublicKey *pubKeyBlock `json:"publicKey,omitempty"`
+}
+
+type inboxPush struct {
+ Actor string `json:"actor"`
+ CC []string `json:"cc"`
+ ID string `json:"id"`
+ Object interface{} `json:"object"`
+ To []string `json:"to"`
+ Type string `json:"type"`
+ Context string `json:"context,omitempty"`
+ Published time.Time `json:"published,omitempty"`
+}
+
+type inboxCreatePayload struct {
+ Actor string `json:"actor"`
+ AttributedTo string `json:"attributedTo"`
+ CC []string `json:"cc"`
+ Content string `json:"content"`
+ Context string `json:"context"`
+ Conversation string `json:"conversation"`
+ ID string `json:"id"`
+ Published time.Time `json:"published"`
+ Sensitive bool `json:"sensitive"`
+ Source string `json:"source"`
+ Tag []tag `json:"tag"`
+ To []string `json:"to"`
+ Type string `json:"Type"`
+}
+
+type tag struct {
+ Href string `json:"href"`
+ Name string `json:"name"`
+ Type string `json:"type"`
+}
diff --git a/handlers.go b/handlers.go
new file mode 100644
index 0000000..593d969
--- /dev/null
+++ b/handlers.go
@@ -0,0 +1,115 @@
+package main
+
+import (
+ "crypto/x509"
+ "encoding/json"
+ "encoding/pem"
+ "fmt"
+ "net/http"
+ "strings"
+)
+
+func hostMetaHandler(w http.ResponseWriter, r *http.Request) {
+ headers := w.Header()
+ headers.Add("Content-Type", "application/xrd+xml")
+ headers.Add("Content-Type", "charset=utf-8")
+ fmt.Fprintf(w, ``, host)
+}
+
+func handlerUserPage(w http.ResponseWriter, r *http.Request) {
+ parts := strings.SplitN(strings.Trim(r.URL.Path, " /"), "/", 2)
+ if len(parts) < 2 {
+ http.Error(w, "page not found", http.StatusNotFound)
+ return
+ }
+ name := parts[1]
+ app, ok := apps[name]
+ if !ok {
+ http.Error(w, "page not found", http.StatusNotFound)
+ return
+ }
+ userURL := fmt.Sprintf("%s/u/%s", fullhost, name)
+
+ contextes := []string{
+ "https://www.w3.org/ns/activitystreams",
+ }
+
+ var pubkey *pubKeyBlock = nil
+ if app.PublicKey != nil {
+ pubKeyBytes := x509.MarshalPKCS1PublicKey(app.PublicKey)
+ pubKeyPem := string(pem.EncodeToMemory(&pem.Block{
+ Type: "PUBLIC KEY",
+ Bytes: pubKeyBytes,
+ }))
+ contextes = append(contextes, "https://w3id.org/security/v1")
+ pubkey = &pubKeyBlock{
+ ID: userURL + "#main-key",
+ Owner: userURL,
+ PEM: pubKeyPem,
+ }
+ }
+ headers := w.Header()
+ headers.Add("Content-Type", "application/activity+json")
+ headers.Add("Content-Type", "charset=utf-8")
+ err := json.NewEncoder(w).Encode(profilePage{
+ Context: contextes,
+ ID: userURL,
+ Type: "Person",
+ PreferredUsername: name,
+ Name: app.Name,
+ Inbox: fmt.Sprintf("%s/inbox", fullhost),
+ Followers: fmt.Sprintf("%s/followers", userURL),
+ PublicKey: pubkey,
+ })
+ if err != nil {
+ http.Error(w, "Error encoding page: "+err.Error(), http.StatusInternalServerError)
+ }
+}
+
+func handlerWebFinger(w http.ResponseWriter, r *http.Request) {
+ params := r.URL.Query()
+ resource := params.Get("resource")
+ if resource == "" {
+ http.Error(w, "must include a valid resource", http.StatusBadRequest)
+ return
+ }
+
+ parts := strings.SplitN(resource, ":", 2)
+ if len(parts) < 2 {
+ http.Error(w, "invalid resource specified", http.StatusBadRequest)
+ return
+ }
+ switch parts[0] {
+ case "acct":
+ // Split user by host
+ userParts := strings.SplitN(parts[1], "@", 2)
+ if len(userParts) < 2 || strings.ToLower(userParts[1]) != host {
+ http.Error(w, "Invalid user specified", http.StatusBadRequest)
+ return
+ }
+ // Check if user is a registered app
+ _, ok := apps[userParts[0]]
+ if !ok {
+ http.Error(w, "user not found", http.StatusNotFound)
+ return
+ }
+ headers := w.Header()
+ headers.Add("Content-Type", "application/json")
+ headers.Add("Content-Type", "charset=utf-8")
+
+ err := json.NewEncoder(w).Encode(profileWebFingerData{
+ Subject: resource,
+ Links: []profileLink{
+ {
+ Rel: "self",
+ Type: "application/activity+json",
+ Href: fmt.Sprintf("%s/u/%s", fullhost, userParts[0]),
+ },
+ },
+ })
+
+ if err != nil {
+ http.Error(w, "Error encoding webfinger: "+err.Error(), http.StatusInternalServerError)
+ }
+ }
+}
diff --git a/main.go b/main.go
index cb88e9c..db1c459 100644
--- a/main.go
+++ b/main.go
@@ -3,7 +3,6 @@ package main
import (
"crypto/rsa"
"crypto/x509"
- "encoding/json"
"encoding/pem"
"flag"
"fmt"
@@ -23,45 +22,11 @@ func mustGetEnv(env string) (val string) {
}
var host string
-
-type appDef struct {
- Name string
- WebhookURL string
- PublicKey *rsa.PublicKey
-}
-
-var apps map[string]appDef
-
-type profileLink struct {
- Rel string `json:"rel"`
- Type string `json:"type"`
- Href string `json:"href"`
-}
-
-type profileWebFingerData struct {
- Subject string `json:"subject"`
- Links []profileLink `json:"links"`
-}
-
-type pubKeyBlock struct {
- ID string `json:"id"`
- Owner string `json:"owner"`
- PEM string `json:"publicKeyPem"`
-}
-
-type profilePage struct {
- Context []string `json:"@context"`
- ID string `json:"id"`
- Type string `json:"type"`
- PreferredUsername string `json:"preferredUsername"`
- Name string `json:"name"`
- Inbox string `json:"inbox"`
- Followers string `json:"followers"`
- PublicKey *pubKeyBlock `json:"publicKey,omitempty"`
-}
+var fullhost string
+var prefix *string
func main() {
- prefix := flag.String("prefix", "AW_", "Environment var prefix")
+ prefix = flag.String("prefix", "AW_", "Environment var prefix")
proto := flag.String("proto", "https", "Protocol under which this server is going to be exposed")
flag.Parse()
@@ -71,8 +36,24 @@ func main() {
}
host = strings.ToLower(mustGetEnv(*prefix + "HOST"))
- fullhost := fmt.Sprintf("%s://%s", *proto, host)
+ fullhost = fmt.Sprintf("%s://%s", *proto, host)
+ discoverApps()
+
+ http.HandleFunc("/.well-known/host-meta", hostMetaHandler)
+ http.HandleFunc("/.well-known/webfinger", handlerWebFinger)
+ http.HandleFunc("/u/", handlerUserPage)
+ http.HandleFunc("/inbox", func(w http.ResponseWriter, r *http.Request) {
+ byt, _ := ioutil.ReadAll(r.Body)
+ fmt.Println(string(byt))
+ })
+
+ if err := http.ListenAndServe(bind, nil); err != nil {
+ log.Fatalf("error while listening: %f", err)
+ }
+}
+
+func discoverApps() {
// Find app definitions
envs := os.Environ()
envAppPrefix := *prefix + "APP_"
@@ -113,118 +94,4 @@ func main() {
log.Printf("app registered: %s", appName)
}
-
- http.HandleFunc("/.well-known/host-meta", func(w http.ResponseWriter, r *http.Request) {
- headers := w.Header()
- headers.Add("Content-Type", "application/xrd+xml")
- headers.Add("Content-Type", "charset=utf-8")
- fmt.Fprintf(w, ``, host)
- })
-
- http.HandleFunc("/.well-known/webfinger", func(w http.ResponseWriter, r *http.Request) {
- params := r.URL.Query()
- resource := params.Get("resource")
- if resource == "" {
- http.Error(w, "must include a valid resource", http.StatusBadRequest)
- return
- }
-
- parts := strings.SplitN(resource, ":", 2)
- if len(parts) < 2 {
- http.Error(w, "invalid resource specified", http.StatusBadRequest)
- return
- }
- switch parts[0] {
- case "acct":
- // Split user by host
- userParts := strings.SplitN(parts[1], "@", 2)
- if len(userParts) < 2 || strings.ToLower(userParts[1]) != host {
- http.Error(w, "Invalid user specified", http.StatusBadRequest)
- return
- }
- // Check if user is a registered app
- _, ok := apps[userParts[0]]
- if !ok {
- http.Error(w, "user not found", http.StatusNotFound)
- return
- }
- headers := w.Header()
- headers.Add("Content-Type", "application/json")
- headers.Add("Content-Type", "charset=utf-8")
-
- err := json.NewEncoder(w).Encode(profileWebFingerData{
- Subject: resource,
- Links: []profileLink{
- {
- Rel: "self",
- Type: "application/activity+json",
- Href: fmt.Sprintf("%s/u/%s", fullhost, userParts[0]),
- },
- },
- })
-
- if err != nil {
- http.Error(w, "Error encoding webfinger: "+err.Error(), http.StatusInternalServerError)
- }
- }
- })
-
- http.HandleFunc("/u/", func(w http.ResponseWriter, r *http.Request) {
- parts := strings.SplitN(strings.Trim(r.URL.Path, " /"), "/", 2)
- if len(parts) < 2 {
- http.Error(w, "page not found", http.StatusNotFound)
- return
- }
- name := parts[1]
- app, ok := apps[name]
- if !ok {
- http.Error(w, "page not found", http.StatusNotFound)
- return
- }
- userURL := fmt.Sprintf("%s/u/%s", fullhost, name)
-
- contextes := []string{
- "https://www.w3.org/ns/activitystreams",
- }
-
- var pubkey *pubKeyBlock = nil
- if app.PublicKey != nil {
- pubKeyBytes := x509.MarshalPKCS1PublicKey(app.PublicKey)
- pubKeyPem := string(pem.EncodeToMemory(&pem.Block{
- Type: "PUBLIC KEY",
- Bytes: pubKeyBytes,
- }))
- contextes = append(contextes, "https://w3id.org/security/v1")
- pubkey = &pubKeyBlock{
- ID: userURL + "#main-key",
- Owner: userURL,
- PEM: pubKeyPem,
- }
- }
- headers := w.Header()
- headers.Add("Content-Type", "application/activity+json")
- headers.Add("Content-Type", "charset=utf-8")
- err := json.NewEncoder(w).Encode(profilePage{
- Context: contextes,
- ID: userURL,
- Type: "Person",
- PreferredUsername: name,
- Name: app.Name,
- Inbox: fmt.Sprintf("%s/inbox", fullhost),
- Followers: fmt.Sprintf("%s/followers", userURL),
- PublicKey: pubkey,
- })
- if err != nil {
- http.Error(w, "Error encoding page: "+err.Error(), http.StatusInternalServerError)
- }
- })
-
- http.HandleFunc("/inbox", func(w http.ResponseWriter, r *http.Request) {
- byt, _ := ioutil.ReadAll(r.Body)
- fmt.Println(string(byt))
- })
-
- if err := http.ListenAndServe(bind, nil); err != nil {
- log.Fatalf("error while listening: %f", err)
- }
}