Merge branch '2020.03-rc' of https://github.com/friendica/friendica into 2020.03-rc

This commit is contained in:
Tobias Diekershoff 2020-03-09 06:44:12 +01:00
commit 1f4d371923
14 changed files with 162 additions and 80 deletions

View file

@ -1,6 +1,6 @@
-- ------------------------------------------ -- ------------------------------------------
-- Friendica 2020.03-dev (Dalmatian Bellflower) -- Friendica 2020.03-dev (Dalmatian Bellflower)
-- DB_UPDATE_VERSION 1336 -- DB_UPDATE_VERSION 1337
-- ------------------------------------------ -- ------------------------------------------
@ -948,6 +948,7 @@ CREATE TABLE IF NOT EXISTS `photo` (
`allow_gid` mediumtext COMMENT 'Access Control - list of allowed groups', `allow_gid` mediumtext COMMENT 'Access Control - list of allowed groups',
`deny_cid` mediumtext COMMENT 'Access Control - list of denied contact.id', `deny_cid` mediumtext COMMENT 'Access Control - list of denied contact.id',
`deny_gid` mediumtext COMMENT 'Access Control - list of denied groups', `deny_gid` mediumtext COMMENT 'Access Control - list of denied groups',
`accessible` boolean NOT NULL DEFAULT '0' COMMENT 'Make photo publicly accessible, ignoring permissions',
`backend-class` tinytext COMMENT 'Storage backend class', `backend-class` tinytext COMMENT 'Storage backend class',
`backend-ref` text COMMENT 'Storage backend data reference', `backend-ref` text COMMENT 'Storage backend data reference',
`updated` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', `updated` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '',

View file

@ -186,6 +186,18 @@ function api_register_func($path, $func, $auth = false, $method = API_METHOD_ANY
*/ */
function api_login(App $a) function api_login(App $a)
{ {
// workaround for HTTP-auth in CGI mode
if (!empty($_SERVER['REDIRECT_REMOTE_USER'])) {
$userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6));
if (strlen($userpass)) {
list($name, $password) = explode(':', $userpass);
$_SERVER['PHP_AUTH_USER'] = $name;
$_SERVER['PHP_AUTH_PW'] = $password;
}
}
if (empty($_SERVER['PHP_AUTH_USER'])) {
// Try OAuth when no user is provided
$oauth1 = new FKOAuth1(); $oauth1 = new FKOAuth1();
// login with oauth // login with oauth
try { try {
@ -200,20 +212,9 @@ function api_login(App $a)
var_dump($consumer, $token); var_dump($consumer, $token);
die(); die();
} catch (Exception $e) { } catch (Exception $e) {
Logger::warning(API_LOG_PREFIX . 'error', ['module' => 'api', 'action' => 'login', 'exception' => $e->getMessage()]); Logger::warning(API_LOG_PREFIX . 'OAuth error', ['module' => 'api', 'action' => 'login', 'exception' => $e->getMessage()]);
} }
// workaround for HTTP-auth in CGI mode
if (!empty($_SERVER['REDIRECT_REMOTE_USER'])) {
$userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6));
if (strlen($userpass)) {
list($name, $password) = explode(':', $userpass);
$_SERVER['PHP_AUTH_USER'] = $name;
$_SERVER['PHP_AUTH_PW'] = $password;
}
}
if (empty($_SERVER['PHP_AUTH_USER'])) {
Logger::debug(API_LOG_PREFIX . 'failed', ['module' => 'api', 'action' => 'login', 'parameters' => $_SERVER]); Logger::debug(API_LOG_PREFIX . 'failed', ['module' => 'api', 'action' => 'login', 'parameters' => $_SERVER]);
header('WWW-Authenticate: Basic realm="Friendica"'); header('WWW-Authenticate: Basic realm="Friendica"');
throw new UnauthorizedException("This API requires login"); throw new UnauthorizedException("This API requires login");

View file

@ -319,6 +319,7 @@ function settings_post(App $a)
$hide_friends = (($_POST['hide-friends'] == 1) ? 1: 0); $hide_friends = (($_POST['hide-friends'] == 1) ? 1: 0);
$hidewall = (($_POST['hidewall'] == 1) ? 1: 0); $hidewall = (($_POST['hidewall'] == 1) ? 1: 0);
$unlisted = (($_POST['unlisted'] == 1) ? 1: 0); $unlisted = (($_POST['unlisted'] == 1) ? 1: 0);
$accessiblephotos = (($_POST['accessible-photos'] == 1) ? 1: 0);
$email_textonly = (($_POST['email_textonly'] == 1) ? 1 : 0); $email_textonly = (($_POST['email_textonly'] == 1) ? 1 : 0);
$detailed_notif = (($_POST['detailed_notif'] == 1) ? 1 : 0); $detailed_notif = (($_POST['detailed_notif'] == 1) ? 1 : 0);
@ -417,6 +418,7 @@ function settings_post(App $a)
DI::pConfig()->set(local_user(), 'system', 'email_textonly', $email_textonly); DI::pConfig()->set(local_user(), 'system', 'email_textonly', $email_textonly);
DI::pConfig()->set(local_user(), 'system', 'detailed_notif', $detailed_notif); DI::pConfig()->set(local_user(), 'system', 'detailed_notif', $detailed_notif);
DI::pConfig()->set(local_user(), 'system', 'unlisted', $unlisted); DI::pConfig()->set(local_user(), 'system', 'unlisted', $unlisted);
DI::pConfig()->set(local_user(), 'system', 'accessible-photos', $accessiblephotos);
if ($page_flags == User::PAGE_FLAGS_PRVGROUP) { if ($page_flags == User::PAGE_FLAGS_PRVGROUP) {
$hidewall = 1; $hidewall = 1;
@ -843,6 +845,10 @@ function settings_content(App $a)
'$field' => ['unlisted', DI::l10n()->t('Make public posts unlisted'), DI::pConfig()->get(local_user(), '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.')], '$field' => ['unlisted', DI::l10n()->t('Make public posts unlisted'), DI::pConfig()->get(local_user(), '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 = Renderer::replaceMacros($opt_tpl, [
'$field' => ['accessible-photos', DI::l10n()->t('Make all posted pictures accessible'), DI::pConfig()->get(local_user(), '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 = Renderer::replaceMacros($opt_tpl, [ $blockwall = Renderer::replaceMacros($opt_tpl, [
'$field' => ['blockwall', DI::l10n()->t('Allow friends to post to your profile page?'), (intval($a->user['blockwall']) ? '0' : '1'), DI::l10n()->t('Your contacts may write posts on your profile wall. These posts will be distributed to your contacts')], '$field' => ['blockwall', DI::l10n()->t('Allow friends to post to your profile page?'), (intval($a->user['blockwall']) ? '0' : '1'), DI::l10n()->t('Your contacts may write posts on your profile wall. These posts will be distributed to your contacts')],
]); ]);
@ -957,6 +963,7 @@ function settings_content(App $a)
'$hide_friends' => $hide_friends, '$hide_friends' => $hide_friends,
'$hide_wall' => $hide_wall, '$hide_wall' => $hide_wall,
'$unlisted' => $unlisted, '$unlisted' => $unlisted,
'$accessiblephotos' => $accessiblephotos,
'$unkmail' => $unkmail, '$unkmail' => $unkmail,
'$cntunkmail' => ['cntunkmail', DI::l10n()->t('Maximum private messages per day from unknown people:'), $cntunkmail , DI::l10n()->t("\x28to prevent spam abuse\x29")], '$cntunkmail' => ['cntunkmail', DI::l10n()->t('Maximum private messages per day from unknown people:'), $cntunkmail , DI::l10n()->t("\x28to prevent spam abuse\x29")],

View file

@ -1282,7 +1282,7 @@ class GContact
* @param string $url URL of a profile * @param string $url URL of a profile
* @return void * @return void
*/ */
public static function discoverFollowers(string $url, int $following_gcid = 0, int $follower_gcid = 0) public static function discoverFollowers(string $url)
{ {
$gcontact = DBA::selectFirst('gcontact', ['id', 'last_discovery'], ['nurl' => Strings::normaliseLink(($url))]); $gcontact = DBA::selectFirst('gcontact', ['id', 'last_discovery'], ['nurl' => Strings::normaliseLink(($url))]);
if (!DBA::isResult($gcontact)) { if (!DBA::isResult($gcontact)) {
@ -1296,16 +1296,6 @@ class GContact
$gcid = $gcontact['id']; $gcid = $gcontact['id'];
if (!empty($following_gcid)) {
$fields = ['gcid' => $following_gcid, 'follower-gcid' => $gcid];
Logger::info('Set relation for followed gcontact', $fields);
DBA::update('gfollower', ['deleted' => false], $fields, true);
} elseif (!empty($follower_gcid)) {
$fields = ['gcid' => $gcid, 'follower-gcid' => $follower_gcid];
Logger::info('Set relation for following gcontact', $fields);
DBA::update('gfollower', ['deleted' => false], $fields, true);
}
$apcontact = APContact::getByURL($url); $apcontact = APContact::getByURL($url);
if (!empty($apcontact['followers']) && is_string($apcontact['followers'])) { if (!empty($apcontact['followers']) && is_string($apcontact['followers'])) {
@ -1350,17 +1340,12 @@ class GContact
continue; continue;
} }
$follower_gcid = 0; if (!Network::isUrlBlocked($contact)) {
$following_gcid = 0;
if (in_array($contact, $followers)) {
$following_gcid = $gcid;
} elseif (in_array($contact, $followings)) {
$follower_gcid = $gcid;
}
Logger::info('Discover new AP contact', ['url' => $contact]); Logger::info('Discover new AP contact', ['url' => $contact]);
Worker::add(PRIORITY_LOW, 'UpdateGContact', $contact, '', $following_gcid, $follower_gcid); Worker::add(PRIORITY_LOW, 'UpdateGContact', $contact);
} else {
Logger::info('No discovery, the URL is blocked.', ['url' => $contact]);
}
} }
if (!empty($followers)) { if (!empty($followers)) {
// Delete all followers that aren't undeleted // Delete all followers that aren't undeleted
@ -1395,8 +1380,12 @@ class GContact
if (DBA::exists('gcontact', ['nurl' => Strings::normaliseLink(($entry['value']))])) { if (DBA::exists('gcontact', ['nurl' => Strings::normaliseLink(($entry['value']))])) {
continue; continue;
} }
if (!Network::isUrlBlocked($entry['value'])) {
Logger::info('Discover new PoCo contact', ['url' => $entry['value']]); Logger::info('Discover new PoCo contact', ['url' => $entry['value']]);
Worker::add(PRIORITY_LOW, 'UpdateGContact', $entry['value']); Worker::add(PRIORITY_LOW, 'UpdateGContact', $entry['value']);
} else {
Logger::info('No discovery, the URL is blocked.', ['url' => $entry['value']]);
}
} }
} }
} }

View file

@ -141,7 +141,7 @@ class Photo
* @return boolean|array * @return boolean|array
* @throws \Exception * @throws \Exception
*/ */
public static function getPhoto($resourceid, $scale = 0) public static function getPhoto(string $resourceid, int $scale = 0)
{ {
$r = self::selectFirst(["uid"], ["resource-id" => $resourceid]); $r = self::selectFirst(["uid"], ["resource-id" => $resourceid]);
if (!DBA::isResult($r)) { if (!DBA::isResult($r)) {
@ -150,7 +150,9 @@ class Photo
$uid = $r["uid"]; $uid = $r["uid"];
$sql_acl = Security::getPermissionsSQLByUserId($uid); $accessible = $uid ? DI::pConfig()->get($uid, 'system', 'accessible-photos') : false;
$sql_acl = Security::getPermissionsSQLByUserId($uid, $accessible);
$conditions = ["`resource-id` = ? AND `scale` <= ? " . $sql_acl, $resourceid, $scale]; $conditions = ["`resource-id` = ? AND `scale` <= ? " . $sql_acl, $resourceid, $scale];
$params = ["order" => ["scale" => true]]; $params = ["order" => ["scale" => true]];
@ -656,18 +658,29 @@ class Photo
// Ensure to only modify photos that you own // Ensure to only modify photos that you own
$srch = '<' . intval($original_contact_id) . '>'; $srch = '<' . intval($original_contact_id) . '>';
$condition = [ $condition = ["(`allow_cid` = ? OR `allow_cid` IS NULL) AND
'allow_cid' => $srch, 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '', (`allow_gid` = ? OR `allow_gid` IS NULL) AND
'resource-id' => $image_rid, 'uid' => $uid (`deny_cid` = ? OR `deny_cid` IS NULL) AND
]; (`deny_gid` = ? OR `deny_gid` IS NULL) AND
`resource-id` = ? AND `uid` =?", $srch, '', '', '', $image_rid, $uid];
if (!Photo::exists($condition)) { if (!Photo::exists($condition)) {
continue; continue;
} }
/// @todo Check if $str_contact_allow does contain a public forum. Then set the permissions to public. /**
* @todo Existing permissions need to be mixed with the new ones.
* Otherwise this creates problems with sharing the same picture multiple times
* Also check if $str_contact_allow does contain a public forum.
* Then set the permissions to public.
*/
$fields = ['allow_cid' => $str_contact_allow, 'allow_gid' => $str_group_allow, $fields = ['allow_cid' => $str_contact_allow, 'allow_gid' => $str_group_allow,
'deny_cid' => $str_contact_deny, 'deny_gid' => $str_group_deny]; 'deny_cid' => $str_contact_deny, 'deny_gid' => $str_group_deny];
if (DI::pConfig()->get($uid, 'system', 'accessible-photos')) {
$fields['accessible'] = true;
}
$condition = ['resource-id' => $image_rid, 'uid' => $uid]; $condition = ['resource-id' => $image_rid, 'uid' => $uid];
Logger::info('Set permissions', ['condition' => $condition, 'permissions' => $fields]); Logger::info('Set permissions', ['condition' => $condition, 'permissions' => $fields]);
Photo::update($fields, $condition); Photo::update($fields, $condition);

View file

@ -84,13 +84,13 @@ class Photo extends BaseModule
} }
$photo = MPhoto::getPhoto($photoid, $scale); $photo = MPhoto::getPhoto($photoid, $scale);
if ($photo === false) { if ($photo === false) {
$photo = MPhoto::createPhotoForSystemResource("images/nosign.jpg"); throw new \Friendica\Network\HTTPException\NotFoundException(DI::l10n()->t('The Photo with id %s is not available.', $photoid));
} }
break; break;
} }
if ($photo === false) { if ($photo === false) {
System::httpExit('404', 'Not Found'); throw new \Friendica\Network\HTTPException\NotFoundException();
} }
$cacheable = ($photo["allow_cid"] . $photo["allow_gid"] . $photo["deny_cid"] . $photo["deny_gid"] === "") && (isset($photo["cacheable"]) ? $photo["cacheable"] : true); $cacheable = ($photo["allow_cid"] . $photo["allow_gid"] . $photo["deny_cid"] . $photo["deny_gid"] === "") && (isset($photo["cacheable"]) ? $photo["cacheable"] : true);

View file

@ -87,20 +87,32 @@ class Security
return false; return false;
} }
public static function getPermissionsSQLByUserId($owner_id) /**
* Create a permission string for an element based on the visitor
*
* @param integer $owner_id User ID of the owner of the element
* @param boolean $accessible Should the element be accessible anyway?
* @return string SQL permissions
*/
public static function getPermissionsSQLByUserId(int $owner_id, bool $accessible = false)
{ {
$local_user = local_user(); $local_user = local_user();
$remote_contact = Session::getRemoteContactID($owner_id); $remote_contact = Session::getRemoteContactID($owner_id);
$acc_sql = '';
if ($accessible) {
$acc_sql = ' OR `accessible`';
}
/* /*
* Construct permissions * Construct permissions
* *
* default permissions - anonymous user * default permissions - anonymous user
*/ */
$sql = " AND allow_cid = '' $sql = " AND (allow_cid = ''
AND allow_gid = '' AND allow_gid = ''
AND deny_cid = '' AND deny_cid = ''
AND deny_gid = '' "; AND deny_gid = ''" . $acc_sql . ") ";
/* /*
* Profile owner - everything is visible * Profile owner - everything is visible
@ -123,7 +135,8 @@ class Security
$sql = sprintf( $sql = sprintf(
" AND (NOT (deny_cid REGEXP '<%d>' OR deny_gid REGEXP '%s') " AND (NOT (deny_cid REGEXP '<%d>' OR deny_gid REGEXP '%s')
AND (allow_cid REGEXP '<%d>' OR allow_gid REGEXP '%s' OR (allow_cid = '' AND allow_gid = ''))) ", AND (allow_cid REGEXP '<%d>' OR allow_gid REGEXP '%s'
OR (allow_cid = '' AND allow_gid = ''))" . $acc_sql . ") ",
intval($remote_contact), intval($remote_contact),
DBA::escape($gs), DBA::escape($gs),
intval($remote_contact), intval($remote_contact),

View file

@ -31,10 +31,8 @@ class UpdateGContact
* Update global contact via probe * Update global contact via probe
* @param string $url Global contact url * @param string $url Global contact url
* @param string $command * @param string $command
* @param integer $following_gcid gcontact ID of the contact that is followed by this one
* @param integer $follower_gcid gcontact ID of the contact that is following this one
*/ */
public static function execute(string $url, string $command = '', int $following_gcid = 0, int $follower_gcid = 0) public static function execute(string $url, string $command = '')
{ {
$force = ($command == "force"); $force = ($command == "force");
@ -43,7 +41,7 @@ class UpdateGContact
Logger::info('Updated from probe', ['url' => $url, 'force' => $force, 'success' => $success]); Logger::info('Updated from probe', ['url' => $url, 'force' => $force, 'success' => $success]);
if ($success && DI::config()->get('system', 'gcontact_discovery')) { if ($success && DI::config()->get('system', 'gcontact_discovery')) {
GContact::discoverFollowers($url, $following_gcid, $follower_gcid); GContact::discoverFollowers($url);
} }
} }
} }

View file

@ -51,7 +51,7 @@
use Friendica\Database\DBA; use Friendica\Database\DBA;
if (!defined('DB_UPDATE_VERSION')) { if (!defined('DB_UPDATE_VERSION')) {
define('DB_UPDATE_VERSION', 1336); define('DB_UPDATE_VERSION', 1337);
} }
return [ return [
@ -1051,6 +1051,7 @@ return [
"allow_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed groups"], "allow_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed groups"],
"deny_cid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied contact.id"], "deny_cid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied contact.id"],
"deny_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied groups"], "deny_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied groups"],
"accessible" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Make photo publicly accessible, ignoring permissions"],
"backend-class" => ["type" => "tinytext", "comment" => "Storage backend class"], "backend-class" => ["type" => "tinytext", "comment" => "Storage backend class"],
"backend-ref" => ["type" => "text", "comment" => "Storage backend data reference"], "backend-ref" => ["type" => "text", "comment" => "Storage backend data reference"],
"updated" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""] "updated" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""]

View file

@ -14,10 +14,12 @@
<div style="clear: both;"></div> <div style="clear: both;"></div>
</td> </td>
</tr> </tr>
<tr>
<td>
{{$htmlversion nofilter}}
</td>
</tr>
</tbody> </tbody>
</table> </table>
<p>
{{$htmlversion nofilter}}
</p>
</body> </body>
</html> </html>

View file

@ -1,20 +1,50 @@
<table> <table>
<tbody> <thead>
<tr><td colspan="2" style="padding-top:22px;">{{$preamble nofilter}}</td></tr> <tr>
<td colspan="2" style="padding-top:22px;">
{{$preamble nofilter}}
</td>
</tr>
</thead>
{{if $content_allowed}} {{if $content_allowed}}
<tbody>
{{if $source_photo}} {{if $source_photo}}
<tr> <tr>
<td style="padding-left:22px;padding-top:22px;width:60px;" valign="top" rowspan=3><a href="{{$source_link}}"><img style="border:0px;width:48px;height:48px;" src="{{$source_photo}}"></a></td> <td style="padding-left:22px;padding-top:22px;width:60px;" valign="top" rowspan=3><a href="{{$source_link}}"><img style="border:0px;width:48px;height:48px;" src="{{$source_photo}}"></a></td>
<td style="padding-top:22px;"><a href="{{$source_link}}">{{$source_name}}</a></td> <td style="padding-top:22px;"><a href="{{$source_link}}">{{$source_name}}</a></td>
</tr> </tr>
{{/if}} {{/if}}
<tr><td style="font-weight:bold;padding-bottom:5px;">{{$title}}</td></tr> <tr>
<tr><td style="padding-right:22px;">{{$htmlversion nofilter}}</td></tr> <td style="font-weight:bold;padding-bottom:5px;">{{$title}}</td>
</tr>
<tr>
<td style="padding-right:22px;">{{$htmlversion nofilter}}
</td>
</tr>
{{/if}} {{/if}}
<tr><td colspan="2" style="padding-top:11px;">{{$hsitelink nofilter}}</td></tr> </tbody>
<tr><td colspan="2" style="padding-bottom:11px;">{{$hitemlink nofilter}}</td></tr> <tfoot>
<tr><td></td><td>{{$thanks}}</td></tr> <tr>
<tr><td></td><td>{{$site_admin}}</td></tr> <td colspan="2" style="padding-top:11px;">
</tbody> {{$hsitelink nofilter}}
</td>
</tr>
<tr>
<td colspan="2" style="padding-bottom:11px;">
{{$hitemlink nofilter}}
</td>
</tr>
<tr>
<td></td>
<td>
{{$thanks}}
</td>
</tr>
<tr>
<td></td>
<td>
{{$site_admin}}
</td>
</tr>
</tfoot>
</table> </table>

View file

@ -1,5 +1,28 @@
<table> <table>
<tr><td style="padding-right:22px;">{{$htmlversion nofilter}}</td></tr> <thead>
<tr><td>{{$thanks}}</td></tr> <tr>
<tr><td>{{$site_admin}}</td></tr> <td>
{{$preamble nofilter}}
</td>
</tr>
</thead>
<tbody>
<tr>
<td style="padding-right:22px;">
{{$htmlversion nofilter}}
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>
{{$thanks}}
</td>
</tr>
<tr>
<td>
{{$site_admin}}
</td>
</tr>
</tfoot>
</table> </table>

View file

@ -55,6 +55,8 @@
{{$unlisted nofilter}} {{$unlisted nofilter}}
{{$accessiblephotos nofilter}}
{{$blockwall nofilter}} {{$blockwall nofilter}}
{{$blocktags nofilter}} {{$blocktags nofilter}}

View file

@ -91,6 +91,8 @@
{{$unlisted nofilter}} {{$unlisted nofilter}}
{{$accessiblephotos nofilter}}
{{$blockwall nofilter}} {{$blockwall nofilter}}
{{$blocktags nofilter}} {{$blocktags nofilter}}