From 747b0718c1f9f6f6b90139990765d24b48bebbca Mon Sep 17 00:00:00 2001
From: Naoki Kosaka <n.k@mail.yukimochi.net>
Date: Thu, 15 Nov 2018 17:16:24 +0900
Subject: [PATCH] Implement Follow-request Pending.

---
 RelayConf/relayconf.go |  35 +++++++
 cli/cli.go             | 226 +++++++++++++++++++++++++----------------
 cli/config.go          |  35 +++++++
 cli/domain.go          |  71 +++++++++++++
 cli/follow.go          | 135 ++++++++++++++++++++++++
 decode_test.go         |   8 +-
 handle.go              |  43 ++++----
 main.go                |  24 ++---
 8 files changed, 451 insertions(+), 126 deletions(-)
 create mode 100644 RelayConf/relayconf.go
 create mode 100644 cli/config.go
 create mode 100644 cli/domain.go
 create mode 100644 cli/follow.go

diff --git a/RelayConf/relayconf.go b/RelayConf/relayconf.go
new file mode 100644
index 0000000..269187c
--- /dev/null
+++ b/RelayConf/relayconf.go
@@ -0,0 +1,35 @@
+package relayconf
+
+import "github.com/go-redis/redis"
+
+// RelayConfig : struct for relay configuration
+type RelayConfig struct {
+	BlockService   bool
+	ManuallyAccept bool
+}
+
+// LoadConfig : Loader for relay configuration
+func LoadConfig(redClient *redis.Client) RelayConfig {
+	blockService, err := redClient.HGet("relay:config", "block_service").Result()
+	if err != nil {
+		redClient.HSet("relay:config", "block_service", 0)
+		blockService = "0"
+	}
+	manuallyAccept, err := redClient.HGet("relay:config", "manually_accept").Result()
+	if err != nil {
+		redClient.HSet("relay:config", "manually_accept", 0)
+		manuallyAccept = "0"
+	}
+	return RelayConfig{
+		BlockService:   blockService == "1",
+		ManuallyAccept: manuallyAccept == "1",
+	}
+}
+
+func SetConfig(redClient *redis.Client, key string, value bool) {
+	strValue := 0
+	if value {
+		strValue = 1
+	}
+	redClient.HSet("relay:config", key, strValue)
+}
diff --git a/cli/cli.go b/cli/cli.go
index e8f9f6f..50d2190 100644
--- a/cli/cli.go
+++ b/cli/cli.go
@@ -1,126 +1,174 @@
 package main
 
 import (
+	"crypto/rsa"
 	"fmt"
 	"log"
+	"net/url"
 	"os"
-	"strings"
 
+	machinery "github.com/RichardKnop/machinery/v1"
+	"github.com/RichardKnop/machinery/v1/config"
 	"github.com/go-redis/redis"
 	"github.com/urfave/cli"
+	"github.com/yukimochi/Activity-Relay/KeyLoader"
 )
 
+var hostname *url.URL
+var hostkey *rsa.PrivateKey
 var redClient *redis.Client
-
-func listDomain(c *cli.Context) error {
-	var err error
-	var domains []string
-	var message string
-	switch c.String("type") {
-	case "limited":
-		message = " - Limited domain :"
-		domains, err = redClient.HKeys("relay:config:limitedDomain").Result()
-		if err != nil {
-			return err
-		}
-	case "blocked":
-		message = " - Blocked domain :"
-		domains, err = redClient.HKeys("relay:config:blockedDomain").Result()
-		if err != nil {
-			return err
-		}
-	default:
-		message = " - Subscribed domain :"
-		temp, err := redClient.Keys("relay:subscription:*").Result()
-		if err != nil {
-			return err
-		}
-		for _, domain := range temp {
-			domains = append(domains, strings.Replace(domain, "relay:subscription:", "", 1))
-		}
-	}
-	fmt.Println(message)
-	for _, domain := range domains {
-		fmt.Println(domain)
-	}
-	fmt.Println(fmt.Sprintf("Total : %d", len(domains)))
-	return nil
-}
-
-func manageDomain(c *cli.Context) error {
-	if c.String("domain") == "" {
-		fmt.Println("No domain given.")
-		return nil
-	}
-	switch c.String("type") {
-	case "limited":
-		if c.Bool("undo") {
-			redClient.HDel("relay:config:limitedDomain", c.String("domain"))
-			fmt.Println("Unregistrate [" + c.String("domain") + "] from Limited domain.")
-		} else {
-			redClient.HSet("relay:config:limitedDomain", c.String("domain"), "1")
-			fmt.Println("Registrate [" + c.String("domain") + "] as Limited domain.")
-		}
-	case "blocked":
-		if c.Bool("undo") {
-			redClient.HDel("relay:config:blockedDomain", c.String("domain"))
-			fmt.Println("Unregistrate [" + c.String("domain") + "] from Blocked domain.")
-		} else {
-			redClient.HSet("relay:config:blockedDomain", c.String("domain"), "1")
-			fmt.Println("Registrate [" + c.String("domain") + "] as Blocked domain.")
-		}
-	default:
-		fmt.Println("No type given.")
-	}
-	return nil
-}
+var macServer *machinery.Server
 
 func main() {
+	pemPath := os.Getenv("ACTOR_PEM")
+	if pemPath == "" {
+		panic("Require ACTOR_PEM environment variable.")
+	}
+	relayDomain := os.Getenv("RELAY_DOMAIN")
+	if relayDomain == "" {
+		panic("Require RELAY_DOMAIN environment variable.")
+	}
+	redisURL := os.Getenv("REDIS_URL")
+	if redisURL == "" {
+		redisURL = "127.0.0.1:6379"
+	}
+
+	var err error
+	hostkey, err = keyloader.ReadPrivateKeyRSAfromPath(pemPath)
+	if err != nil {
+		panic("Can't read Hostkey Pemfile")
+	}
+	hostname, err = url.Parse("https://" + relayDomain)
+	if err != nil {
+		panic("Can't parse Relay Domain")
+	}
 	redClient = redis.NewClient(&redis.Options{
-		Addr: os.Getenv("REDIS_URL"),
+		Addr: redisURL,
 	})
 
+	var macConfig = &config.Config{
+		Broker:          "redis://" + redisURL,
+		DefaultQueue:    "relay",
+		ResultBackend:   "redis://" + redisURL,
+		ResultsExpireIn: 5,
+	}
+
+	macServer, err = machinery.NewServer(macConfig)
+	if err != nil {
+		fmt.Println(err)
+	}
+
 	app := cli.NewApp()
 	app.Name = "Activity Relay Extarnal CLI"
 	app.Usage = "Control Relay configration"
 	app.Version = "0.0.2"
 	app.Commands = []cli.Command{
 		{
-			Name:    "list-domain",
-			Aliases: []string{"ld"},
-			Usage:   "List {subscribed,limited,blocked} domains",
-			Flags: []cli.Flag{
-				cli.StringFlag{
-					Name:  "type, t",
-					Value: "subscribed",
-					Usage: "Registrate type [subscribed,limited,blocked]",
+			Name:  "domain",
+			Usage: "Management domains",
+			Subcommands: []cli.Command{
+				{
+					Name:  "list",
+					Usage: "List {subscribed,limited,blocked} domains",
+					Flags: []cli.Flag{
+						cli.StringFlag{
+							Name:  "type, t",
+							Value: "subscribed",
+							Usage: "Domain type [subscribed,limited,blocked]",
+						},
+					},
+					Action: listDomains,
+				},
+				{
+					Name:  "set",
+					Usage: "set domain type [limited,blocked]",
+					Flags: []cli.Flag{
+						cli.StringFlag{
+							Name:  "type, t",
+							Usage: "Domain type [limited,blocked]",
+						},
+						cli.StringFlag{
+							Name:  "domain, d",
+							Usage: "Registrate domain",
+						},
+						cli.BoolFlag{
+							Name:  "undo, u",
+							Usage: "Undo registrate",
+						},
+					},
+					Action: setDomainType,
 				},
 			},
-			Action: listDomain,
 		},
 		{
-			Name:    "manage-domain",
-			Aliases: []string{"md"},
-			Usage:   "Manage {limited,blocked} domains",
-			Flags: []cli.Flag{
-				cli.StringFlag{
-					Name:  "type, t",
-					Usage: "Registrate type [limited,blocked]",
+			Name:  "config",
+			Usage: "Management relay config",
+			Subcommands: []cli.Command{
+				{
+					Name:   "show",
+					Usage:  "Show all relay configrations",
+					Action: listConfigs,
 				},
-				cli.StringFlag{
-					Name:  "domain, d",
-					Usage: "Registrate domain",
+				{
+					Name:  "service-block",
+					Usage: "Enable blocking for service-type actor",
+					Flags: []cli.Flag{
+						cli.BoolFlag{
+							Name:  "undo, u",
+							Usage: "Undo block",
+						},
+					},
+					Action: serviceBlock,
 				},
-				cli.BoolFlag{
-					Name:  "undo, u",
-					Usage: "Undo registrate",
+				{
+					Name:  "manually-accept",
+					Usage: "Enable Manually accept follow-request",
+					Flags: []cli.Flag{
+						cli.BoolFlag{
+							Name:  "undo, u",
+							Usage: "Undo block",
+						},
+					},
+					Action: manuallyAccept,
+				},
+			},
+		},
+		{
+			Name:  "follow-request",
+			Usage: "Management follow-request",
+			Subcommands: []cli.Command{
+				{
+					Name:   "show",
+					Usage:  "Show all follow-request",
+					Action: listFollows,
+				},
+				{
+					Name:  "reject",
+					Usage: "Reject follow-request",
+					Flags: []cli.Flag{
+						cli.StringFlag{
+							Name:  "domain, d",
+							Usage: "domain name",
+						},
+					},
+					Action: rejectFollow,
+				},
+				{
+					Name:  "accept",
+					Usage: "Accept follow-request",
+					Flags: []cli.Flag{
+						cli.StringFlag{
+							Name:  "domain, d",
+							Usage: "domain name",
+						},
+					},
+					Action: acceptFollow,
 				},
 			},
-			Action: manageDomain,
 		},
 	}
 
-	err := app.Run(os.Args)
+	err = app.Run(os.Args)
 	if err != nil {
 		log.Fatal(err)
 	}
diff --git a/cli/config.go b/cli/config.go
new file mode 100644
index 0000000..3525314
--- /dev/null
+++ b/cli/config.go
@@ -0,0 +1,35 @@
+package main
+
+import (
+	"fmt"
+
+	"github.com/urfave/cli"
+	"github.com/yukimochi/Activity-Relay/RelayConf"
+)
+
+func serviceBlock(c *cli.Context) {
+	if c.Bool("undo") {
+		relayconf.SetConfig(redClient, "block_service", false)
+		fmt.Println("Blocking for service-type actor is Disabled.")
+	} else {
+		relayconf.SetConfig(redClient, "block_service", true)
+		fmt.Println("Blocking for service-type actor is Enabled.")
+	}
+}
+
+func manuallyAccept(c *cli.Context) {
+	if c.Bool("undo") {
+		relayconf.SetConfig(redClient, "manually_accept", false)
+		fmt.Println("Manually accept follow-request is Disabled.")
+	} else {
+		relayconf.SetConfig(redClient, "manually_accept", true)
+		fmt.Println("Manually accept follow-request is Enabled.")
+	}
+}
+
+func listConfigs(c *cli.Context) {
+	config := relayconf.LoadConfig(redClient)
+
+	fmt.Println("Blocking for service-type actor : ", config.BlockService)
+	fmt.Println("Manually accept follow-request : ", config.ManuallyAccept)
+}
diff --git a/cli/domain.go b/cli/domain.go
new file mode 100644
index 0000000..39b4d21
--- /dev/null
+++ b/cli/domain.go
@@ -0,0 +1,71 @@
+package main
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/urfave/cli"
+)
+
+func listDomains(c *cli.Context) error {
+	var err error
+	var domains []string
+	var message string
+	switch c.String("type") {
+	case "limited":
+		fmt.Println(" - Limited domain :")
+		domains, err = redClient.HKeys("relay:config:limitedDomain").Result()
+		if err != nil {
+			return err
+		}
+	case "blocked":
+		fmt.Println(" - Blocked domain :")
+		domains, err = redClient.HKeys("relay:config:blockedDomain").Result()
+		if err != nil {
+			return err
+		}
+	default:
+		fmt.Println(" - Subscribed domain :")
+		temp, err := redClient.Keys("relay:subscription:*").Result()
+		if err != nil {
+			return err
+		}
+		for _, domain := range temp {
+			domains = append(domains, strings.Replace(domain, "relay:subscription:", "", 1))
+		}
+	}
+	fmt.Println(message)
+	for _, domain := range domains {
+		fmt.Println(domain)
+	}
+	fmt.Println(fmt.Sprintf("Total : %d", len(domains)))
+	return nil
+}
+
+func setDomainType(c *cli.Context) error {
+	if c.String("domain") == "" {
+		fmt.Println("No domain given.")
+		return nil
+	}
+	switch c.String("type") {
+	case "limited":
+		if c.Bool("undo") {
+			redClient.HDel("relay:config:limitedDomain", c.String("domain"))
+			fmt.Println("Unset [" + c.String("domain") + "] as Limited domain.")
+		} else {
+			redClient.HSet("relay:config:limitedDomain", c.String("domain"), "1")
+			fmt.Println("Set [" + c.String("domain") + "] as Limited domain.")
+		}
+	case "blocked":
+		if c.Bool("undo") {
+			redClient.HDel("relay:config:blockedDomain", c.String("domain"))
+			fmt.Println("Unset [" + c.String("domain") + "] as Blocked domain.")
+		} else {
+			redClient.HSet("relay:config:blockedDomain", c.String("domain"), "1")
+			fmt.Println("Set [" + c.String("domain") + "] as Blocked domain.")
+		}
+	default:
+		fmt.Println("No type given.")
+	}
+	return nil
+}
diff --git a/cli/follow.go b/cli/follow.go
new file mode 100644
index 0000000..5b57d23
--- /dev/null
+++ b/cli/follow.go
@@ -0,0 +1,135 @@
+package main
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/url"
+	"strings"
+	"unsafe"
+
+	"github.com/RichardKnop/machinery/v1/tasks"
+	"github.com/urfave/cli"
+	"github.com/yukimochi/Activity-Relay/ActivityPub"
+)
+
+func pushRegistorJob(inboxURL string, body []byte) {
+	job := &tasks.Signature{
+		Name:       "registor",
+		RetryCount: 25,
+		Args: []tasks.Arg{
+			{
+				Name:  "inboxURL",
+				Type:  "string",
+				Value: inboxURL,
+			},
+			{
+				Name:  "body",
+				Type:  "string",
+				Value: *(*string)(unsafe.Pointer(&body)),
+			},
+		},
+	}
+	_, err := macServer.SendTask(job)
+	if err != nil {
+		fmt.Println(err)
+	}
+}
+
+func listFollows(c *cli.Context) error {
+	var err error
+	var domains []string
+
+	fmt.Println(" - Follow request :")
+	follows, err := redClient.Keys("relay:pending:*").Result()
+	if err != nil {
+		return err
+	}
+	for _, follow := range follows {
+		domains = append(domains, strings.Replace(follow, "relay:pending:", "", 1))
+	}
+	for _, domain := range domains {
+		fmt.Println(domain)
+	}
+	return nil
+}
+
+func acceptFollow(c *cli.Context) error {
+	domain := c.String("domain")
+	if domain != "" {
+		num, err := redClient.Exists("relay:pending:" + domain).Result()
+		if err != nil {
+			return err
+		}
+		if num == 0 {
+			fmt.Println("Given domain not found.")
+			return nil
+		}
+
+		fmt.Println("Accept Follow request : " + domain)
+		data, err := redClient.HGetAll("relay:pending:" + domain).Result()
+		if err != nil {
+			return err
+		}
+		activity := activitypub.Activity{
+			[]string{"https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"},
+			data["activity_id"],
+			data["actor"],
+			data["type"],
+			data["object"],
+			nil,
+			nil,
+		}
+
+		actorDomain, _ := url.Parse(activity.Actor)
+		resp := activitypub.GenerateActivityResponse(hostname, actorDomain, "Accept", activity)
+		jsonData, _ := json.Marshal(&resp)
+
+		pushRegistorJob(data["inbox_url"], jsonData)
+		redClient.HSet("relay:subscription:"+domain, "inbox_url", data["inbox_url"])
+		redClient.Del("relay:pending:" + domain)
+		return nil
+	} else {
+		fmt.Println("No domain given.")
+		return nil
+	}
+}
+
+func rejectFollow(c *cli.Context) error {
+	domain := c.String("domain")
+	if domain != "" {
+		num, err := redClient.Exists("relay:pending:" + domain).Result()
+		if err != nil {
+			return err
+		}
+		if num == 0 {
+			fmt.Println("Given domain not found.")
+			return nil
+		}
+
+		fmt.Println("Reject Follow request : " + domain)
+		data, err := redClient.HGetAll("relay:pending:" + domain).Result()
+		if err != nil {
+			return err
+		}
+		activity := activitypub.Activity{
+			[]string{"https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"},
+			data["activity_id"],
+			data["actor"],
+			data["type"],
+			data["object"],
+			nil,
+			nil,
+		}
+
+		actorDomain, _ := url.Parse(activity.Actor)
+		resp := activitypub.GenerateActivityResponse(hostname, actorDomain, "Reject", activity)
+		jsonData, _ := json.Marshal(&resp)
+
+		pushRegistorJob(data["inbox_url"], jsonData)
+		redClient.Del("relay:pending:" + domain)
+		return nil
+	} else {
+		fmt.Println("No domain given.")
+		return nil
+	}
+}
diff --git a/decode_test.go b/decode_test.go
index 14ba1f2..ba65187 100644
--- a/decode_test.go
+++ b/decode_test.go
@@ -7,7 +7,9 @@ import (
 )
 
 func TestHandleInboxNoSignature(t *testing.T) {
-	s := httptest.NewServer(http.HandlerFunc(handleInbox))
+	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		handleInbox(w, r, decodeActivity)
+	}))
 	defer s.Close()
 
 	req, _ := http.NewRequest("POST", s.URL, nil)
@@ -22,7 +24,9 @@ func TestHandleInboxNoSignature(t *testing.T) {
 }
 
 func TestHandleInboxInvalidMethod(t *testing.T) {
-	s := httptest.NewServer(http.HandlerFunc(handleInbox))
+	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		handleInbox(w, r, decodeActivity)
+	}))
 	defer s.Close()
 
 	req, _ := http.NewRequest("GET", s.URL, nil)
diff --git a/handle.go b/handle.go
index 069cc4f..1103709 100644
--- a/handle.go
+++ b/handle.go
@@ -152,20 +152,21 @@ func suitableRelay(activity *activitypub.Activity, actor *activitypub.Actor) boo
 	if limited {
 		return false
 	}
-	if relConfig.blockService && actor.Type == "Service" {
+	if relConfig.BlockService && actor.Type == "Service" {
 		return false
 	}
 	return true
 }
 
-func handleInbox(w http.ResponseWriter, r *http.Request) {
+func handleInbox(w http.ResponseWriter, r *http.Request, activityDecoder func(*http.Request) (*activitypub.Activity, *activitypub.Actor, []byte, error)) {
 	switch r.Method {
 	case "POST":
-		activity, actor, body, err := decodeActivity(r)
+		activity, actor, body, err := activityDecoder(r)
 		if err != nil {
 			w.WriteHeader(400)
 			w.Write(nil)
 		} else {
+			domain, _ := url.Parse(activity.Actor)
 			switch activity.Type {
 			case "Follow":
 				err = followAcceptable(activity, actor)
@@ -173,29 +174,39 @@ func handleInbox(w http.ResponseWriter, r *http.Request) {
 					w.WriteHeader(400)
 					w.Write([]byte(err.Error()))
 				} else {
-					domain, _ := url.Parse(activity.Actor)
-					var responseType string
 					if suitableFollow(activity, actor) {
-						responseType = "Accept"
-						redClient.HSet("relay:subscription:"+domain.Host, "inbox_url", actor.Endpoints.SharedInbox)
+						if relConfig.ManuallyAccept {
+							redClient.HMSet("relay:pending:"+domain.Host, map[string]interface{}{
+								"inbox_url":   actor.Endpoints.SharedInbox,
+								"activity_id": activity.ID,
+								"type":        "Follow",
+								"actor":       actor.ID,
+								"object":      activity.Object.(string),
+							})
+							fmt.Println("Pending Follow Request : ", activity.Actor)
+						} else {
+							resp := activitypub.GenerateActivityResponse(hostname, domain, "Accept", *activity)
+							jsonData, _ := json.Marshal(&resp)
+							go pushRegistorJob(actor.Inbox, jsonData)
+							redClient.HSet("relay:subscription:"+domain.Host, "inbox_url", actor.Endpoints.SharedInbox)
+							fmt.Println("Accept Follow Request : ", activity.Actor)
+						}
 					} else {
-						responseType = "Reject"
+						resp := activitypub.GenerateActivityResponse(hostname, domain, "Reject", *activity)
+						jsonData, _ := json.Marshal(&resp)
+						go pushRegistorJob(actor.Inbox, jsonData)
+						fmt.Println("Reject Follow Request : ", activity.Actor)
 					}
-					resp := activitypub.GenerateActivityResponse(hostname, domain, responseType, *activity)
-					jsonData, _ := json.Marshal(&resp)
-					go pushRegistorJob(actor.Inbox, jsonData)
 
-					fmt.Println(responseType+" Follow Request : ", activity.Actor)
 					w.WriteHeader(202)
 					w.Write(nil)
 				}
 			case "Undo":
 				nestedActivity, _ := activitypub.DescribeNestedActivity(activity.Object)
 				if nestedActivity.Type == "Follow" && nestedActivity.Actor == activity.Actor {
-					domain, _ := url.Parse(activity.Actor)
 					redClient.Del("relay:subscription:" + domain.Host)
-
 					fmt.Println("Accept Unfollow Request : ", activity.Actor)
+
 					w.WriteHeader(202)
 					w.Write(nil)
 				} else {
@@ -206,8 +217,8 @@ func handleInbox(w http.ResponseWriter, r *http.Request) {
 					} else {
 						domain, _ := url.Parse(activity.Actor)
 						go pushRelayJob(domain.Host, body)
-
 						fmt.Println("Accept Relay Status : ", activity.Actor)
+
 						w.WriteHeader(202)
 						w.Write(nil)
 					}
@@ -219,9 +230,7 @@ func handleInbox(w http.ResponseWriter, r *http.Request) {
 					w.Write([]byte(err.Error()))
 				} else {
 					if suitableRelay(activity, actor) {
-						domain, _ := url.Parse(activity.Actor)
 						go pushRelayJob(domain.Host, body)
-
 						fmt.Println("Accept Relay Status : ", activity.Actor)
 					} else {
 						fmt.Println("Skipping Relay Status : ", activity.Actor)
diff --git a/main.go b/main.go
index 3893f8a..49fa837 100644
--- a/main.go
+++ b/main.go
@@ -12,6 +12,7 @@ import (
 	"github.com/go-redis/redis"
 	"github.com/yukimochi/Activity-Relay/ActivityPub"
 	"github.com/yukimochi/Activity-Relay/KeyLoader"
+	"github.com/yukimochi/Activity-Relay/RelayConf"
 )
 
 // Actor : Relay's Actor
@@ -20,26 +21,11 @@ var Actor activitypub.Actor
 // WebfingerResource : Relay's Webfinger resource
 var WebfingerResource activitypub.WebfingerResource
 
-type relayConfig struct {
-	blockService bool
-}
-
 var hostname *url.URL
 var hostkey *rsa.PrivateKey
 var redClient *redis.Client
 var macServer *machinery.Server
-var relConfig relayConfig
-
-func loadConfig() relayConfig {
-	blockService, err := redClient.HGet("relay:config", "block_service").Result()
-	if err != nil {
-		redClient.HSet("relay:config", "block_service", 0)
-		blockService = "0"
-	}
-	return relayConfig{
-		blockService: blockService == "1",
-	}
-}
+var relConfig relayconf.RelayConfig
 
 func main() {
 	pemPath := os.Getenv("ACTOR_PEM")
@@ -88,11 +74,13 @@ func main() {
 	WebfingerResource = activitypub.GenerateWebfingerResource(hostname, &Actor)
 
 	// Load Config
-	relConfig = loadConfig()
+	relConfig = relayconf.LoadConfig(redClient)
 
 	http.HandleFunc("/.well-known/webfinger", handleWebfinger)
 	http.HandleFunc("/actor", handleActor)
-	http.HandleFunc("/inbox", handleInbox)
+	http.HandleFunc("/inbox", func(w http.ResponseWriter, r *http.Request) {
+		handleInbox(w, r, decodeActivity)
+	})
 
 	fmt.Println("Welcome to YUKIMOCHI Activity-Relay [Server]\n - Configrations")
 	fmt.Println("RELAY DOMAIN : ", relayDomain)