| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  | <?php | 
					
						
							|  |  |  | // This file is part of GNU social - https://www.gnu.org/software/social
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // GNU social 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.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // GNU social 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 GNU social.  If not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * ActivityPub implementation for GNU social | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @package   GNUsocial | 
					
						
							|  |  |  |  * @author    Diogo Cordeiro <diogo@fc.up.pt> | 
					
						
							|  |  |  |  * @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org | 
					
						
							|  |  |  |  * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later | 
					
						
							|  |  |  |  * @link      http://www.gnu.org/software/social/ | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | defined('GNUSOCIAL') || die(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * ActivityPub notice representation | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @category  Plugin | 
					
						
							|  |  |  |  * @package   GNUsocial | 
					
						
							|  |  |  |  * @author    Diogo Cordeiro <diogo@fc.up.pt> | 
					
						
							|  |  |  |  * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2019-08-13 02:54:38 +01:00
										 |  |  | class Activitypub_notice | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Generates a pretty notice from a Notice object | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param Notice $notice | 
					
						
							|  |  |  |      * @return array array to be used in a response | 
					
						
							|  |  |  |      * @throws EmptyPkeyValueException | 
					
						
							|  |  |  |      * @throws InvalidUrlException | 
					
						
							|  |  |  |      * @throws ServerException | 
					
						
							| 
									
										
										
										
											2019-10-11 19:09:08 +01:00
										 |  |  |      * @throws Exception | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  |      * @author Diogo Cordeiro <diogo@fc.up.pt> | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2020-08-28 01:12:40 +01:00
										 |  |  |     public static function notice_to_array(Notice $notice): array | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  |     { | 
					
						
							|  |  |  |         $profile = $notice->getProfile(); | 
					
						
							|  |  |  |         $attachments = []; | 
					
						
							|  |  |  |         foreach ($notice->attachments() as $attachment) { | 
					
						
							|  |  |  |             $attachments[] = Activitypub_attachment::attachment_to_array($attachment); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $tags = []; | 
					
						
							|  |  |  |         foreach ($notice->getTags() as $tag) { | 
					
						
							|  |  |  |             if ($tag != "") {       // Hacky workaround to avoid stupid outputs
 | 
					
						
							|  |  |  |                 $tags[] = Activitypub_tag::tag_to_array($tag); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-13 00:05:51 +01:00
										 |  |  |         if ($notice->isPublic()) { | 
					
						
							|  |  |  |             $to = ['https://www.w3.org/ns/activitystreams#Public']; | 
					
						
							|  |  |  |             $cc = [common_local_url('apActorFollowers', ['id' => $profile->getID()])]; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             // Since we currently don't support sending unlisted/followers-only
 | 
					
						
							|  |  |  |             // notices, arriving here means we're instead answering to that type
 | 
					
						
							|  |  |  |             // of posts. Not having subscription policy working, its safer to
 | 
					
						
							|  |  |  |             // always send answers of type unlisted.
 | 
					
						
							|  |  |  |             $to = []; | 
					
						
							|  |  |  |             $cc = ['https://www.w3.org/ns/activitystreams#Public']; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  |         foreach ($notice->getAttentionProfiles() as $to_profile) { | 
					
						
							| 
									
										
										
										
											2019-10-11 19:09:08 +01:00
										 |  |  |             $to[] = $href = $to_profile->getUri(); | 
					
						
							|  |  |  |             $tags[] = Activitypub_mention_tag::mention_tag_to_array_from_values($href, $to_profile->getNickname() . '@' . parse_url($href, PHP_URL_HOST)); | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-29 11:12:02 +01:00
										 |  |  |         if (ActivityUtils::compareVerbs($notice->getVerb(), ActivityVerb::DELETE)) { | 
					
						
							|  |  |  |             $item = [ | 
					
						
							|  |  |  |                 '@context' => 'https://www.w3.org/ns/activitystreams', | 
					
						
							|  |  |  |                 'id' => self::getUri($notice), | 
					
						
							|  |  |  |                 'type' => 'Delete', | 
					
						
							|  |  |  |                 // XXX: A bit of ugly code here
 | 
					
						
							| 
									
										
										
										
											2020-08-29 22:18:00 +01:00
										 |  |  |                 'object' => array_merge(Activitypub_tombstone::tombstone_to_array((int)substr(explode(':', $notice->getUri())[2],9)), ['deleted' => str_replace(' ', 'T', $notice->getCreated()) . 'Z']), | 
					
						
							| 
									
										
										
										
											2020-08-29 11:12:02 +01:00
										 |  |  |                 'url' => $notice->getUrl(), | 
					
						
							|  |  |  |                 'actor' => $profile->getUri(), | 
					
						
							|  |  |  |                 'to' => $to, | 
					
						
							|  |  |  |                 'cc' => $cc, | 
					
						
							|  |  |  |                 'conversationId' => $notice->getConversationUrl(false), | 
					
						
							|  |  |  |                 'conversationUrl' => $notice->getConversationUrl(), | 
					
						
							|  |  |  |                 'content' => $notice->getRendered(), | 
					
						
							|  |  |  |                 'isLocal' => $notice->isLocal(), | 
					
						
							|  |  |  |                 'attachment' => $attachments, | 
					
						
							|  |  |  |                 'tag' => $tags | 
					
						
							|  |  |  |             ]; | 
					
						
							|  |  |  |         } else { // Note
 | 
					
						
							|  |  |  |             $item = [ | 
					
						
							|  |  |  |                 '@context' => 'https://www.w3.org/ns/activitystreams', | 
					
						
							| 
									
										
										
										
											2020-08-29 23:51:46 +01:00
										 |  |  |                 'id' => self::note_uri($notice->getID()), | 
					
						
							| 
									
										
										
										
											2020-08-29 11:12:02 +01:00
										 |  |  |                 'type' => 'Note', | 
					
						
							|  |  |  |                 'published' => str_replace(' ', 'T', $notice->getCreated()) . 'Z', | 
					
						
							|  |  |  |                 'url' => $notice->getUrl(), | 
					
						
							|  |  |  |                 'attributedTo' => $profile->getUri(), | 
					
						
							|  |  |  |                 'to' => $to, | 
					
						
							|  |  |  |                 'cc' => $cc, | 
					
						
							|  |  |  |                 'conversationId' => $notice->getConversationUrl(false), | 
					
						
							|  |  |  |                 'conversationUrl' => $notice->getConversationUrl(), | 
					
						
							|  |  |  |                 'content' => $notice->getRendered(), | 
					
						
							|  |  |  |                 'isLocal' => $notice->isLocal(), | 
					
						
							|  |  |  |                 'attachment' => $attachments, | 
					
						
							|  |  |  |                 'tag' => $tags | 
					
						
							|  |  |  |             ]; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Is this a reply?
 | 
					
						
							|  |  |  |         if (!empty($notice->reply_to)) { | 
					
						
							| 
									
										
										
										
											2020-08-28 01:12:40 +01:00
										 |  |  |             $item['inReplyTo'] = self::getUri(Notice::getById($notice->reply_to)); | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Do we have a location for this notice?
 | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |             $location = Notice_location::locFromStored($notice); | 
					
						
							| 
									
										
										
										
											2019-10-11 19:09:08 +01:00
										 |  |  |             $item['latitude'] = $location->lat; | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  |             $item['longitude'] = $location->lon; | 
					
						
							|  |  |  |         } catch (Exception $e) { | 
					
						
							|  |  |  |             // Apparently no.
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $item; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Create a Notice via ActivityPub Note Object. | 
					
						
							|  |  |  |      * Returns created Notice. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param array $object | 
					
						
							| 
									
										
										
										
											2019-08-13 00:05:51 +01:00
										 |  |  |      * @param Profile $actor_profile | 
					
						
							| 
									
										
										
										
											2019-08-19 23:33:18 +01:00
										 |  |  |      * @param bool $directMessage | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  |      * @return Notice | 
					
						
							|  |  |  |      * @throws Exception | 
					
						
							| 
									
										
										
										
											2019-10-11 19:09:08 +01:00
										 |  |  |      * @author Diogo Cordeiro <diogo@fc.up.pt> | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2020-07-05 01:58:22 +01:00
										 |  |  |     public static function create_notice(array $object, Profile $actor_profile, bool $directMessage = false): Notice | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-07-07 17:57:48 +01:00
										 |  |  |         $id = $object['id'];                                 // int
 | 
					
						
							| 
									
										
										
										
											2019-10-11 19:09:08 +01:00
										 |  |  |         $url = isset($object['url']) ? $object['url'] : $id; // string
 | 
					
						
							| 
									
										
										
										
											2020-07-07 17:57:48 +01:00
										 |  |  |         $content = $object['content'];                       // string
 | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // possible keys: ['inReplyTo', 'latitude', 'longitude']
 | 
					
						
							|  |  |  |         $settings = []; | 
					
						
							|  |  |  |         if (isset($object['inReplyTo'])) { | 
					
						
							|  |  |  |             $settings['inReplyTo'] = $object['inReplyTo']; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (isset($object['latitude'])) { | 
					
						
							| 
									
										
										
										
											2019-10-11 19:09:08 +01:00
										 |  |  |             $settings['latitude'] = $object['latitude']; | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |         if (isset($object['longitude'])) { | 
					
						
							|  |  |  |             $settings['longitude'] = $object['longitude']; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $act = new Activity(); | 
					
						
							|  |  |  |         $act->verb = ActivityVerb::POST; | 
					
						
							|  |  |  |         $act->time = time(); | 
					
						
							|  |  |  |         $act->actor = $actor_profile->asActivityObject(); | 
					
						
							|  |  |  |         $act->context = new ActivityContext(); | 
					
						
							| 
									
										
										
										
											2019-10-11 19:09:08 +01:00
										 |  |  |         $options = ['source' => 'ActivityPub', | 
					
						
							|  |  |  |             'uri' => $id, | 
					
						
							|  |  |  |             'url' => $url, | 
					
						
							|  |  |  |             'is_local' => self::getNotePolicyType($object, $actor_profile)]; | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-19 23:33:18 +01:00
										 |  |  |         if ($directMessage) { | 
					
						
							|  |  |  |             $options['scope'] = Notice::MESSAGE_SCOPE; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  |         // Is this a reply?
 | 
					
						
							|  |  |  |         if (isset($settings['inReplyTo'])) { | 
					
						
							|  |  |  |             try { | 
					
						
							|  |  |  |                 $inReplyTo = ActivityPubPlugin::grab_notice_from_url($settings['inReplyTo']); | 
					
						
							| 
									
										
										
										
											2019-10-11 19:09:08 +01:00
										 |  |  |                 $act->context->replyToID = $inReplyTo->getUri(); | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  |                 $act->context->replyToUrl = $inReplyTo->getUrl(); | 
					
						
							|  |  |  |             } catch (Exception $e) { | 
					
						
							|  |  |  |                 // It failed to grab, maybe we got this note from another source
 | 
					
						
							|  |  |  |                 // (e.g.: OStatus) that handles this differently or we really
 | 
					
						
							|  |  |  |                 // failed to get it...
 | 
					
						
							|  |  |  |                 // Welp, nothing that we can do about, let's
 | 
					
						
							|  |  |  |                 // just fake we don't have such notice.
 | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             $inReplyTo = null; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Mentions
 | 
					
						
							|  |  |  |         $mentions = []; | 
					
						
							|  |  |  |         if (isset($object['tag']) && is_array($object['tag'])) { | 
					
						
							|  |  |  |             foreach ($object['tag'] as $tag) { | 
					
						
							| 
									
										
										
										
											2020-02-14 17:25:26 +00:00
										 |  |  |                 if (array_key_exists('type', $tag) && $tag['type'] == 'Mention') { | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  |                     $mentions[] = $tag['href']; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         $mentions_profiles = []; | 
					
						
							|  |  |  |         $discovery = new Activitypub_explorer; | 
					
						
							|  |  |  |         foreach ($mentions as $mention) { | 
					
						
							|  |  |  |             try { | 
					
						
							| 
									
										
										
										
											2020-08-05 17:27:30 +01:00
										 |  |  |                 $mentioned_profile = $discovery->lookup($mention); | 
					
						
							|  |  |  |                 if (!empty($mentioned_profile)) { | 
					
						
							|  |  |  |                     $mentions_profiles[] = $mentioned_profile[0]; | 
					
						
							| 
									
										
										
										
											2020-08-04 20:00:55 +01:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  |             } catch (Exception $e) { | 
					
						
							| 
									
										
										
										
											2020-08-04 20:00:55 +01:00
										 |  |  |                 // Invalid actor found, just let it go, it will eventually be handled by some other federation plugin like OStatus.
 | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         unset($discovery); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         foreach ($mentions_profiles as $mp) { | 
					
						
							| 
									
										
										
										
											2019-08-19 23:33:18 +01:00
										 |  |  |             if (!$mp->hasBlocked($actor_profile)) { | 
					
						
							| 
									
										
										
										
											2019-12-10 22:27:32 +00:00
										 |  |  |                 $act->context->attention[$mp->getUri()] = 'http://activitystrea.ms/schema/1.0/person'; | 
					
						
							| 
									
										
										
										
											2019-08-19 23:33:18 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Add location if that is set
 | 
					
						
							|  |  |  |         if (isset($settings['latitude'], $settings['longitude'])) { | 
					
						
							|  |  |  |             $act->context->location = Location::fromLatLon($settings['latitude'], $settings['longitude']); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Reject notice if it is too long (without the HTML) | 
					
						
							| 
									
										
										
										
											2020-08-28 01:12:40 +01:00
										 |  |  |         if (Notice::contentTooLong($content)) { | 
					
						
							|  |  |  |             throw new Exception('That\'s too long. Maximum notice size is %d character.'); | 
					
						
							|  |  |  |         }*/ | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-05 17:21:30 +01:00
										 |  |  |         // Attachments (first part)
 | 
					
						
							|  |  |  |         $attachments = []; | 
					
						
							|  |  |  |         if (isset($object['attachment']) && is_array($object['attachment'])) { | 
					
						
							|  |  |  |             foreach ($object['attachment'] as $attachment) { | 
					
						
							|  |  |  |                 if (array_key_exists('type', $attachment) && $attachment['type'] == 'Document') { | 
					
						
							|  |  |  |                     try { | 
					
						
							|  |  |  |                         // throws exception on failure
 | 
					
						
							|  |  |  |                         $attachment = MediaFile::fromUrl($attachment['url'], $actor_profile, $attachment['name']); | 
					
						
							|  |  |  |                         $act->enclosures[] = $attachment->getEnclosure(); | 
					
						
							|  |  |  |                         $attachments[] = $attachment; | 
					
						
							|  |  |  |                     } catch (Exception $e) { | 
					
						
							|  |  |  |                         // Whatever.
 | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  |         $actobj = new ActivityObject(); | 
					
						
							|  |  |  |         $actobj->type = ActivityObject::NOTE; | 
					
						
							|  |  |  |         $actobj->content = strip_tags($content, '<p><b><i><u><a><ul><ol><li>'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Finally add the activity object to our activity
 | 
					
						
							|  |  |  |         $act->objects[] = $actobj; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $note = Notice::saveActivity($act, $actor_profile, $options); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-05 17:21:30 +01:00
										 |  |  |         // Attachments (last part)
 | 
					
						
							|  |  |  |         foreach($attachments as $attachment) { | 
					
						
							|  |  |  |             $attachment->attachToNotice($note); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  |         return $note; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Validates a note. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param array $object | 
					
						
							| 
									
										
										
										
											2019-10-11 19:09:08 +01:00
										 |  |  |      * @return bool false if unacceptable for GS but valid ActivityPub object | 
					
						
							|  |  |  |      * @throws Exception if invalid ActivityPub object | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  |      * @author Diogo Cordeiro <diogo@fc.up.pt> | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2020-08-28 01:12:40 +01:00
										 |  |  |     public static function validate_note(array $object): bool | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  |     { | 
					
						
							|  |  |  |         if (!isset($object['id'])) { | 
					
						
							|  |  |  |             common_debug('ActivityPub Notice Validator: Rejected because Object ID was not specified.'); | 
					
						
							|  |  |  |             throw new Exception('Object ID not specified.'); | 
					
						
							|  |  |  |         } elseif (!filter_var($object['id'], FILTER_VALIDATE_URL)) { | 
					
						
							|  |  |  |             common_debug('ActivityPub Notice Validator: Rejected because Object ID is invalid.'); | 
					
						
							|  |  |  |             throw new Exception('Invalid Object ID.'); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (!isset($object['type']) || $object['type'] !== 'Note') { | 
					
						
							|  |  |  |             common_debug('ActivityPub Notice Validator: Rejected because of Type.'); | 
					
						
							|  |  |  |             throw new Exception('Invalid Object type.'); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-08-05 23:22:32 +01:00
										 |  |  |         if (isset($object['url']) && !filter_var($object['url'], FILTER_VALIDATE_URL)) { | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  |             common_debug('ActivityPub Notice Validator: Rejected because Object URL is invalid.'); | 
					
						
							|  |  |  |             throw new Exception('Invalid Object URL.'); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-08-13 00:05:51 +01:00
										 |  |  |         if (!(isset($object['to']) && isset($object['cc']))) { | 
					
						
							|  |  |  |             common_debug('ActivityPub Notice Validator: Rejected because either Object CC or TO wasn\'t specified.'); | 
					
						
							|  |  |  |             throw new Exception('Either Object CC or TO wasn\'t specified.'); | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-10-11 19:09:08 +01:00
										 |  |  |         if (!isset($object['content'])) { | 
					
						
							|  |  |  |             common_debug('ActivityPub Notice Validator: Rejected because Content was not specified (GNU social requires content in notes).'); | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-07-17 16:25:24 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Get the original representation URL of a given notice. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param Notice $notice notice from which to retrieve the URL | 
					
						
							|  |  |  |      * @return string URL | 
					
						
							| 
									
										
										
										
											2019-10-11 19:09:08 +01:00
										 |  |  |      * @throws InvalidUrlException | 
					
						
							|  |  |  |      * @throws Exception | 
					
						
							| 
									
										
										
										
											2019-07-17 16:25:24 +01:00
										 |  |  |      * @author Bruno Casteleiro <brunoccast@fc.up.pt> | 
					
						
							| 
									
										
										
										
											2020-08-29 23:51:46 +01:00
										 |  |  |      * @see note_uri when it's not a generic activity but a object type note | 
					
						
							| 
									
										
										
										
											2019-07-17 16:25:24 +01:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2020-08-28 01:12:40 +01:00
										 |  |  |     public static function getUri(Notice $notice): string | 
					
						
							| 
									
										
										
										
											2019-10-11 19:09:08 +01:00
										 |  |  |     { | 
					
						
							|  |  |  |         if ($notice->isLocal()) { | 
					
						
							|  |  |  |             return common_local_url('apNotice', ['id' => $notice->getID()]); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             return $notice->getUrl(); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-08-13 00:05:51 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-29 23:51:46 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Use this if your Notice is in fact a note | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param int $id | 
					
						
							|  |  |  |      * @return string it's uri | 
					
						
							|  |  |  |      * @author Diogo Cordeiro <diogo@fc.up.pt> | 
					
						
							|  |  |  |      * @see getUri for every other activity that aren't objects of a certain type like note | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public static function note_uri(int $id): string | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return common_root_url() . 'object/note/' . $id; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-13 00:05:51 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Extract note policy type from note targets. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param array $note received Note | 
					
						
							|  |  |  |      * @param Profile $actor_profile Note author | 
					
						
							|  |  |  |      * @return int Notice policy type | 
					
						
							|  |  |  |      * @author Bruno Casteleiro <brunoccast@fc.up.pt> | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2019-10-11 19:09:08 +01:00
										 |  |  |     public static function getNotePolicyType(array $note, Profile $actor_profile): int | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-08-13 00:05:51 +01:00
										 |  |  |         if (in_array('https://www.w3.org/ns/activitystreams#Public', $note['to'])) { | 
					
						
							|  |  |  |             return $actor_profile->isLocal() ? Notice::LOCAL_PUBLIC : Notice::REMOTE; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             // either an unlisted or followers-only note, we'll handle
 | 
					
						
							|  |  |  |             // both as a GATEWAY notice since this type is not visible
 | 
					
						
							|  |  |  |             // from the public timelines, hence partially enough while
 | 
					
						
							|  |  |  |             // we don't have subscription_policy working.
 | 
					
						
							|  |  |  |             return Notice::GATEWAY; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-05-11 12:27:21 +01:00
										 |  |  | } |