$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);
if (!DBA::isResult($existing_event)) {
return 0;
}
-
+
if ($existing_event['edited'] === $event['edited']) {
return $event['id'];
}
* 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;
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
'$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,
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;
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);
$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');
use Friendica\BaseModule;
use Friendica\Core\System;
+use Friendica\Model\User;
use Friendica\Module\Response;
+use Friendica\Network\HTTPException;
use Friendica\Protocol\OStatus;
/**
{
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);
}
}
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
* - /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':
$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);
}
}
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'])) {
if (!empty($parent)) {
$pageUid = $parent['uid'];
- $isRemoteContact = $this->session->getRemoteContactID($pageUid);
- if ($isRemoteContact) {
+ if ($this->session->getRemoteContactID($pageUid)) {
$itemUid = $parent['uid'];
}
} else {
}
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);
$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);
$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());
{
$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) {
$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 = '';
}
// 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)) {
--- /dev/null
+<?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.'),
+ ]);
+ }
+}
$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']);
'$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')],
$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.'));
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;
* 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']);
}
'/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]],
'/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' => [