mirror of
https://github.com/superseriousbusiness/gotosocial
synced 2025-06-05 21:59:39 +02:00
216
internal/typeutils/asextractionutil.go
Normal file
216
internal/typeutils/asextractionutil.go
Normal file
@@ -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")
|
||||
}
|
Reference in New Issue
Block a user