| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | /* | 
					
						
							|  |  |  |    GoToSocial | 
					
						
							| 
									
										
										
										
											2023-01-05 12:43:00 +01:00
										 |  |  |    Copyright (C) 2021-2023 GoToSocial Authors admin@gotosocial.org | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |    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/>. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | // Package ap contains models and utilities for working with activitypub/activitystreams representations. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // It is built on top of go-fed/activity. | 
					
						
							|  |  |  | package ap | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2022-11-30 23:13:13 +01:00
										 |  |  | 	"crypto" | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 	"crypto/rsa" | 
					
						
							|  |  |  | 	"crypto/x509" | 
					
						
							|  |  |  | 	"encoding/pem" | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"net/url" | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	"strings" | 
					
						
							|  |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-13 17:29:43 +01:00
										 |  |  | 	"github.com/superseriousbusiness/activity/pub" | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | 
					
						
							|  |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/util" | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | // ExtractPreferredUsername returns a string representation of an interface's preferredUsername property. | 
					
						
							|  |  |  | func ExtractPreferredUsername(i WithPreferredUsername) (string, error) { | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 	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 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-02 16:41:02 +01:00
										 |  |  | // ExtractName returns a string representation of an interface's name property, | 
					
						
							|  |  |  | // or an empty string if this is not found. | 
					
						
							|  |  |  | func ExtractName(i WithName) string { | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 	nameProp := i.GetActivityStreamsName() | 
					
						
							|  |  |  | 	if nameProp == nil { | 
					
						
							| 
									
										
										
										
											2023-02-02 16:41:02 +01:00
										 |  |  | 		return "" | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// take the first name string we can find | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	for iter := nameProp.Begin(); iter != nameProp.End(); iter = iter.Next() { | 
					
						
							|  |  |  | 		if iter.IsXMLSchemaString() && iter.GetXMLSchemaString() != "" { | 
					
						
							| 
									
										
										
										
											2023-02-02 16:41:02 +01:00
										 |  |  | 			return iter.GetXMLSchemaString() | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-02 16:41:02 +01:00
										 |  |  | 	return "" | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | // ExtractInReplyToURI extracts the inReplyToURI property (if present) from an interface. | 
					
						
							|  |  |  | func ExtractInReplyToURI(i WithInReplyTo) *url.URL { | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	inReplyToProp := i.GetActivityStreamsInReplyTo() | 
					
						
							| 
									
										
										
										
											2021-05-23 18:07:04 +02:00
										 |  |  | 	if inReplyToProp == nil { | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | 		// the property just wasn't set | 
					
						
							|  |  |  | 		return nil | 
					
						
							| 
									
										
										
										
											2021-05-23 18:07:04 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	for iter := inReplyToProp.Begin(); iter != inReplyToProp.End(); iter = iter.Next() { | 
					
						
							|  |  |  | 		if iter.IsIRI() { | 
					
						
							|  |  |  | 			if iter.GetIRI() != nil { | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | 				return iter.GetIRI() | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | 	// couldn't find a URI | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ExtractURLItems extracts a slice of URLs from a property that has withItems. | 
					
						
							|  |  |  | func ExtractURLItems(i WithItems) []*url.URL { | 
					
						
							|  |  |  | 	urls := []*url.URL{} | 
					
						
							|  |  |  | 	items := i.GetActivityStreamsItems() | 
					
						
							|  |  |  | 	if items == nil || items.Len() == 0 { | 
					
						
							|  |  |  | 		return urls | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for iter := items.Begin(); iter != items.End(); iter = iter.Next() { | 
					
						
							|  |  |  | 		if iter.IsIRI() { | 
					
						
							|  |  |  | 			urls = append(urls, iter.GetIRI()) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return urls | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | // ExtractTos returns a list of URIs that the activity addresses as To. | 
					
						
							|  |  |  | func ExtractTos(i WithTo) ([]*url.URL, error) { | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	to := []*url.URL{} | 
					
						
							|  |  |  | 	toProp := i.GetActivityStreamsTo() | 
					
						
							| 
									
										
										
										
											2021-05-23 18:07:04 +02:00
										 |  |  | 	if toProp == nil { | 
					
						
							|  |  |  | 		return nil, errors.New("toProp was nil") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	for iter := toProp.Begin(); iter != toProp.End(); iter = iter.Next() { | 
					
						
							|  |  |  | 		if iter.IsIRI() { | 
					
						
							|  |  |  | 			if iter.GetIRI() != nil { | 
					
						
							|  |  |  | 				to = append(to, iter.GetIRI()) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return to, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | // ExtractCCs returns a list of URIs that the activity addresses as CC. | 
					
						
							|  |  |  | func ExtractCCs(i WithCC) ([]*url.URL, error) { | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	cc := []*url.URL{} | 
					
						
							|  |  |  | 	ccProp := i.GetActivityStreamsCc() | 
					
						
							| 
									
										
										
										
											2021-05-23 18:07:04 +02:00
										 |  |  | 	if ccProp == nil { | 
					
						
							|  |  |  | 		return cc, nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	for iter := ccProp.Begin(); iter != ccProp.End(); iter = iter.Next() { | 
					
						
							|  |  |  | 		if iter.IsIRI() { | 
					
						
							|  |  |  | 			if iter.GetIRI() != nil { | 
					
						
							|  |  |  | 				cc = append(cc, iter.GetIRI()) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return cc, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | // ExtractAttributedTo returns the URL of the actor that the withAttributedTo is attributed to. | 
					
						
							|  |  |  | func ExtractAttributedTo(i WithAttributedTo) (*url.URL, error) { | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	attributedToProp := i.GetActivityStreamsAttributedTo() | 
					
						
							| 
									
										
										
										
											2021-05-23 18:07:04 +02:00
										 |  |  | 	if attributedToProp == nil { | 
					
						
							|  |  |  | 		return nil, errors.New("attributedToProp was nil") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	for iter := attributedToProp.Begin(); iter != attributedToProp.End(); iter = iter.Next() { | 
					
						
							|  |  |  | 		if iter.IsIRI() { | 
					
						
							|  |  |  | 			if iter.GetIRI() != nil { | 
					
						
							|  |  |  | 				return iter.GetIRI(), nil | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil, errors.New("couldn't find iri for attributed to") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | // ExtractPublished extracts the publication time of an activity. | 
					
						
							|  |  |  | func ExtractPublished(i WithPublished) (time.Time, error) { | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	publishedProp := i.GetActivityStreamsPublished() | 
					
						
							|  |  |  | 	if publishedProp == nil { | 
					
						
							|  |  |  | 		return time.Time{}, errors.New("published prop was nil") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if !publishedProp.IsXMLSchemaDateTime() { | 
					
						
							|  |  |  | 		return time.Time{}, errors.New("published prop was not date time") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t := publishedProp.Get() | 
					
						
							|  |  |  | 	if t.IsZero() { | 
					
						
							|  |  |  | 		return time.Time{}, errors.New("published time was zero") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return t, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | // ExtractIconURL extracts a URL to a supported image file from something like: | 
					
						
							| 
									
										
										
										
											2022-09-28 18:30:40 +01:00
										 |  |  | // | 
					
						
							|  |  |  | //	"icon": { | 
					
						
							|  |  |  | //	  "mediaType": "image/jpeg", | 
					
						
							|  |  |  | //	  "type": "Image", | 
					
						
							|  |  |  | //	  "url": "http://example.org/path/to/some/file.jpeg" | 
					
						
							|  |  |  | //	}, | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | func ExtractIconURL(i WithIcon) (*url.URL, error) { | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 	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 | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	for iter := iconProp.Begin(); iter != iconProp.End(); iter = iter.Next() { | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 		// 1. is an image | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 		if !iter.IsActivityStreamsImage() { | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 		imageValue := iter.GetActivityStreamsImage() | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 		if imageValue == nil { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// 2. has a URL so we can grab it | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | 		url, err := ExtractURL(imageValue) | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 		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") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | // ExtractImageURL extracts a URL to a supported image file from something like: | 
					
						
							| 
									
										
										
										
											2022-09-28 18:30:40 +01:00
										 |  |  | // | 
					
						
							|  |  |  | //	"image": { | 
					
						
							|  |  |  | //	  "mediaType": "image/jpeg", | 
					
						
							|  |  |  | //	  "type": "Image", | 
					
						
							|  |  |  | //	  "url": "http://example.org/path/to/some/file.jpeg" | 
					
						
							|  |  |  | //	}, | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | func ExtractImageURL(i WithImage) (*url.URL, error) { | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 	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 | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	for iter := imageProp.Begin(); iter != imageProp.End(); iter = iter.Next() { | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 		// 1. is an image | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 		if !iter.IsActivityStreamsImage() { | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 		imageValue := iter.GetActivityStreamsImage() | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 		if imageValue == nil { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// 2. has a URL so we can grab it | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | 		url, err := ExtractURL(imageValue) | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 		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") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | // ExtractSummary extracts the summary/content warning of an interface. | 
					
						
							| 
									
										
										
										
											2023-02-02 16:41:02 +01:00
										 |  |  | // Will return an empty string if no summary was present. | 
					
						
							|  |  |  | func ExtractSummary(i WithSummary) string { | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 	summaryProp := i.GetActivityStreamsSummary() | 
					
						
							| 
									
										
										
										
											2021-08-29 12:03:08 +02:00
										 |  |  | 	if summaryProp == nil || summaryProp.Len() == 0 { | 
					
						
							|  |  |  | 		// no summary to speak of | 
					
						
							| 
									
										
										
										
											2023-02-02 16:41:02 +01:00
										 |  |  | 		return "" | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	for iter := summaryProp.Begin(); iter != summaryProp.End(); iter = iter.Next() { | 
					
						
							| 
									
										
										
										
											2022-04-26 10:47:21 +02:00
										 |  |  | 		switch { | 
					
						
							|  |  |  | 		case iter.IsIRI(): | 
					
						
							| 
									
										
										
										
											2023-02-02 16:41:02 +01:00
										 |  |  | 			return iter.GetIRI().String() | 
					
						
							| 
									
										
										
										
											2022-04-26 10:47:21 +02:00
										 |  |  | 		case iter.IsXMLSchemaString(): | 
					
						
							| 
									
										
										
										
											2023-02-02 16:41:02 +01:00
										 |  |  | 			return iter.GetXMLSchemaString() | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-02 16:41:02 +01:00
										 |  |  | 	return "" | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | // ExtractDiscoverable extracts the Discoverable boolean of an interface. | 
					
						
							|  |  |  | func ExtractDiscoverable(i WithDiscoverable) (bool, error) { | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 	if i.GetTootDiscoverable() == nil { | 
					
						
							|  |  |  | 		return false, errors.New("discoverable was nil") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return i.GetTootDiscoverable().Get(), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | // ExtractURL extracts the URL property of an interface. | 
					
						
							|  |  |  | func ExtractURL(i WithURL) (*url.URL, error) { | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 	urlProp := i.GetActivityStreamsUrl() | 
					
						
							|  |  |  | 	if urlProp == nil { | 
					
						
							|  |  |  | 		return nil, errors.New("url property was nil") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	for iter := urlProp.Begin(); iter != urlProp.End(); iter = iter.Next() { | 
					
						
							|  |  |  | 		if iter.IsIRI() && iter.GetIRI() != nil { | 
					
						
							|  |  |  | 			return iter.GetIRI(), nil | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil, errors.New("could not extract url") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | // ExtractPublicKeyForOwner extracts the public key from an interface, as long as it belongs to the specified owner. | 
					
						
							|  |  |  | // It will return the public key itself, the id/URL of the public key, or an error if something goes wrong. | 
					
						
							|  |  |  | func ExtractPublicKeyForOwner(i WithPublicKey, forOwner *url.URL) (*rsa.PublicKey, *url.URL, error) { | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 	publicKeyProp := i.GetW3IDSecurityV1PublicKey() | 
					
						
							|  |  |  | 	if publicKeyProp == nil { | 
					
						
							|  |  |  | 		return nil, nil, errors.New("public key property was nil") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	for iter := publicKeyProp.Begin(); iter != publicKeyProp.End(); iter = iter.Next() { | 
					
						
							|  |  |  | 		pkey := iter.Get() | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 		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)) | 
					
						
							| 
									
										
										
										
											2022-11-30 23:13:13 +01:00
										 |  |  | 		if block == nil { | 
					
						
							|  |  |  | 			return nil, nil, errors.New("could not decode publicKeyPem: no PEM data") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		var p crypto.PublicKey | 
					
						
							|  |  |  | 		switch block.Type { | 
					
						
							|  |  |  | 		case "PUBLIC KEY": | 
					
						
							|  |  |  | 			p, err = x509.ParsePKIXPublicKey(block.Bytes) | 
					
						
							|  |  |  | 		case "RSA PUBLIC KEY": | 
					
						
							|  |  |  | 			p, err = x509.ParsePKCS1PublicKey(block.Bytes) | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			return nil, nil, fmt.Errorf("could not parse public key: unknown block type: %q", block.Type) | 
					
						
							| 
									
										
										
										
											2021-05-08 14:25:55 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		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") | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-23 17:12:46 +02:00
										 |  |  | // ExtractContent returns a string representation of the interface's Content property, | 
					
						
							|  |  |  | // or an empty string if no Content is found. | 
					
						
							|  |  |  | func ExtractContent(i WithContent) string { | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	contentProperty := i.GetActivityStreamsContent() | 
					
						
							|  |  |  | 	if contentProperty == nil { | 
					
						
							| 
									
										
										
										
											2022-05-23 17:12:46 +02:00
										 |  |  | 		return "" | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-05-23 17:12:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	for iter := contentProperty.Begin(); iter != contentProperty.End(); iter = iter.Next() { | 
					
						
							| 
									
										
										
										
											2022-05-23 17:12:46 +02:00
										 |  |  | 		if iter.IsXMLSchemaString() { | 
					
						
							|  |  |  | 			return iter.GetXMLSchemaString() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if iter.IsIRI() && iter.GetIRI() != nil { | 
					
						
							|  |  |  | 			return iter.GetIRI().String() | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-05-23 17:12:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return "" | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | // ExtractAttachment returns a gts model of an attachment from an attachmentable interface. | 
					
						
							|  |  |  | func ExtractAttachment(i Attachmentable) (*gtsmodel.MediaAttachment, error) { | 
					
						
							| 
									
										
										
										
											2023-02-02 16:41:02 +01:00
										 |  |  | 	attachment := >smodel.MediaAttachment{} | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | 	attachmentURL, err := ExtractURL(i) | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	attachment.RemoteURL = attachmentURL.String() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mediaType := i.GetActivityStreamsMediaType() | 
					
						
							| 
									
										
										
										
											2023-02-02 16:41:02 +01:00
										 |  |  | 	if mediaType != nil { | 
					
						
							|  |  |  | 		attachment.File.ContentType = mediaType.Get() | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	attachment.Type = gtsmodel.FileTypeImage | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-02 16:41:02 +01:00
										 |  |  | 	attachment.Description = ExtractName(i) | 
					
						
							| 
									
										
										
										
											2022-01-09 18:41:22 +01:00
										 |  |  | 	attachment.Blurhash = ExtractBlurhash(i) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-17 19:06:58 +02:00
										 |  |  | 	attachment.Processing = gtsmodel.ProcessingStatusReceived | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return attachment, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-09 18:41:22 +01:00
										 |  |  | // ExtractBlurhash extracts the blurhash value (if present) from a WithBlurhash interface. | 
					
						
							|  |  |  | func ExtractBlurhash(i WithBlurhash) string { | 
					
						
							|  |  |  | 	if i.GetTootBlurhash() == nil { | 
					
						
							|  |  |  | 		return "" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return i.GetTootBlurhash().Get() | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | // ExtractHashtags returns a slice of tags on the interface. | 
					
						
							|  |  |  | func ExtractHashtags(i WithTag) ([]*gtsmodel.Tag, error) { | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	tags := []*gtsmodel.Tag{} | 
					
						
							|  |  |  | 	tagsProp := i.GetActivityStreamsTag() | 
					
						
							| 
									
										
										
										
											2021-05-23 18:07:04 +02:00
										 |  |  | 	if tagsProp == nil { | 
					
						
							|  |  |  | 		return tags, nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	for iter := tagsProp.Begin(); iter != tagsProp.End(); iter = iter.Next() { | 
					
						
							|  |  |  | 		t := iter.GetType() | 
					
						
							|  |  |  | 		if t == nil { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if t.GetTypeName() != "Hashtag" { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		hashtaggable, ok := t.(Hashtaggable) | 
					
						
							|  |  |  | 		if !ok { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | 		tag, err := ExtractHashtag(hashtaggable) | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		tags = append(tags, tag) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return tags, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | // ExtractHashtag returns a gtsmodel tag from a hashtaggable. | 
					
						
							|  |  |  | func ExtractHashtag(i Hashtaggable) (*gtsmodel.Tag, error) { | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	tag := >smodel.Tag{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	hrefProp := i.GetActivityStreamsHref() | 
					
						
							|  |  |  | 	if hrefProp == nil || !hrefProp.IsIRI() { | 
					
						
							|  |  |  | 		return nil, errors.New("no href prop") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	tag.URL = hrefProp.GetIRI().String() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-02 16:41:02 +01:00
										 |  |  | 	name := ExtractName(i) | 
					
						
							|  |  |  | 	if name == "" { | 
					
						
							|  |  |  | 		return nil, errors.New("name prop empty") | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-02-02 16:41:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	tag.Name = strings.TrimPrefix(name, "#") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return tag, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | // ExtractEmojis returns a slice of emojis on the interface. | 
					
						
							|  |  |  | func ExtractEmojis(i WithTag) ([]*gtsmodel.Emoji, error) { | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	emojis := []*gtsmodel.Emoji{} | 
					
						
							|  |  |  | 	tagsProp := i.GetActivityStreamsTag() | 
					
						
							| 
									
										
										
										
											2021-05-23 18:07:04 +02:00
										 |  |  | 	if tagsProp == nil { | 
					
						
							|  |  |  | 		return emojis, nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	for iter := tagsProp.Begin(); iter != tagsProp.End(); iter = iter.Next() { | 
					
						
							|  |  |  | 		t := iter.GetType() | 
					
						
							|  |  |  | 		if t == nil { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if t.GetTypeName() != "Emoji" { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		emojiable, ok := t.(Emojiable) | 
					
						
							|  |  |  | 		if !ok { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | 		emoji, err := ExtractEmoji(emojiable) | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		emojis = append(emojis, emoji) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return emojis, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | // ExtractEmoji ... | 
					
						
							|  |  |  | func ExtractEmoji(i Emojiable) (*gtsmodel.Emoji, error) { | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	emoji := >smodel.Emoji{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	idProp := i.GetJSONLDId() | 
					
						
							|  |  |  | 	if idProp == nil || !idProp.IsIRI() { | 
					
						
							|  |  |  | 		return nil, errors.New("no id for emoji") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	uri := idProp.GetIRI() | 
					
						
							|  |  |  | 	emoji.URI = uri.String() | 
					
						
							|  |  |  | 	emoji.Domain = uri.Host | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-02 16:41:02 +01:00
										 |  |  | 	name := ExtractName(i) | 
					
						
							|  |  |  | 	if name == "" { | 
					
						
							|  |  |  | 		return nil, errors.New("name prop empty") | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	emoji.Shortcode = strings.Trim(name, ":") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if i.GetActivityStreamsIcon() == nil { | 
					
						
							|  |  |  | 		return nil, errors.New("no icon for emoji") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | 	imageURL, err := ExtractIconURL(i) | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, errors.New("no url for emoji image") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	emoji.ImageRemoteURL = imageURL.String() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-15 12:35:05 +02:00
										 |  |  | 	// assume false for both to begin | 
					
						
							|  |  |  | 	emoji.Disabled = new(bool) | 
					
						
							|  |  |  | 	emoji.VisibleInPicker = new(bool) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-13 15:16:24 +02:00
										 |  |  | 	updatedProp := i.GetActivityStreamsUpdated() | 
					
						
							|  |  |  | 	if updatedProp != nil && updatedProp.IsXMLSchemaDateTime() { | 
					
						
							|  |  |  | 		emoji.UpdatedAt = updatedProp.Get() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	return emoji, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | // ExtractMentions extracts a slice of gtsmodel Mentions from a WithTag interface. | 
					
						
							|  |  |  | func ExtractMentions(i WithTag) ([]*gtsmodel.Mention, error) { | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	mentions := []*gtsmodel.Mention{} | 
					
						
							|  |  |  | 	tagsProp := i.GetActivityStreamsTag() | 
					
						
							| 
									
										
										
										
											2021-05-23 18:07:04 +02:00
										 |  |  | 	if tagsProp == nil { | 
					
						
							|  |  |  | 		return mentions, nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	for iter := tagsProp.Begin(); iter != tagsProp.End(); iter = iter.Next() { | 
					
						
							|  |  |  | 		t := iter.GetType() | 
					
						
							|  |  |  | 		if t == nil { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if t.GetTypeName() != "Mention" { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		mentionable, ok := t.(Mentionable) | 
					
						
							|  |  |  | 		if !ok { | 
					
						
							| 
									
										
										
										
											2021-08-29 12:03:08 +02:00
										 |  |  | 			return nil, errors.New("mention was not convertable to ap.Mentionable") | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | 		mention, err := ExtractMention(mentionable) | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2021-08-29 12:03:08 +02:00
										 |  |  | 			return nil, err | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		mentions = append(mentions, mention) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return mentions, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | // ExtractMention extracts a gts model mention from a Mentionable. | 
					
						
							|  |  |  | func ExtractMention(i Mentionable) (*gtsmodel.Mention, error) { | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	mention := >smodel.Mention{} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-02 16:41:02 +01:00
										 |  |  | 	mentionString := ExtractName(i) | 
					
						
							|  |  |  | 	if mentionString == "" { | 
					
						
							|  |  |  | 		return nil, errors.New("name prop empty") | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// just make sure the mention string is valid so we can handle it properly later on... | 
					
						
							| 
									
										
										
										
											2023-02-02 16:41:02 +01:00
										 |  |  | 	if _, _, err := util.ExtractNamestringParts(mentionString); err != nil { | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	mention.NameString = mentionString | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// the href prop should be the AP URI of a user we know, eg https://example.org/users/whatever_user | 
					
						
							|  |  |  | 	hrefProp := i.GetActivityStreamsHref() | 
					
						
							|  |  |  | 	if hrefProp == nil || !hrefProp.IsIRI() { | 
					
						
							|  |  |  | 		return nil, errors.New("no href prop") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-08-20 12:26:56 +02:00
										 |  |  | 	mention.TargetAccountURI = hrefProp.GetIRI().String() | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	return mention, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | // ExtractActor extracts the actor ID/IRI from an interface WithActor. | 
					
						
							|  |  |  | func ExtractActor(i WithActor) (*url.URL, error) { | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	actorProp := i.GetActivityStreamsActor() | 
					
						
							|  |  |  | 	if actorProp == nil { | 
					
						
							|  |  |  | 		return nil, errors.New("actor property was nil") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for iter := actorProp.Begin(); iter != actorProp.End(); iter = iter.Next() { | 
					
						
							|  |  |  | 		if iter.IsIRI() && iter.GetIRI() != nil { | 
					
						
							|  |  |  | 			return iter.GetIRI(), nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil, errors.New("no iri found for actor prop") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-27 14:48:11 +01:00
										 |  |  | // ExtractObject extracts the first URL object from a WithObject interface. | 
					
						
							| 
									
										
										
										
											2021-08-10 13:32:39 +02:00
										 |  |  | func ExtractObject(i WithObject) (*url.URL, error) { | 
					
						
							| 
									
										
										
										
											2021-05-15 11:58:11 +02:00
										 |  |  | 	objectProp := i.GetActivityStreamsObject() | 
					
						
							|  |  |  | 	if objectProp == nil { | 
					
						
							|  |  |  | 		return nil, errors.New("object property was nil") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for iter := objectProp.Begin(); iter != objectProp.End(); iter = iter.Next() { | 
					
						
							|  |  |  | 		if iter.IsIRI() && iter.GetIRI() != nil { | 
					
						
							|  |  |  | 			return iter.GetIRI(), nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil, errors.New("no iri found for object prop") | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-10-06 18:18:02 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-25 11:12:27 +01:00
										 |  |  | // ExtractObjects extracts a slice of URL objects from a WithObject interface. | 
					
						
							|  |  |  | func ExtractObjects(i WithObject) ([]*url.URL, error) { | 
					
						
							|  |  |  | 	objectProp := i.GetActivityStreamsObject() | 
					
						
							|  |  |  | 	if objectProp == nil { | 
					
						
							|  |  |  | 		return nil, errors.New("object property was nil") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	urls := make([]*url.URL, 0, objectProp.Len()) | 
					
						
							|  |  |  | 	for iter := objectProp.Begin(); iter != objectProp.End(); iter = iter.Next() { | 
					
						
							|  |  |  | 		if iter.IsIRI() && iter.GetIRI() != nil { | 
					
						
							|  |  |  | 			urls = append(urls, iter.GetIRI()) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return urls, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-06 18:18:02 +02:00
										 |  |  | // ExtractVisibility extracts the gtsmodel.Visibility of a given addressable with a To and CC property. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // ActorFollowersURI is needed to check whether the visibility is FollowersOnly or not. The passed-in value | 
					
						
							|  |  |  | // should just be the string value representation of the followers URI of the actor who created the activity, | 
					
						
							|  |  |  | // eg https://example.org/users/whoever/followers. | 
					
						
							|  |  |  | func ExtractVisibility(addressable Addressable, actorFollowersURI string) (gtsmodel.Visibility, error) { | 
					
						
							|  |  |  | 	to, err := ExtractTos(addressable) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return "", fmt.Errorf("deriveVisibility: error extracting TO values: %s", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cc, err := ExtractCCs(addressable) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return "", fmt.Errorf("deriveVisibility: error extracting CC values: %s", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(to) == 0 && len(cc) == 0 { | 
					
						
							|  |  |  | 		return "", errors.New("deriveVisibility: message wasn't TO or CC anyone") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// for visibility derivation, we start by assuming most restrictive, and work our way to least restrictive | 
					
						
							|  |  |  | 	visibility := gtsmodel.VisibilityDirect | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// if it's got followers in TO and it's not also CC'ed to public, it's followers only | 
					
						
							|  |  |  | 	if isFollowers(to, actorFollowersURI) { | 
					
						
							|  |  |  | 		visibility = gtsmodel.VisibilityFollowersOnly | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// if it's CC'ed to public, it's unlocked | 
					
						
							|  |  |  | 	// mentioned SPECIFIC ACCOUNTS also get added to CC'es if it's not a direct message | 
					
						
							|  |  |  | 	if isPublic(cc) { | 
					
						
							|  |  |  | 		visibility = gtsmodel.VisibilityUnlocked | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// if it's To public, it's just straight up public | 
					
						
							|  |  |  | 	if isPublic(to) { | 
					
						
							|  |  |  | 		visibility = gtsmodel.VisibilityPublic | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return visibility, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // isPublic checks if at least one entry in the given uris slice equals | 
					
						
							|  |  |  | // the activitystreams public uri. | 
					
						
							|  |  |  | func isPublic(uris []*url.URL) bool { | 
					
						
							|  |  |  | 	for _, entry := range uris { | 
					
						
							|  |  |  | 		if strings.EqualFold(entry.String(), pub.PublicActivityPubIRI) { | 
					
						
							|  |  |  | 			return true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return false | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // isFollowers checks if at least one entry in the given uris slice equals | 
					
						
							|  |  |  | // the given followersURI. | 
					
						
							|  |  |  | func isFollowers(uris []*url.URL, followersURI string) bool { | 
					
						
							|  |  |  | 	for _, entry := range uris { | 
					
						
							|  |  |  | 		if strings.EqualFold(entry.String(), followersURI) { | 
					
						
							|  |  |  | 			return true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return false | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-11-13 17:29:43 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | // ExtractSensitive extracts whether or not an item is 'sensitive'. | 
					
						
							|  |  |  | // If no sensitive property is set on the item at all, or if this property | 
					
						
							|  |  |  | // isn't a boolean, then false will be returned by default. | 
					
						
							|  |  |  | func ExtractSensitive(withSensitive WithSensitive) bool { | 
					
						
							|  |  |  | 	sensitiveProp := withSensitive.GetActivityStreamsSensitive() | 
					
						
							|  |  |  | 	if sensitiveProp == nil { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for iter := sensitiveProp.Begin(); iter != sensitiveProp.End(); iter = iter.Next() { | 
					
						
							|  |  |  | 		if iter.IsXMLSchemaBoolean() { | 
					
						
							|  |  |  | 			return iter.Get() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return false | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-09-23 21:27:35 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // ExtractSharedInbox extracts the sharedInbox URI properly from an Actor. | 
					
						
							|  |  |  | // Returns nil if this property is not set. | 
					
						
							|  |  |  | func ExtractSharedInbox(withEndpoints WithEndpoints) *url.URL { | 
					
						
							|  |  |  | 	endpointsProp := withEndpoints.GetActivityStreamsEndpoints() | 
					
						
							|  |  |  | 	if endpointsProp == nil { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for iter := endpointsProp.Begin(); iter != endpointsProp.End(); iter = iter.Next() { | 
					
						
							|  |  |  | 		if iter.IsActivityStreamsEndpoints() { | 
					
						
							|  |  |  | 			endpoints := iter.Get() | 
					
						
							|  |  |  | 			if endpoints == nil { | 
					
						
							|  |  |  | 				return nil | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			sharedInboxProp := endpoints.GetActivityStreamsSharedInbox() | 
					
						
							|  |  |  | 			if sharedInboxProp == nil { | 
					
						
							|  |  |  | 				return nil | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if !sharedInboxProp.IsIRI() { | 
					
						
							|  |  |  | 				return nil | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return sharedInboxProp.GetIRI() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } |