Skip to content

Commit

Permalink
everything else
Browse files Browse the repository at this point in the history
  • Loading branch information
tsmethurst committed Jul 17, 2024
1 parent a311b74 commit 4d93796
Show file tree
Hide file tree
Showing 38 changed files with 3,218 additions and 297 deletions.
508 changes: 508 additions & 0 deletions docs/federation/posts.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ require (
github.com/spf13/cobra v1.8.1
github.com/spf13/viper v1.19.0
github.com/stretchr/testify v1.9.0
github.com/superseriousbusiness/activity v1.7.0-gts
github.com/superseriousbusiness/activity v1.8.0-gts
github.com/superseriousbusiness/httpsig v1.2.0-SSB
github.com/superseriousbusiness/oauth2/v4 v4.3.2-SSB.0.20230227143000-f4900831d6c8
github.com/tdewolff/minify/v2 v2.20.37
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -505,8 +505,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/superseriousbusiness/activity v1.7.0-gts h1:DsCvzksTWptn7JUDTFIIiJ7xkh0A22VZs5KI3q67p+4=
github.com/superseriousbusiness/activity v1.7.0-gts/go.mod h1:AZw0Xb4Oju8rmaJCZ21gc5CPg47MmNgyac+Hx5jo8VM=
github.com/superseriousbusiness/activity v1.8.0-gts h1:CMSN1eZUwNfIX1DFo4YxRCzSeT4jmGoIdakt/ZuDkQM=
github.com/superseriousbusiness/activity v1.8.0-gts/go.mod h1:AZw0Xb4Oju8rmaJCZ21gc5CPg47MmNgyac+Hx5jo8VM=
github.com/superseriousbusiness/httpsig v1.2.0-SSB h1:BinBGKbf2LSuVT5+MuH0XynHN9f0XVshx2CTDtkaWj0=
github.com/superseriousbusiness/httpsig v1.2.0-SSB/go.mod h1:+rxfATjFaDoDIVaJOTSP0gj6UrbicaYPEptvCLC9F28=
github.com/superseriousbusiness/oauth2/v4 v4.3.2-SSB.0.20230227143000-f4900831d6c8 h1:nTIhuP157oOFcscuoK1kCme1xTeGIzztSw70lX9NrDQ=
Expand Down
63 changes: 63 additions & 0 deletions internal/ap/ap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/superseriousbusiness/activity/streams"
"github.com/superseriousbusiness/activity/streams/vocab"
"github.com/superseriousbusiness/gotosocial/internal/ap"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/testrig"
)

Expand Down Expand Up @@ -103,6 +104,66 @@ func noteWithMentions1() vocab.ActivityStreamsNote {

note.SetActivityStreamsContent(content)

policy := streams.NewGoToSocialInteractionPolicy()

// Set canLike.
canLike := streams.NewGoToSocialCanLike()

// Anyone can like.
canLikeAlwaysProp := streams.NewGoToSocialAlwaysProperty()
canLikeAlwaysProp.AppendIRI(testrig.URLMustParse(pub.PublicActivityPubIRI))
canLike.SetGoToSocialAlways(canLikeAlwaysProp)

// Empty approvalRequired.
canLikeApprovalRequiredProp := streams.NewGoToSocialApprovalRequiredProperty()
canLike.SetGoToSocialApprovalRequired(canLikeApprovalRequiredProp)

// Set canLike on the policy.
canLikeProp := streams.NewGoToSocialCanLikeProperty()
canLikeProp.AppendGoToSocialCanLike(canLike)
policy.SetGoToSocialCanLike(canLikeProp)

// Build canReply.
canReply := streams.NewGoToSocialCanReply()

// Anyone can reply.
canReplyAlwaysProp := streams.NewGoToSocialAlwaysProperty()
canReplyAlwaysProp.AppendIRI(testrig.URLMustParse(pub.PublicActivityPubIRI))
canReply.SetGoToSocialAlways(canReplyAlwaysProp)

// Set empty approvalRequired.
canReplyApprovalRequiredProp := streams.NewGoToSocialApprovalRequiredProperty()
canReply.SetGoToSocialApprovalRequired(canReplyApprovalRequiredProp)

// Set canReply on the policy.
canReplyProp := streams.NewGoToSocialCanReplyProperty()
canReplyProp.AppendGoToSocialCanReply(canReply)
policy.SetGoToSocialCanReply(canReplyProp)

// Build canAnnounce.
canAnnounce := streams.NewGoToSocialCanAnnounce()

// Only f0x and dumpsterqueer can announce.
canAnnounceAlwaysProp := streams.NewGoToSocialAlwaysProperty()
canAnnounceAlwaysProp.AppendIRI(testrig.URLMustParse("https://gts.superseriousbusiness.org/users/dumpsterqueer"))
canAnnounceAlwaysProp.AppendIRI(testrig.URLMustParse("https://gts.superseriousbusiness.org/users/f0x"))
canAnnounce.SetGoToSocialAlways(canAnnounceAlwaysProp)

// Public requires approval to announce.
canAnnounceApprovalRequiredProp := streams.NewGoToSocialApprovalRequiredProperty()
canAnnounceApprovalRequiredProp.AppendIRI(testrig.URLMustParse(pub.PublicActivityPubIRI))
canAnnounce.SetGoToSocialApprovalRequired(canAnnounceApprovalRequiredProp)

// Set canAnnounce on the policy.
canAnnounceProp := streams.NewGoToSocialCanAnnounceProperty()
canAnnounceProp.AppendGoToSocialCanAnnounce(canAnnounce)
policy.SetGoToSocialCanAnnounce(canAnnounceProp)

// Set the policy on the note.
policyProp := streams.NewGoToSocialInteractionPolicyProperty()
policyProp.AppendGoToSocialInteractionPolicy(policy)
note.SetGoToSocialInteractionPolicy(policyProp)

return note
}

Expand Down Expand Up @@ -296,6 +357,7 @@ type APTestSuite struct {
addressable3 ap.Addressable
addressable4 vocab.ActivityStreamsAnnounce
addressable5 ap.Addressable
testAccounts map[string]*gtsmodel.Account
}

func (suite *APTestSuite) jsonToType(rawJson string) (vocab.Type, map[string]interface{}) {
Expand Down Expand Up @@ -336,4 +398,5 @@ func (suite *APTestSuite) SetupTest() {
suite.addressable3 = addressable3()
suite.addressable4 = addressable4()
suite.addressable5 = addressable5()
suite.testAccounts = testrig.NewTestAccounts()
}
131 changes: 131 additions & 0 deletions internal/ap/extract.go
Original file line number Diff line number Diff line change
Expand Up @@ -1057,6 +1057,137 @@ func ExtractVisibility(addressable Addressable, actorFollowersURI string) (gtsmo
return visibility, nil
}

// ExtractInteractionPolicy extracts a *gtsmodel.InteractionPolicy
// from the given Statusable created by by the given *gtsmodel.Account.
//
// Will be nil (default policy) for Statusables that have no policy
// set on them, or have a null policy. In such a case, the caller
// should assume the default policy for the status's visibility level.
func ExtractInteractionPolicy(
statusable Statusable,
owner *gtsmodel.Account,
) *gtsmodel.InteractionPolicy {
policyProp := statusable.GetGoToSocialInteractionPolicy()
if policyProp == nil || policyProp.Len() != 1 {
return nil
}

policyPropIter := policyProp.At(0)
if !policyPropIter.IsGoToSocialInteractionPolicy() {
return nil
}

policy := policyPropIter.Get()
if policy == nil {
return nil
}

return &gtsmodel.InteractionPolicy{
CanLike: extractCanLike(policy.GetGoToSocialCanLike(), owner),
CanReply: extractCanReply(policy.GetGoToSocialCanReply(), owner),
CanAnnounce: extractCanAnnounce(policy.GetGoToSocialCanAnnounce(), owner),
}
}

func extractCanLike(
prop vocab.GoToSocialCanLikeProperty,
owner *gtsmodel.Account,
) gtsmodel.PolicyRules {
if prop == nil || prop.Len() != 1 {
return gtsmodel.PolicyRules{}
}

propIter := prop.At(0)
if !propIter.IsGoToSocialCanLike() {
return gtsmodel.PolicyRules{}
}

withRules := propIter.Get()
if withRules == nil {
return gtsmodel.PolicyRules{}
}

return gtsmodel.PolicyRules{
Always: extractPolicyValues(withRules.GetGoToSocialAlways(), owner),
WithApproval: extractPolicyValues(withRules.GetGoToSocialApprovalRequired(), owner),
}
}

func extractCanReply(
prop vocab.GoToSocialCanReplyProperty,
owner *gtsmodel.Account,
) gtsmodel.PolicyRules {
if prop == nil || prop.Len() != 1 {
return gtsmodel.PolicyRules{}
}

propIter := prop.At(0)
if !propIter.IsGoToSocialCanReply() {
return gtsmodel.PolicyRules{}
}

withRules := propIter.Get()
if withRules == nil {
return gtsmodel.PolicyRules{}
}

return gtsmodel.PolicyRules{
Always: extractPolicyValues(withRules.GetGoToSocialAlways(), owner),
WithApproval: extractPolicyValues(withRules.GetGoToSocialApprovalRequired(), owner),
}
}

func extractCanAnnounce(
prop vocab.GoToSocialCanAnnounceProperty,
owner *gtsmodel.Account,
) gtsmodel.PolicyRules {
if prop == nil || prop.Len() != 1 {
return gtsmodel.PolicyRules{}
}

propIter := prop.At(0)
if !propIter.IsGoToSocialCanAnnounce() {
return gtsmodel.PolicyRules{}
}

withRules := propIter.Get()
if withRules == nil {
return gtsmodel.PolicyRules{}
}

return gtsmodel.PolicyRules{
Always: extractPolicyValues(withRules.GetGoToSocialAlways(), owner),
WithApproval: extractPolicyValues(withRules.GetGoToSocialApprovalRequired(), owner),
}
}

func extractPolicyValues[T WithIRI](
prop Property[T],
owner *gtsmodel.Account,
) gtsmodel.PolicyValues {
iris := getIRIs(prop)
PolicyValues := make(gtsmodel.PolicyValues, 0, len(iris))

for _, iri := range iris {
switch iriStr := iri.String(); iriStr {
case pub.PublicActivityPubIRI:
PolicyValues = append(PolicyValues, gtsmodel.PolicyValuePublic)
case owner.FollowersURI:
PolicyValues = append(PolicyValues, gtsmodel.PolicyValueFollowers)
case owner.FollowingURI:
PolicyValues = append(PolicyValues, gtsmodel.PolicyValueFollowers)
case owner.URI:
PolicyValues = append(PolicyValues, gtsmodel.PolicyValueAuthor)
default:
if iri.Scheme == "http" || iri.Scheme == "https" {
PolicyValues = append(PolicyValues, gtsmodel.PolicyValue(iriStr))
}
}
}

return PolicyValues
}

// ExtractSensitive extracts whether or not an item should
// be marked as sensitive according to its ActivityStreams
// sensitive property.
Expand Down
137 changes: 137 additions & 0 deletions internal/ap/extractpolicy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// GoToSocial
// Copyright (C) GoToSocial Authors [email protected]
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

package ap_test

import (
"bytes"
"context"
"io"
"testing"

"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/ap"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
)

type ExtractPolicyTestSuite struct {
APTestSuite
}

func (suite *ExtractPolicyTestSuite) TestExtractPolicy() {
rawNote := `{
"@context": [
"https://gotosocial.org/ns",
"https://www.w3.org/ns/activitystreams"
],
"content": "hey @f0x and @dumpsterqueer",
"contentMap": {
"en": "hey @f0x and @dumpsterqueer",
"fr": "bonjour @f0x et @dumpsterqueer"
},
"interactionPolicy": {
"canLike": {
"always": [
"https://www.w3.org/ns/activitystreams#Public"
],
"approvalRequired": []
},
"canReply": {
"always": [
"http://localhost:8080/users/the_mighty_zork",
"http://localhost:8080/users/the_mighty_zork/followers",
"https://gts.superseriousbusiness.org/users/dumpsterqueer",
"https://gts.superseriousbusiness.org/users/f0x"
],
"approvalRequired": [
"https://www.w3.org/ns/activitystreams#Public"
]
},
"canAnnounce": {
"always": [
"http://localhost:8080/users/the_mighty_zork"
],
"approvalRequired": [
"https://www.w3.org/ns/activitystreams#Public"
]
}
},
"tag": [
{
"href": "https://gts.superseriousbusiness.org/users/dumpsterqueer",
"name": "@[email protected]",
"type": "Mention"
},
{
"href": "https://gts.superseriousbusiness.org/users/f0x",
"name": "@[email protected]",
"type": "Mention"
}
],
"type": "Note"
}`

statusable, err := ap.ResolveStatusable(
context.Background(),
io.NopCloser(
bytes.NewBufferString(rawNote),
),
)
if err != nil {
suite.FailNow(err.Error())
}

policy := ap.ExtractInteractionPolicy(
statusable,
// Zork didn't actually create
// this status but nevermind.
suite.testAccounts["local_account_1"],
)

expectedPolicy := &gtsmodel.InteractionPolicy{
CanLike: gtsmodel.PolicyRules{
Always: gtsmodel.PolicyValues{
gtsmodel.PolicyValuePublic,
},
WithApproval: gtsmodel.PolicyValues{},
},
CanReply: gtsmodel.PolicyRules{
Always: gtsmodel.PolicyValues{
gtsmodel.PolicyValueAuthor,
gtsmodel.PolicyValueFollowers,
"https://gts.superseriousbusiness.org/users/dumpsterqueer",
"https://gts.superseriousbusiness.org/users/f0x",
},
WithApproval: gtsmodel.PolicyValues{
gtsmodel.PolicyValuePublic,
},
},
CanAnnounce: gtsmodel.PolicyRules{
Always: gtsmodel.PolicyValues{
gtsmodel.PolicyValueAuthor,
},
WithApproval: gtsmodel.PolicyValues{
gtsmodel.PolicyValuePublic,
},
},
}
suite.EqualValues(expectedPolicy, policy)
}

func TestExtractPolicyTestSuite(t *testing.T) {
suite.Run(t, &ExtractPolicyTestSuite{})
}
Loading

0 comments on commit 4d93796

Please sign in to comment.