parent
a270868333
commit
8b23ec4d86
@ -15,6 +15,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Songmu/go-httpdate"
|
"github.com/Songmu/go-httpdate"
|
||||||
|
"github.com/satori/go.uuid"
|
||||||
"github.com/yukimochi/Activity-Relay/KeyLoader"
|
"github.com/yukimochi/Activity-Relay/KeyLoader"
|
||||||
"github.com/yukimochi/httpsig"
|
"github.com/yukimochi/httpsig"
|
||||||
)
|
)
|
||||||
@ -84,13 +85,32 @@ func RetrieveActor(url string) (*Actor, error) {
|
|||||||
// DescribeNestedActivity : Descrive Nested Activity Series
|
// DescribeNestedActivity : Descrive Nested Activity Series
|
||||||
func DescribeNestedActivity(nestedActivity interface{}) (*Activity, error) {
|
func DescribeNestedActivity(nestedActivity interface{}) (*Activity, error) {
|
||||||
mappedObject := nestedActivity.(map[string]interface{})
|
mappedObject := nestedActivity.(map[string]interface{})
|
||||||
|
if id, ok := mappedObject["id"].(string); ok {
|
||||||
return &Activity{
|
if nestedType, ok := mappedObject["type"].(string); ok {
|
||||||
ID: mappedObject["id"].(string),
|
actor, ok := mappedObject["actor"].(string)
|
||||||
Type: mappedObject["type"].(string),
|
if !ok {
|
||||||
Actor: mappedObject["actor"].(string),
|
actor = ""
|
||||||
Object: mappedObject["object"],
|
}
|
||||||
}, nil
|
switch object := mappedObject["object"].(type) {
|
||||||
|
case string:
|
||||||
|
return &Activity{
|
||||||
|
ID: id,
|
||||||
|
Type: nestedType,
|
||||||
|
Actor: actor,
|
||||||
|
Object: object,
|
||||||
|
}, nil
|
||||||
|
default:
|
||||||
|
return &Activity{
|
||||||
|
ID: id,
|
||||||
|
Type: nestedType,
|
||||||
|
Actor: actor,
|
||||||
|
Object: mappedObject["object"],
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, errors.New("Can't assart type")
|
||||||
|
}
|
||||||
|
return nil, errors.New("Can't assart id")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateActor : Generate Actor by hostname and publickey
|
// GenerateActor : Generate Actor by hostname and publickey
|
||||||
@ -127,8 +147,8 @@ func GenerateWebfingerResource(hostname *url.URL, actor *Actor) WebfingerResourc
|
|||||||
// GenerateActivityResponse : Generate Responce Activity to Activity
|
// GenerateActivityResponse : Generate Responce Activity to Activity
|
||||||
func GenerateActivityResponse(host *url.URL, to *url.URL, responseType string, activity Activity) Activity {
|
func GenerateActivityResponse(host *url.URL, to *url.URL, responseType string, activity Activity) Activity {
|
||||||
return Activity{
|
return Activity{
|
||||||
[]string{"https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"},
|
[]string{"https://www.w3.org/ns/activitystreams"},
|
||||||
host.String() + "/actor#accepts/follows/" + to.Host,
|
host.String() + "/activities/" + uuid.NewV4().String(),
|
||||||
host.String() + "/actor",
|
host.String() + "/actor",
|
||||||
responseType,
|
responseType,
|
||||||
&activity,
|
&activity,
|
||||||
@ -136,3 +156,16 @@ func GenerateActivityResponse(host *url.URL, to *url.URL, responseType string, a
|
|||||||
nil,
|
nil,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GenerateActivityAnnounce : Generate Announce Activity to Activity
|
||||||
|
func GenerateActivityAnnounce(host *url.URL, to *url.URL, actiivtyID string) Activity {
|
||||||
|
return Activity{
|
||||||
|
[]string{"https://www.w3.org/ns/activitystreams"},
|
||||||
|
host.String() + "/activities/" + uuid.NewV4().String(),
|
||||||
|
host.String() + "/actor",
|
||||||
|
"Announce",
|
||||||
|
actiivtyID,
|
||||||
|
[]string{host.String() + "/actor/followers"},
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -4,8 +4,9 @@ import "github.com/go-redis/redis"
|
|||||||
|
|
||||||
// RelayConfig : struct for relay configuration
|
// RelayConfig : struct for relay configuration
|
||||||
type RelayConfig struct {
|
type RelayConfig struct {
|
||||||
BlockService bool
|
BlockService bool
|
||||||
ManuallyAccept bool
|
ManuallyAccept bool
|
||||||
|
CreateAsAnnounce bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadConfig : Loader for relay configuration
|
// LoadConfig : Loader for relay configuration
|
||||||
@ -20,9 +21,15 @@ func LoadConfig(redClient *redis.Client) RelayConfig {
|
|||||||
redClient.HSet("relay:config", "manually_accept", 0)
|
redClient.HSet("relay:config", "manually_accept", 0)
|
||||||
manuallyAccept = "0"
|
manuallyAccept = "0"
|
||||||
}
|
}
|
||||||
|
createAsAnnounce, err := redClient.HGet("relay:config", "create_as_announce").Result()
|
||||||
|
if err != nil {
|
||||||
|
redClient.HSet("relay:config", "create_as_announce", 0)
|
||||||
|
createAsAnnounce = "0"
|
||||||
|
}
|
||||||
return RelayConfig{
|
return RelayConfig{
|
||||||
BlockService: blockService == "1",
|
BlockService: blockService == "1",
|
||||||
ManuallyAccept: manuallyAccept == "1",
|
ManuallyAccept: manuallyAccept == "1",
|
||||||
|
CreateAsAnnounce: createAsAnnounce == "1",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
11
cli/cli.go
11
cli/cli.go
@ -131,6 +131,17 @@ func main() {
|
|||||||
},
|
},
|
||||||
Action: manuallyAccept,
|
Action: manuallyAccept,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "create-as-announce",
|
||||||
|
Usage: "Enable Announce activity instead of relay create activity (Not recommended)",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "undo, u",
|
||||||
|
Usage: "Undo block",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: createAsAnnounce,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -27,9 +27,20 @@ func manuallyAccept(c *cli.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createAsAnnounce(c *cli.Context) {
|
||||||
|
if c.Bool("undo") {
|
||||||
|
relayconf.SetConfig(redClient, "create_as_announce", false)
|
||||||
|
fmt.Println("Announce activity instead of relay create activity is Disabled.")
|
||||||
|
} else {
|
||||||
|
relayconf.SetConfig(redClient, "create_as_announce", true)
|
||||||
|
fmt.Println("Announce activity instead of relay create activity is Enabled.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func listConfigs(c *cli.Context) {
|
func listConfigs(c *cli.Context) {
|
||||||
config := relayconf.LoadConfig(redClient)
|
config := relayconf.LoadConfig(redClient)
|
||||||
|
|
||||||
fmt.Println("Blocking for service-type actor : ", config.BlockService)
|
fmt.Println("Blocking for service-type actor : ", config.BlockService)
|
||||||
fmt.Println("Manually accept follow-request : ", config.ManuallyAccept)
|
fmt.Println("Manually accept follow-request : ", config.ManuallyAccept)
|
||||||
|
fmt.Println("Announce activity instead of relay create activity : ", config.CreateAsAnnounce)
|
||||||
}
|
}
|
||||||
|
20
handle.go
20
handle.go
@ -230,8 +230,24 @@ func handleInbox(w http.ResponseWriter, r *http.Request, activityDecoder func(*h
|
|||||||
w.Write([]byte(err.Error()))
|
w.Write([]byte(err.Error()))
|
||||||
} else {
|
} else {
|
||||||
if suitableRelay(activity, actor) {
|
if suitableRelay(activity, actor) {
|
||||||
go pushRelayJob(domain.Host, body)
|
if relConfig.CreateAsAnnounce && activity.Type == "Create" {
|
||||||
fmt.Println("Accept Relay Status : ", activity.Actor)
|
nestedObject, err := activitypub.DescribeNestedActivity(activity.Object)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Fail Assert activity : activity.Actor")
|
||||||
|
}
|
||||||
|
switch nestedObject.Type {
|
||||||
|
case "Note":
|
||||||
|
resp := activitypub.GenerateActivityAnnounce(hostname, domain, nestedObject.ID)
|
||||||
|
jsonData, _ := json.Marshal(&resp)
|
||||||
|
go pushRelayJob(domain.Host, jsonData)
|
||||||
|
fmt.Println("Accept Announce Note : ", activity.Actor)
|
||||||
|
default:
|
||||||
|
fmt.Println("Skipping Announce", nestedObject.Type, ": ", activity.Actor)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
go pushRelayJob(domain.Host, body)
|
||||||
|
fmt.Println("Accept Relay Status : ", activity.Actor)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Skipping Relay Status : ", activity.Actor)
|
fmt.Println("Skipping Relay Status : ", activity.Actor)
|
||||||
}
|
}
|
||||||
|
@ -190,6 +190,11 @@ func mockActivity(req string) activitypub.Activity {
|
|||||||
var activity activitypub.Activity
|
var activity activitypub.Activity
|
||||||
json.Unmarshal([]byte(body), &activity)
|
json.Unmarshal([]byte(body), &activity)
|
||||||
return activity
|
return activity
|
||||||
|
case "Create-Article":
|
||||||
|
body := "{\"@context\":[\"https://www.w3.org/ns/activitystreams\",\"https://w3id.org/security/v1\",{\"manuallyApprovesFollowers\":\"as:manuallyApprovesFollowers\",\"sensitive\":\"as:sensitive\",\"movedTo\":{\"@id\":\"as:movedTo\",\"@type\":\"@id\"},\"Hashtag\":\"as:Hashtag\",\"ostatus\":\"http://ostatus.org#\",\"atomUri\":\"ostatus:atomUri\",\"inReplyToAtomUri\":\"ostatus:inReplyToAtomUri\",\"conversation\":\"ostatus:conversation\",\"toot\":\"http://joinmastodon.org/ns#\",\"Emoji\":\"toot:Emoji\",\"focalPoint\":{\"@container\":\"@list\",\"@id\":\"toot:focalPoint\"},\"featured\":{\"@id\":\"toot:featured\",\"@type\":\"@id\"},\"schema\":\"http://schema.org#\",\"PropertyValue\":\"schema:PropertyValue\",\"value\":\"schema:value\"}],\"id\":\"https://mastodon.test.yukimochi.io/users/yukimochi/statuses/101075045564444857/activity\",\"type\":\"Create\",\"actor\":\"https://mastodon.test.yukimochi.io/users/yukimochi\",\"published\":\"2018-11-15T11:07:26Z\",\"to\":[\"https://www.w3.org/ns/activitystreams#Public\"],\"cc\":[\"https://mastodon.test.yukimochi.io/users/yukimochi/followers\"],\"object\":{\"id\":\"https://mastodon.test.yukimochi.io/users/yukimochi/statuses/101075045564444857\",\"type\":\"Article\",\"summary\":null,\"inReplyTo\":null,\"published\":\"2018-11-15T11:07:26Z\",\"url\":\"https://mastodon.test.yukimochi.io/@yukimochi/101075045564444857\",\"attributedTo\":\"https://mastodon.test.yukimochi.io/users/yukimochi\",\"to\":[\"https://www.w3.org/ns/activitystreams#Public\"],\"cc\":[\"https://mastodon.test.yukimochi.io/users/yukimochi/followers\"],\"sensitive\":false,\"atomUri\":\"https://mastodon.test.yukimochi.io/users/yukimochi/statuses/101075045564444857\",\"inReplyToAtomUri\":null,\"conversation\":\"tag:mastodon.test.yukimochi.io,2018-11-15:objectId=68:objectType=Conversation\",\"content\":\"<p>Actvity-Relay</p>\",\"contentMap\":{\"en\":\"<p>Actvity-Relay</p>\"},\"attachment\":[],\"tag\":[]},\"signature\":{\"type\":\"RsaSignature2017\",\"creator\":\"https://mastodon.test.yukimochi.io/users/yukimochi#main-key\",\"created\":\"2018-11-15T11:07:26Z\",\"signatureValue\":\"mMgl2GgVPgb1Kw6a2iDIZc7r0j3ob+Cl9y+QkCxIe6KmnUzb15e60UuhkE5j3rJnoTwRKqOFy1PMkSxlYW6fPG/5DBxW9I4kX+8sw8iH/zpwKKUOnXUJEqfwRrNH2ix33xcs/GkKPdedY6iAPV9vGZ10MSMOdypfYgU9r+UI0sTaaC2iMXH0WPnHQuYAI+Q1JDHIbDX5FH1WlDL6+8fKAicf3spBMxDwPHGPK8W2jmDLWdN2Vz4ffsCtWs5BCuqOKZrtTW0Rdd4HWzo40MnRXvBjv7yNlnnKzokANBqiOLWT7kNfK0+Vtnt6c/bNX64KBro53KR7wL3ZBvPVuv5rdQ==\"}}"
|
||||||
|
var activity activitypub.Activity
|
||||||
|
json.Unmarshal([]byte(body), &activity)
|
||||||
|
return activity
|
||||||
case "Announce":
|
case "Announce":
|
||||||
body := "{\"@context\":[\"https://www.w3.org/ns/activitystreams\",\"https://w3id.org/security/v1\",{\"manuallyApprovesFollowers\":\"as:manuallyApprovesFollowers\",\"sensitive\":\"as:sensitive\",\"movedTo\":{\"@id\":\"as:movedTo\",\"@type\":\"@id\"},\"Hashtag\":\"as:Hashtag\",\"ostatus\":\"http://ostatus.org#\",\"atomUri\":\"ostatus:atomUri\",\"inReplyToAtomUri\":\"ostatus:inReplyToAtomUri\",\"conversation\":\"ostatus:conversation\",\"toot\":\"http://joinmastodon.org/ns#\",\"Emoji\":\"toot:Emoji\",\"focalPoint\":{\"@container\":\"@list\",\"@id\":\"toot:focalPoint\"},\"featured\":{\"@id\":\"toot:featured\",\"@type\":\"@id\"},\"schema\":\"http://schema.org#\",\"PropertyValue\":\"schema:PropertyValue\",\"value\":\"schema:value\"}],\"id\":\"https://mastodon.test.yukimochi.io/users/yukimochi/statuses/101075096728565994/activity\",\"type\":\"Announce\",\"actor\":\"https://mastodon.test.yukimochi.io/users/yukimochi\",\"published\":\"2018-11-15T11:20:27Z\",\"to\":[\"https://www.w3.org/ns/activitystreams#Public\"],\"cc\":[\"https://mastodon.test.yukimochi.io/users/yukimochi\",\"https://mastodon.test.yukimochi.io/users/yukimochi/followers\"],\"object\":\"https://mastodon.test.yukimochi.io/users/yukimochi/statuses/101075042939498980\",\"atomUri\":\"https://mastodon.test.yukimochi.io/users/yukimochi/statuses/101075096728565994/activity\",\"signature\":{\"type\":\"RsaSignature2017\",\"creator\":\"https://mastodon.test.yukimochi.io/users/yukimochi#main-key\",\"created\":\"2018-11-15T11:20:27Z\",\"signatureValue\":\"HUe7M49uoEE5bsCM7rrG1ruamKVuYclKYst4OHQHBcvGSWkMTYCG5OmNQMihpFAantN1Mhz+PWKubXsWmrEnUGDNtog9XDGo2iVbYDcD1wjrDz6EuJiq3CBjLpzQ+F04EIx8LK8WSq6pec+jaIxBJghBa7BNH5i77nUdD7QLZxglqljMkf/r2s1i1eDtVJVDLzU3PW05Qu6Z+RDGZrG137ZwLZ3a5hnFyUPqw3fSgdA4n+AmxYenIHorgj45bmI4QJB8X1TPuAadB2XDvnSTTSuJQyDPyR3kCafBWmXDrqb0MRREsc99KzS9L00OiOY31v0TXr78vjSDxoGzEE81cw==\"}}"
|
body := "{\"@context\":[\"https://www.w3.org/ns/activitystreams\",\"https://w3id.org/security/v1\",{\"manuallyApprovesFollowers\":\"as:manuallyApprovesFollowers\",\"sensitive\":\"as:sensitive\",\"movedTo\":{\"@id\":\"as:movedTo\",\"@type\":\"@id\"},\"Hashtag\":\"as:Hashtag\",\"ostatus\":\"http://ostatus.org#\",\"atomUri\":\"ostatus:atomUri\",\"inReplyToAtomUri\":\"ostatus:inReplyToAtomUri\",\"conversation\":\"ostatus:conversation\",\"toot\":\"http://joinmastodon.org/ns#\",\"Emoji\":\"toot:Emoji\",\"focalPoint\":{\"@container\":\"@list\",\"@id\":\"toot:focalPoint\"},\"featured\":{\"@id\":\"toot:featured\",\"@type\":\"@id\"},\"schema\":\"http://schema.org#\",\"PropertyValue\":\"schema:PropertyValue\",\"value\":\"schema:value\"}],\"id\":\"https://mastodon.test.yukimochi.io/users/yukimochi/statuses/101075096728565994/activity\",\"type\":\"Announce\",\"actor\":\"https://mastodon.test.yukimochi.io/users/yukimochi\",\"published\":\"2018-11-15T11:20:27Z\",\"to\":[\"https://www.w3.org/ns/activitystreams#Public\"],\"cc\":[\"https://mastodon.test.yukimochi.io/users/yukimochi\",\"https://mastodon.test.yukimochi.io/users/yukimochi/followers\"],\"object\":\"https://mastodon.test.yukimochi.io/users/yukimochi/statuses/101075042939498980\",\"atomUri\":\"https://mastodon.test.yukimochi.io/users/yukimochi/statuses/101075096728565994/activity\",\"signature\":{\"type\":\"RsaSignature2017\",\"creator\":\"https://mastodon.test.yukimochi.io/users/yukimochi#main-key\",\"created\":\"2018-11-15T11:20:27Z\",\"signatureValue\":\"HUe7M49uoEE5bsCM7rrG1ruamKVuYclKYst4OHQHBcvGSWkMTYCG5OmNQMihpFAantN1Mhz+PWKubXsWmrEnUGDNtog9XDGo2iVbYDcD1wjrDz6EuJiq3CBjLpzQ+F04EIx8LK8WSq6pec+jaIxBJghBa7BNH5i77nUdD7QLZxglqljMkf/r2s1i1eDtVJVDLzU3PW05Qu6Z+RDGZrG137ZwLZ3a5hnFyUPqw3fSgdA4n+AmxYenIHorgj45bmI4QJB8X1TPuAadB2XDvnSTTSuJQyDPyR3kCafBWmXDrqb0MRREsc99KzS9L00OiOY31v0TXr78vjSDxoGzEE81cw==\"}}"
|
||||||
var activity activitypub.Activity
|
var activity activitypub.Activity
|
||||||
@ -537,6 +542,64 @@ func TestHandleInboxlimitedCreate(t *testing.T) {
|
|||||||
redClient.Del("relay:config:limitedDomain", domain.Host).Result()
|
redClient.Del("relay:config:limitedDomain", domain.Host).Result()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHandleInboxValidCreateAsAnnounceNote(t *testing.T) {
|
||||||
|
activity := mockActivity("Create")
|
||||||
|
actor := mockActor("Person")
|
||||||
|
domain, _ := url.Parse(activity.Actor)
|
||||||
|
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
handleInbox(w, r, mockActivityDecoderProvider(&activity, &actor))
|
||||||
|
}))
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
redClient.HSet("relay:subscription:"+domain.Host, "inbox_url", "https://mastodon.test.yukimochi.io/inbox").Result()
|
||||||
|
redClient.HSet("relay:subscription:example.org", "inbox_url", "https://example.org/inbox").Result()
|
||||||
|
redClient.HSet("relay:config", "create_as_announce", "1").Result()
|
||||||
|
relConfig = relayconf.LoadConfig(redClient)
|
||||||
|
|
||||||
|
req, _ := http.NewRequest("POST", s.URL, nil)
|
||||||
|
client := new(http.Client)
|
||||||
|
r, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed - " + err.Error())
|
||||||
|
}
|
||||||
|
if r.StatusCode != 202 {
|
||||||
|
t.Fatalf("Failed - StatusCode is not 202")
|
||||||
|
}
|
||||||
|
redClient.Del("relay:subscription:" + domain.Host).Result()
|
||||||
|
redClient.Del("relay:subscription:example.org").Result()
|
||||||
|
redClient.HSet("relay:config", "create_as_announce", "0").Result()
|
||||||
|
relConfig = relayconf.LoadConfig(redClient)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleInboxValidCreateAsAnnounceNoNote(t *testing.T) {
|
||||||
|
activity := mockActivity("Create-Article")
|
||||||
|
actor := mockActor("Person")
|
||||||
|
domain, _ := url.Parse(activity.Actor)
|
||||||
|
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
handleInbox(w, r, mockActivityDecoderProvider(&activity, &actor))
|
||||||
|
}))
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
redClient.HSet("relay:subscription:"+domain.Host, "inbox_url", "https://mastodon.test.yukimochi.io/inbox").Result()
|
||||||
|
redClient.HSet("relay:subscription:example.org", "inbox_url", "https://example.org/inbox").Result()
|
||||||
|
redClient.HSet("relay:config", "create_as_announce", "1").Result()
|
||||||
|
relConfig = relayconf.LoadConfig(redClient)
|
||||||
|
|
||||||
|
req, _ := http.NewRequest("POST", s.URL, nil)
|
||||||
|
client := new(http.Client)
|
||||||
|
r, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed - " + err.Error())
|
||||||
|
}
|
||||||
|
if r.StatusCode != 202 {
|
||||||
|
t.Fatalf("Failed - StatusCode is not 202")
|
||||||
|
}
|
||||||
|
redClient.Del("relay:subscription:" + domain.Host).Result()
|
||||||
|
redClient.Del("relay:subscription:example.org").Result()
|
||||||
|
redClient.HSet("relay:config", "create_as_announce", "0").Result()
|
||||||
|
relConfig = relayconf.LoadConfig(redClient)
|
||||||
|
}
|
||||||
|
|
||||||
func TestHandleInboxUnsubscriptionCreate(t *testing.T) {
|
func TestHandleInboxUnsubscriptionCreate(t *testing.T) {
|
||||||
activity := mockActivity("Create")
|
activity := mockActivity("Create")
|
||||||
actor := mockActor("Person")
|
actor := mockActor("Person")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user