]> git.mxchange.org Git - friendica.git/commitdiff
Tighten profile restriction feature
authorHypolite Petovan <hypolite@mrpetovan.com>
Wed, 30 Nov 2022 18:50:52 +0000 (13:50 -0500)
committerHypolite Petovan <hypolite@mrpetovan.com>
Thu, 1 Dec 2022 13:03:35 +0000 (08:03 -0500)
- Prevent feed access to restricted profiles
- Rework display of restricted profiles with a redirect to the profile/restricted route
- Normalize permission checking with IHandleUserSession->isAuthenticated
- Remove unusable "nocache" parameter in feed module because session isn't initialized
- Reword setting name and description

16 files changed:
mod/photos.php
src/Model/Event.php
src/Model/Profile.php
src/Module/ActivityPub/Objects.php
src/Module/Calendar/Show.php
src/Module/DFRN/Poll.php
src/Module/Feed.php
src/Module/Item/Display.php
src/Module/Profile/Photos.php
src/Module/Profile/Profile.php
src/Module/Profile/Restricted.php [new file with mode: 0644]
src/Module/Profile/Status.php
src/Module/Settings/Account.php
src/Module/Update/Profile.php
src/Protocol/Feed.php
static/routes.config.php

index 14eb88ac95b6ac6d7ac1952c24b7032e0392d525..865e0fb318ce34569e79055397a3c39426ca7cc1 100644 (file)
@@ -865,9 +865,8 @@ function photos_content(App $a)
                $contact = DBA::selectFirst('contact', [], ['id' => $contact_id, 'uid' => $owner_uid, 'blocked' => false, 'pending' => false]);
        }
 
-       if ($user['hidewall'] && (DI::userSession()->getLocalUserId() != $owner_uid) && !$remote_contact) {
-               DI::sysmsg()->addNotice(DI::l10n()->t('Access to this item is restricted.'));
-               return;
+       if ($user['hidewall'] && !DI::userSession()->isAuthenticated()) {
+               DI::baseUrl()->redirect('profile/' . $user['nickname'] . '/restricted');
        }
 
        $sql_extra = Security::getPermissionsSQLByUserId($owner_uid);
index 6f1b29a6c3f9e36a80d8bec7f7a9600e4b94956d..82f7702165ab4be5152e25f3556b87ec73c1d473 100644 (file)
@@ -281,7 +281,7 @@ class Event
                        if (!DBA::isResult($existing_event)) {
                                return 0;
                        }
-                       
+
                        if ($existing_event['edited'] === $event['edited']) {
                                return $event['id'];
                        }
@@ -501,29 +501,20 @@ class Event
         * Additionally, it can check if the owner array is selectable
         *
         * @param string $nickname
-        * @param bool   $check
         *
         * @return array the owner array
         * @throws NotFoundException The given nickname does not exist
         * @throws UnauthorizedException The access for the given nickname is restricted
         */
-       public static function getOwnerForNickname(string $nickname, bool $check = true): array
+       public static function getOwnerForNickname(string $nickname): array
        {
                $owner = User::getOwnerDataByNick($nickname);
-               if (empty($owner)) {
+               if (empty($owner) || $owner['account_removed'] || $owner['account_expired']) {
                        throw new NotFoundException(DI::l10n()->t('User not found.'));
                }
 
-               if ($check) {
-                       $contact_id = DI::userSession()->getRemoteContactID($owner['uid']);
-
-                       $remote_contact = $contact_id && DBA::exists('contact', ['id' => $contact_id, 'uid' => $owner['uid']]);
-
-                       $is_owner = DI::userSession()->getLocalUserId() == $owner['uid'];
-
-                       if ($owner['hidewall'] && !$is_owner && !$remote_contact) {
-                               throw new UnauthorizedException(DI::l10n()->t('Access to this profile has been restricted.'));
-                       }
+               if ($owner['hidewall'] && !DI::userSession()->isAuthenticated()) {
+                       throw new UnauthorizedException(DI::l10n()->t('Access to this profile has been restricted.'));
                }
 
                return $owner;
@@ -541,7 +532,7 @@ class Event
        public static function getByIdAndUid(int $owner_uid, int $event_id, string $nickname = null): array
        {
                if (!empty($nickname)) {
-                       $owner = static::getOwnerForNickname($nickname, true);
+                       $owner = static::getOwnerForNickname($nickname);
                        $owner_uid = $owner['uid'];
 
                        // get the permissions
index dcd39a30c1cf2b243bace5a5fa880a26a2546e8c..26395cb4d123ea3101900c2c2366df436a5aa823 100644 (file)
@@ -461,7 +461,7 @@ class Profile
                        '$unfollow' => DI::l10n()->t('Unfollow'),
                        '$unfollow_link' => $unfollow_link,
                        '$subscribe_feed' => DI::l10n()->t('Atom feed'),
-                       '$subscribe_feed_link' => $profile['poll'],
+                       '$subscribe_feed_link' => $profile['hidewall'] ? '' : $profile['poll'],
                        '$wallmessage' => DI::l10n()->t('Message'),
                        '$wallmessage_link' => $wallmessage_link,
                        '$account_type' => $account_type,
index e2328b5e585c59ac6fd1598d30491fef1eb84608..8c8109d667ca99ac2d8a7a0a798f789a6c44f1bb 100644 (file)
@@ -29,6 +29,7 @@ use Friendica\DI;
 use Friendica\Model\Contact;
 use Friendica\Model\Item;
 use Friendica\Model\Post;
+use Friendica\Model\User;
 use Friendica\Network\HTTPException;
 use Friendica\Protocol\ActivityPub;
 use Friendica\Util\HTTPSignature;
@@ -74,7 +75,9 @@ class Objects extends BaseModule
                        throw new HTTPException\NotFoundException();
                }
 
-               $validated = in_array($item['private'], [Item::PUBLIC, Item::UNLISTED]);
+               $owner = User::getById($item['uid'], ['hidewall']);
+
+               $validated = empty($owner['hidewall']) && in_array($item['private'], [Item::PUBLIC, Item::UNLISTED]);
 
                if (!$validated) {
                        $requester = HTTPSignature::getSigner('', $_SERVER);
index 9c5c9c4526320fe1a524ed1fcbca93d9ef8caf8a..da0e285a91712fab765a52b187d100d7b516c8da 100644 (file)
@@ -91,7 +91,7 @@ class Show extends BaseModule
 
                        $this->page['aside'] .= Widget\CalendarExport::getHTML($this->session->getLocalUserId());
                } else {
-                       $owner = Event::getOwnerForNickname($this->parameters['nickname'], true);
+                       $owner = Event::getOwnerForNickname($this->parameters['nickname']);
 
                        Nav::setSelected('calendar');
 
index e41dafed56f2c2d90d2d7017024fe86135a54d07..1562ce0de263f7b1a9b7ce94d07c2da2990eeb5a 100644 (file)
@@ -23,7 +23,9 @@ namespace Friendica\Module\DFRN;
 
 use Friendica\BaseModule;
 use Friendica\Core\System;
+use Friendica\Model\User;
 use Friendica\Module\Response;
+use Friendica\Network\HTTPException;
 use Friendica\Protocol\OStatus;
 
 /**
@@ -33,7 +35,19 @@ class Poll extends BaseModule
 {
        protected function rawContent(array $request = [])
        {
+               $owner = User::getByNickname(
+                       $this->parameters['nickname'] ?? '',
+                       ['nickname', 'blocked', 'account_expired', 'account_removed', 'hidewall']
+               );
+               if (!$owner || $owner['account_expired'] || $owner['account_removed']) {
+                       throw new HTTPException\NotFoundException($this->t('User not found.'));
+               }
+
+               if ($owner['blocked'] || $owner['hidewall']) {
+                       throw new HTTPException\UnauthorizedException($this->t('Access to this profile has been restricted.'));
+               }
+
                $last_update = $request['last_update'] ?? '';
-               System::httpExit(OStatus::feed($this->parameters['nickname'], $last_update, 10) ?? '', Response::TYPE_ATOM);
+               System::httpExit(OStatus::feed($owner['nickname'], $last_update, 10) ?? '', Response::TYPE_ATOM);
        }
 }
index b24ccbc94666ba5b8f842ccde7428c687dc0d5d8..59714af387baa60f3e4ec2df537fa162c0a4c1a6 100644 (file)
@@ -23,9 +23,9 @@ namespace Friendica\Module;
 
 use Friendica\BaseModule;
 use Friendica\Core\System;
-use Friendica\DI;
-use Friendica\Protocol\Feed as ProtocolFeed;
+use Friendica\Model\User;
 use Friendica\Network\HTTPException;
+use Friendica\Protocol\Feed as ProtocolFeed;
 
 /**
  * Provides public Atom feeds
@@ -37,23 +37,14 @@ use Friendica\Network\HTTPException;
  * - /feed/[nickname]/replies => comments
  * - /feed/[nickname]/activity => activity
  *
- * The nocache GET parameter is provided mainly for debug purposes, requires auth
- *
  * @author Hypolite Petovan <hypolite@mrpetovan.com>
  */
 class Feed extends BaseModule
 {
        protected function rawContent(array $request = [])
        {
-               $last_update = $this->getRequestValue($request, 'last_update', '');
-               $nocache     = !empty($request['nocache']) && DI::userSession()->getLocalUserId();
-
-               $type = null;
-               // @TODO: Replace with parameter from router
-               if (DI::args()->getArgc() > 2) {
-                       $type = DI::args()->getArgv()[2];
-               }
-
+               $nick = $this->parameters['nickname'] ?? '';
+               $type = $this->parameters['type'] ?? null;
                switch ($type) {
                        case 'posts':
                        case 'comments':
@@ -67,11 +58,19 @@ class Feed extends BaseModule
                                $type = 'posts';
                }
 
-               $feed = ProtocolFeed::atom($this->parameters['nickname'], $last_update, 10, $type, $nocache, true);
-               if (empty($feed)) {
-                       throw new HTTPException\NotFoundException(DI::l10n()->t('User not found.'));
+               $last_update = $this->getRequestValue($request, 'last_update', '');
+
+               $owner = User::getOwnerDataByNick($nick);
+               if (!$owner || $owner['account_expired'] || $owner['account_removed']) {
+                       throw new HTTPException\NotFoundException($this->t('User not found.'));
+               }
+
+               if ($owner['blocked'] || $owner['hidewall']) {
+                       throw new HTTPException\UnauthorizedException($this->t('Access to this profile has been restricted.'));
                }
 
+               $feed = ProtocolFeed::atom($owner, $last_update, 10, $type);
+
                System::httpExit($feed, Response::TYPE_ATOM);
        }
 }
index df500f7ccb4aedd31a95b52b9c82c8cefc0cfe04..01bf9a5587ec263946e7866b99670254022b168d 100644 (file)
@@ -196,8 +196,7 @@ class Display extends BaseModule
 
        protected function getDisplayData(array $item, bool $update = false, int $updateUid = 0, bool $force = false): string
        {
-               $isRemoteContact = false;
-               $itemUid         = $this->session->getLocalUserId();
+               $itemUid = $this->session->getLocalUserId();
 
                $parent = null;
                if (!$this->session->getLocalUserId() && !empty($item['parent-uri-id'])) {
@@ -206,8 +205,7 @@ class Display extends BaseModule
 
                if (!empty($parent)) {
                        $pageUid         = $parent['uid'];
-                       $isRemoteContact = $this->session->getRemoteContactID($pageUid);
-                       if ($isRemoteContact) {
+                       if ($this->session->getRemoteContactID($pageUid)) {
                                $itemUid = $parent['uid'];
                        }
                } else {
@@ -215,13 +213,11 @@ class Display extends BaseModule
                }
 
                if (!empty($pageUid) && ($pageUid != $this->session->getLocalUserId())) {
-                       $page_user = User::getById($pageUid, ['hidewall']);
+                       $page_user = User::getById($pageUid, ['nickname', 'hidewall']);
                }
 
-               $is_owner = $this->session->getLocalUserId() && (in_array($pageUid, [$this->session->getLocalUserId(), 0]));
-
-               if (!empty($page_user['hidewall']) && !$is_owner && !$isRemoteContact) {
-                       throw new HTTPException\ForbiddenException($this->t('Access to this profile has been restricted.'));
+               if (!empty($page_user['hidewall']) && !$this->session->isAuthenticated()) {
+                       $this->baseUrl->redirect('profile/' . $page_user['nickname'] . '/restricted');
                }
 
                $sql_extra = Item::getPermissionsSQLByUserId($pageUid);
@@ -275,6 +271,8 @@ class Display extends BaseModule
 
                $output = '';
 
+               $is_owner = $this->session->getLocalUserId() && (in_array($pageUid, [$this->session->getLocalUserId(), 0]));
+
                // We need the editor here to be able to reshare an item.
                if ($is_owner && !$update) {
                        $output .= $this->conversation->statusEditor([], 0, true);
index 50af6f0e961c34a54fb72dab8c16860308e90770..940c1257b2043c3b07aaec95a055c23d615f4a03 100644 (file)
@@ -88,8 +88,8 @@ class Photos extends \Friendica\Module\BaseProfile
                        $remote_contact = $contact && !$contact['blocked'] && !$contact['pending'];
                }
 
-               if ($owner['hidewall'] && !$is_owner && !$remote_contact) {
-                       throw new HttpException\ForbiddenException($this->t('Access to this item is restricted.'));
+               if ($owner['hidewall'] && !$this->session->isAuthenticated()) {
+                       $this->baseUrl->redirect('profile/' . $owner['nickname'] . '/restricted');
                }
 
                $this->session->set('photo_return', $this->args->getCommand());
index 07db082591df7149d20c325e052e07e6745adcba..553e9c523140b06a184138f3e3e1843a6a69b775 100644 (file)
@@ -76,21 +76,19 @@ class Profile extends BaseProfile
        {
                $a = DI::app();
 
-               $profile = ProfileModel::load($a, $this->parameters['nickname']);
+               $profile = ProfileModel::load($a, $this->parameters['nickname'] ?? '');
                if (!$profile) {
                        throw new HTTPException\NotFoundException(DI::l10n()->t('Profile not found.'));
                }
 
                $remote_contact_id = DI::userSession()->getRemoteContactID($profile['uid']);
 
-               if (DI::config()->get('system', 'block_public') && !DI::userSession()->getLocalUserId() && !$remote_contact_id) {
+               if (DI::config()->get('system', 'block_public') && !DI::userSession()->isAuthenticated()) {
                        return Login::form();
                }
 
-               $is_owner = DI::userSession()->getLocalUserId() == $profile['uid'];
-
-               if (!empty($profile['hidewall']) && !$is_owner && !$remote_contact_id) {
-                       throw new HTTPException\ForbiddenException(DI::l10n()->t('Access to this profile has been restricted.'));
+               if (!empty($profile['hidewall']) && !DI::userSession()->isAuthenticated()) {
+                       $this->baseUrl->redirect('profile/' . $profile['nickname'] . '/restricted');
                }
 
                if (!empty($profile['page-flags']) && $profile['page-flags'] == User::PAGE_FLAGS_COMMUNITY) {
@@ -104,11 +102,6 @@ class Profile extends BaseProfile
                $is_owner = DI::userSession()->getLocalUserId() == $profile['uid'];
                $o = self::getTabsHTML($a, 'profile', $is_owner, $profile['nickname'], $profile['hide-friends']);
 
-               if (!empty($profile['hidewall']) && !$is_owner && !$remote_contact_id) {
-                       DI::sysmsg()->addNotice(DI::l10n()->t('Access to this profile has been restricted.'));
-                       return '';
-               }
-
                $view_as_contacts = [];
                $view_as_contact_id = 0;
                $view_as_contact_alert = '';
@@ -307,8 +300,8 @@ class Profile extends BaseProfile
                }
 
                // site block
-               $blocked   = !DI::userSession()->getLocalUserId() && !$remote_contact_id && DI::config()->get('system', 'block_public');
-               $userblock = !DI::userSession()->getLocalUserId() && !$remote_contact_id && $profile['hidewall'];
+               $blocked   = !DI::userSession()->isAuthenticated() && DI::config()->get('system', 'block_public');
+               $userblock = !DI::userSession()->isAuthenticated() && $profile['hidewall'];
                if (!$blocked && !$userblock) {
                        $keywords = str_replace(['#', ',', ' ', ',,'], ['', ' ', ',', ','], $profile['pub_keywords'] ?? '');
                        if (strlen($keywords)) {
diff --git a/src/Module/Profile/Restricted.php b/src/Module/Profile/Restricted.php
new file mode 100644 (file)
index 0000000..31ce69f
--- /dev/null
@@ -0,0 +1,63 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2022, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Module\Profile;
+
+use Friendica\App;
+use Friendica\BaseModule;
+use Friendica\Core\L10n;
+use Friendica\Core\Renderer;
+use Friendica\Model\Profile;
+use Friendica\Module\Response;
+use Friendica\Network\HTTPException;
+use Friendica\Util\Profiler;
+use Psr\Log\LoggerInterface;
+
+class Restricted extends BaseModule
+{
+       /** @var App */
+       private $app;
+
+       public function __construct(App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = [])
+       {
+               parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
+
+               $this->app = $app;
+       }
+
+       protected function content(array $request = []): string
+       {
+               $profile = Profile::load($this->app, $this->parameters['nickname'] ?? '', false);
+               if (!$profile) {
+                       throw new HTTPException\NotFoundException($this->t('Profile not found.'));
+               }
+
+               if (empty($profile['hidewall'])) {
+                       $this->baseUrl->redirect('profile/' . $profile['nickname']);
+               }
+
+               $tpl = Renderer::getMarkupTemplate('exception.tpl');
+               return Renderer::replaceMacros($tpl, [
+                       '$title'   => $this->t('Restricted profile'),
+                       '$message' => $this->t('This profile has been restricted which prevents access to their public content from anonymous visitors.'),
+               ]);
+       }
+}
index 6543ea1952a98cabb3e371c681a55da385b66168..4b5e56755131f673f28e27441c5b15f2b74b30a5 100644 (file)
@@ -105,9 +105,8 @@ class Status extends BaseProfile
                $is_owner = DI::userSession()->getLocalUserId() == $profile['uid'];
                $last_updated_key = "profile:" . $profile['uid'] . ":" . DI::userSession()->getLocalUserId() . ":" . $remote_contact;
 
-               if (!empty($profile['hidewall']) && !$is_owner && !$remote_contact) {
-                       DI::sysmsg()->addNotice(DI::l10n()->t('Access to this profile has been restricted.'));
-                       return '';
+               if (!empty($profile['hidewall']) && !DI::userSession()->isAuthenticated()) {
+                       $this->baseUrl->redirect('profile/' . $profile['nickname'] . '/restricted');
                }
 
                $o .= self::getTabsHTML($a, 'status', $is_owner, $profile['nickname'], $profile['hide-friends']);
index 4217b1e88d9af900f8d09fce9cd4cdb6ff9a143e..8768115ec326becd1d5195568f2b28a24e1c55a1 100644 (file)
@@ -586,7 +586,7 @@ class Account extends BaseSettings
                        '$profile_in_dir'     => $profile_in_dir,
                        '$profile_in_net_dir' => ['profile_in_netdirectory', DI::l10n()->t('Allow your profile to be searchable globally?'), $profile['net-publish'], DI::l10n()->t("Activate this setting if you want others to easily find and follow you. Your profile will be searchable on remote systems. This setting also determines whether Friendica will inform search engines that your profile should be indexed or not.") . $net_pub_desc],
                        '$hide_friends'       => ['hide-friends', DI::l10n()->t('Hide your contact/friend list from viewers of your profile?'), $profile['hide-friends'], DI::l10n()->t('A list of your contacts is displayed on your profile page. Activate this option to disable the display of your contact list.')],
-                       '$hide_wall'          => ['hidewall', DI::l10n()->t('Hide your profile details from anonymous viewers?'), $user['hidewall'], DI::l10n()->t('Anonymous visitors will only see your profile picture, your display name and the nickname you are using on your profile page. Your public posts and replies will still be accessible by other means.')],
+                       '$hide_wall'          => ['hidewall', $this->t('Hide your public content from anonymous viewers'), $user['hidewall'], $this->t('Anonymous visitors will only see your basic profile details. Your public posts and replies will still be freely accessible on the remote servers of your followers and through relays.')],
                        '$unlisted'           => ['unlisted', DI::l10n()->t('Make public posts unlisted'), DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'unlisted'), DI::l10n()->t('Your public posts will not appear on the community pages or in search results, nor be sent to relay servers. However they can still appear on public feeds on remote servers.')],
                        '$accessiblephotos'   => ['accessible-photos', DI::l10n()->t('Make all posted pictures accessible'), DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'accessible-photos'), DI::l10n()->t("This option makes every posted picture accessible via the direct link. This is a workaround for the problem that most other networks can't handle permissions on pictures. Non public pictures still won't be visible for the public on your photo albums though.")],
                        '$blockwall'          => ['blockwall', DI::l10n()->t('Allow friends to post to your profile page?'), (intval($user['blockwall']) ? '0' : '1'), DI::l10n()->t('Your contacts may write posts on your profile wall. These posts will be distributed to your contacts')],
index be15820e45d5ea24c95c8fb25208c6dda773acb2..c1b7522e5c8d9615f87905c5a6e22b1181a66895 100644 (file)
@@ -49,7 +49,7 @@ class Profile extends BaseModule
                $is_owner = DI::userSession()->getLocalUserId() == $a->getProfileOwner();
                $last_updated_key = "profile:" . $a->getProfileOwner() . ":" . DI::userSession()->getLocalUserId() . ":" . $remote_contact;
 
-               if (!$is_owner && !$remote_contact) {
+               if (!DI::userSession()->isAuthenticated()) {
                        $user = User::getById($a->getProfileOwner(), ['hidewall']);
                        if ($user['hidewall']) {
                                throw new ForbiddenException(DI::l10n()->t('Access to this profile has been restricted.'));
index 7c6a68b60187907828d914fade202efe8054a41e..3dac91e8494025c7fbd7408116fcc6f0a948827b 100644 (file)
@@ -40,6 +40,7 @@ use Friendica\Model\Item;
 use Friendica\Model\Post;
 use Friendica\Model\Tag;
 use Friendica\Model\User;
+use Friendica\Network\HTTPException;
 use Friendica\Util\DateTimeFormat;
 use Friendica\Util\Network;
 use Friendica\Util\ParseUrl;
@@ -915,28 +916,23 @@ class Feed
         * Updates the provided last_update parameter if the result comes from the
         * cache or it is empty
         *
-        * @param string  $owner_nick  Nickname of the feed owner
+        * @param array   $owner       owner-view record of the feed owner
         * @param string  $last_update Date of the last update
         * @param integer $max_items   Number of maximum items to fetch
         * @param string  $filter      Feed items filter (activity, posts or comments)
         * @param boolean $nocache     Wether to bypass caching
         *
         * @return string Atom feed
-        * @throws \Friendica\Network\HTTPException\InternalServerErrorException
+        * @throws HTTPException\InternalServerErrorException
         * @throws \ImagickException
         */
-       public static function atom(string $owner_nick, string $last_update, int $max_items = 300, string $filter = 'activity', bool $nocache = false)
+       public static function atom(array $owner, string $last_update, int $max_items = 300, string $filter = 'activity', bool $nocache = false)
        {
                $stamp = microtime(true);
 
-               $owner = User::getOwnerDataByNick($owner_nick);
-               if (!$owner) {
-                       return;
-               }
-
-               $cachekey = 'feed:feed:' . $owner_nick . ':' . $filter . ':' . $last_update;
+               $cachekey = 'feed:feed:' . $owner['nickname'] . ':' . $filter . ':' . $last_update;
 
-               // Display events in the users's timezone
+               // Display events in the user's timezone
                if (strlen($owner['timezone'])) {
                        DI::app()->setTimeZone($owner['timezone']);
                }
index 8d1fec6f0e2c39508e4fc062ae58cd16ebe02f33..b4ce8f79ed6d92e53712a2eace2b02834f64f2a9 100644 (file)
@@ -38,6 +38,7 @@ $profileRoutes = [
        '/photos'                                  => [Module\Profile\Photos::class,       [R::GET         ]],
        '/profile'                                 => [Module\Profile\Profile::class,      [R::GET]],
        '/remote_follow'                           => [Module\Profile\RemoteFollow::class, [R::GET, R::POST]],
+       '/restricted'                              => [Module\Profile\Restricted::class,   [R::GET         ]],
        '/schedule'                                => [Module\Profile\Schedule::class,     [R::GET, R::POST]],
        '/status[/{category}[/{date1}[/{date2}]]]' => [Module\Profile\Status::class,       [R::GET]],
        '/unkmail'                                 => [Module\Profile\UnkMail::class,      [R::GET, R::POST]],
@@ -416,13 +417,8 @@ return [
 
        '/featured/{nickname}'      => [Module\ActivityPub\Featured::class, [R::GET]],
 
-       '/feed'     => [
-               '/{nickname}'          => [Module\Feed::class, [R::GET]],
-               '/{nickname}/posts'    => [Module\Feed::class, [R::GET]],
-               '/{nickname}/comments' => [Module\Feed::class, [R::GET]],
-               '/{nickname}/replies'  => [Module\Feed::class, [R::GET]],
-               '/{nickname}/activity' => [Module\Feed::class, [R::GET]],
-       ],
+       '/feed/{nickname}[/{type:posts|comments|replies|activity}]' => [Module\Feed::class, [R::GET]],
+
        '/feedtest' => [Module\Debug\Feed::class, [R::GET]],
 
        '/fetch'             => [