summaryrefslogtreecommitdiff
path: root/internal/typeutils/asextractionutil.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/typeutils/asextractionutil.go')
-rw-r--r--internal/typeutils/asextractionutil.go216
1 files changed, 216 insertions, 0 deletions
diff --git a/internal/typeutils/asextractionutil.go b/internal/typeutils/asextractionutil.go
new file mode 100644
index 000000000..8d39be3ec
--- /dev/null
+++ b/internal/typeutils/asextractionutil.go
@@ -0,0 +1,216 @@
+/*
+ GoToSocial
+ Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
+
+ 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 typeutils
+
+import (
+ "crypto/rsa"
+ "crypto/x509"
+ "encoding/pem"
+ "errors"
+ "fmt"
+ "net/url"
+
+ "github.com/go-fed/activity/pub"
+)
+
+func extractPreferredUsername(i withPreferredUsername) (string, error) {
+ u := i.GetActivityStreamsPreferredUsername()
+ if u == nil || !u.IsXMLSchemaString() {
+ return "", errors.New("preferredUsername was not a string")
+ }
+ if u.GetXMLSchemaString() == "" {
+ return "", errors.New("preferredUsername was empty")
+ }
+ return u.GetXMLSchemaString(), nil
+}
+
+func extractName(i withDisplayName) (string, error) {
+ nameProp := i.GetActivityStreamsName()
+ if nameProp == nil {
+ return "", errors.New("activityStreamsName not found")
+ }
+
+ // take the first name string we can find
+ for nameIter := nameProp.Begin(); nameIter != nameProp.End(); nameIter = nameIter.Next() {
+ if nameIter.IsXMLSchemaString() && nameIter.GetXMLSchemaString() != "" {
+ return nameIter.GetXMLSchemaString(), nil
+ }
+ }
+
+ return "", errors.New("activityStreamsName not found")
+}
+
+// extractIconURL extracts a URL to a supported image file from something like:
+// "icon": {
+// "mediaType": "image/jpeg",
+// "type": "Image",
+// "url": "http://example.org/path/to/some/file.jpeg"
+// },
+func extractIconURL(i withIcon) (*url.URL, error) {
+ iconProp := i.GetActivityStreamsIcon()
+ if iconProp == nil {
+ return nil, errors.New("icon property was nil")
+ }
+
+ // icon can potentially contain multiple entries, so we iterate through all of them
+ // here in order to find the first one that meets these criteria:
+ // 1. is an image
+ // 2. has a URL so we can grab it
+ for iconIter := iconProp.Begin(); iconIter != iconProp.End(); iconIter = iconIter.Next() {
+ // 1. is an image
+ if !iconIter.IsActivityStreamsImage() {
+ continue
+ }
+ imageValue := iconIter.GetActivityStreamsImage()
+ if imageValue == nil {
+ continue
+ }
+
+ // 2. has a URL so we can grab it
+ url, err := extractURL(imageValue)
+ if err == nil && url != nil {
+ return url, nil
+ }
+ }
+ // if we get to this point we didn't find an icon meeting our criteria :'(
+ return nil, errors.New("could not extract valid image from icon")
+}
+
+// extractImageURL extracts a URL to a supported image file from something like:
+// "image": {
+// "mediaType": "image/jpeg",
+// "type": "Image",
+// "url": "http://example.org/path/to/some/file.jpeg"
+// },
+func extractImageURL(i withImage) (*url.URL, error) {
+ imageProp := i.GetActivityStreamsImage()
+ if imageProp == nil {
+ return nil, errors.New("icon property was nil")
+ }
+
+ // icon can potentially contain multiple entries, so we iterate through all of them
+ // here in order to find the first one that meets these criteria:
+ // 1. is an image
+ // 2. has a URL so we can grab it
+ for imageIter := imageProp.Begin(); imageIter != imageProp.End(); imageIter = imageIter.Next() {
+ // 1. is an image
+ if !imageIter.IsActivityStreamsImage() {
+ continue
+ }
+ imageValue := imageIter.GetActivityStreamsImage()
+ if imageValue == nil {
+ continue
+ }
+
+ // 2. has a URL so we can grab it
+ url, err := extractURL(imageValue)
+ if err == nil && url != nil {
+ return url, nil
+ }
+ }
+ // if we get to this point we didn't find an image meeting our criteria :'(
+ return nil, errors.New("could not extract valid image from image property")
+}
+
+func extractSummary(i withSummary) (string, error) {
+ summaryProp := i.GetActivityStreamsSummary()
+ if summaryProp == nil {
+ return "", errors.New("summary property was nil")
+ }
+
+ for summaryIter := summaryProp.Begin(); summaryIter != summaryProp.End(); summaryIter = summaryIter.Next() {
+ if summaryIter.IsXMLSchemaString() && summaryIter.GetXMLSchemaString() != "" {
+ return summaryIter.GetXMLSchemaString(), nil
+ }
+ }
+
+ return "", errors.New("could not extract summary")
+}
+
+func extractDiscoverable(i withDiscoverable) (bool, error) {
+ if i.GetTootDiscoverable() == nil {
+ return false, errors.New("discoverable was nil")
+ }
+ return i.GetTootDiscoverable().Get(), nil
+}
+
+func extractURL(i withURL) (*url.URL, error) {
+ urlProp := i.GetActivityStreamsUrl()
+ if urlProp == nil {
+ return nil, errors.New("url property was nil")
+ }
+
+ for urlIter := urlProp.Begin(); urlIter != urlProp.End(); urlIter = urlIter.Next() {
+ if urlIter.IsIRI() && urlIter.GetIRI() != nil {
+ return urlIter.GetIRI(), nil
+ }
+ }
+
+ return nil, errors.New("could not extract url")
+}
+
+func extractPublicKeyForOwner(i withPublicKey, forOwner *url.URL) (*rsa.PublicKey, *url.URL, error) {
+ publicKeyProp := i.GetW3IDSecurityV1PublicKey()
+ if publicKeyProp == nil {
+ return nil, nil, errors.New("public key property was nil")
+ }
+
+ for publicKeyIter := publicKeyProp.Begin(); publicKeyIter != publicKeyProp.End(); publicKeyIter = publicKeyIter.Next() {
+ pkey := publicKeyIter.Get()
+ if pkey == nil {
+ continue
+ }
+
+ pkeyID, err := pub.GetId(pkey)
+ if err != nil || pkeyID == nil {
+ continue
+ }
+
+ if pkey.GetW3IDSecurityV1Owner() == nil || pkey.GetW3IDSecurityV1Owner().Get() == nil || pkey.GetW3IDSecurityV1Owner().Get().String() != forOwner.String() {
+ continue
+ }
+
+ if pkey.GetW3IDSecurityV1PublicKeyPem() == nil {
+ continue
+ }
+
+ pkeyPem := pkey.GetW3IDSecurityV1PublicKeyPem().Get()
+ if pkeyPem == "" {
+ continue
+ }
+
+ block, _ := pem.Decode([]byte(pkeyPem))
+ if block == nil || block.Type != "PUBLIC KEY" {
+ return nil, nil, errors.New("could not decode publicKeyPem to PUBLIC KEY pem block type")
+ }
+
+ p, err := x509.ParsePKIXPublicKey(block.Bytes)
+ if err != nil {
+ return nil, nil, fmt.Errorf("could not parse public key from block bytes: %s", err)
+ }
+ if p == nil {
+ return nil, nil, errors.New("returned public key was empty")
+ }
+
+ if publicKey, ok := p.(*rsa.PublicKey); ok {
+ return publicKey, pkeyID, nil
+ }
+ }
+ return nil, nil, errors.New("couldn't find public key")
+}