Merge remote-tracking branch 'upstream/2020.09-rc' into api-count

This commit is contained in:
Michael 2020-09-07 14:29:02 +00:00
commit 07ccfb212b
38 changed files with 36826 additions and 36563 deletions

4
.gitignore vendored
View file

@ -71,8 +71,8 @@ venv/
/addons /addons
/addon /addon
#ignore .htaccess #ignore base .htaccess
.htaccess /.htaccess
#ignore filesystem storage default path #ignore filesystem storage default path
/storage /storage

View file

@ -1,3 +1,6 @@
# This file is meant to be copied to ".htaccess" on Apache-powered web servers.
# The created .htaccess file can be edited manually and will not be overwritten by Friendica updates.
Options -Indexes Options -Indexes
AddType application/x-java-archive .jar AddType application/x-java-archive .jar
AddType audio/ogg .oga AddType audio/ogg .oga

View file

@ -1 +1 @@
2020.09-dev 2020.09-rc

10
bin/.htaccess Normal file
View file

@ -0,0 +1,10 @@
# This file prevents browser access to Friendica command-line scripts on Apache-powered web servers.
# It isn't meant to be edited manually, please check the base Friendica folder for the .htaccess-dist file instead.
<IfModule authz_host_module>
Require all denied
</IfModule>
<IfModule !authz_host_module>
Order Allow,Deny
Deny from all
</IfModule>

View file

@ -51,6 +51,11 @@
* *
*/ */
if (php_sapi_name() !== 'cli') {
header($_SERVER["SERVER_PROTOCOL"] . ' 403 Forbidden');
exit();
}
use Dice\Dice; use Dice\Dice;
use Friendica\App\Mode; use Friendica\App\Mode;
use Friendica\Util\ExAuth; use Friendica\Util\ExAuth;

View file

@ -20,6 +20,11 @@
* *
*/ */
if (php_sapi_name() !== 'cli') {
header($_SERVER["SERVER_PROTOCOL"] . ' 403 Forbidden');
exit();
}
use Dice\Dice; use Dice\Dice;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;

View file

@ -23,6 +23,11 @@
* This script was taken from http://php.net/manual/en/function.pcntl-fork.php * This script was taken from http://php.net/manual/en/function.pcntl-fork.php
*/ */
if (php_sapi_name() !== 'cli') {
header($_SERVER["SERVER_PROTOCOL"] . ' 403 Forbidden');
exit();
}
use Dice\Dice; use Dice\Dice;
use Friendica\Core\Logger; use Friendica\Core\Logger;
use Friendica\Core\Worker; use Friendica\Core\Worker;

View file

@ -26,6 +26,10 @@
* *
*/ */
if (php_sapi_name() !== 'cli') {
header($_SERVER["SERVER_PROTOCOL"] . ' 403 Forbidden');
exit();
}
if (($_SERVER["argc"] > 1) && isset($_SERVER["argv"][1])) { if (($_SERVER["argc"] > 1) && isset($_SERVER["argv"][1])) {
echo $_SERVER["argv"][1]; echo $_SERVER["argv"][1];

View file

@ -24,6 +24,11 @@
* Usage: php bin/wait-for-connection {HOST} {PORT} [{TIMEOUT}] * Usage: php bin/wait-for-connection {HOST} {PORT} [{TIMEOUT}]
*/ */
if (php_sapi_name() !== 'cli') {
header($_SERVER["SERVER_PROTOCOL"] . ' 403 Forbidden');
exit();
}
$timeout = 60; $timeout = 60;
switch ($argc) { switch ($argc) {
case 4: case 4:

View file

@ -21,6 +21,11 @@
* Starts the background processing * Starts the background processing
*/ */
if (php_sapi_name() !== 'cli') {
header($_SERVER["SERVER_PROTOCOL"] . ' 403 Forbidden');
exit();
}
use Dice\Dice; use Dice\Dice;
use Friendica\App; use Friendica\App;
use Friendica\Core\Update; use Friendica\Core\Update;

View file

@ -38,7 +38,7 @@ use Friendica\Util\DateTimeFormat;
define('FRIENDICA_PLATFORM', 'Friendica'); define('FRIENDICA_PLATFORM', 'Friendica');
define('FRIENDICA_CODENAME', 'Red Hot Poker'); define('FRIENDICA_CODENAME', 'Red Hot Poker');
define('FRIENDICA_VERSION', '2020.09-dev'); define('FRIENDICA_VERSION', '2020.09-rc');
define('DFRN_PROTOCOL_VERSION', '2.23'); define('DFRN_PROTOCOL_VERSION', '2.23');
define('NEW_UPDATE_ROUTINE_VERSION', 1170); define('NEW_UPDATE_ROUTINE_VERSION', 1170);

View file

@ -509,7 +509,8 @@ function notification($params)
Logger::log('sending notification email'); Logger::log('sending notification email');
if (isset($params['parent']) && (intval($params['parent']) != 0)) { if (isset($params['parent']) && (intval($params['parent']) != 0)) {
$id_for_parent = $params['parent'] . "@" . $hostname; $parent = Item::selectFirst(['guid'], ['id' => $params['parent']]);
$message_id = "<" . $parent['guid'] . "@" . gethostname() . ">";
// Is this the first email notification for this parent item and user? // Is this the first email notification for this parent item and user?
if (!DBA::exists('notify-threads', ['master-parent-item' => $params['parent'], 'receiver-uid' => $params['uid']])) { if (!DBA::exists('notify-threads', ['master-parent-item' => $params['parent'], 'receiver-uid' => $params['uid']])) {
@ -520,13 +521,13 @@ function notification($params)
'receiver-uid' => $params['uid'], 'parent-item' => 0]; 'receiver-uid' => $params['uid'], 'parent-item' => 0];
DBA::insert('notify-threads', $fields); DBA::insert('notify-threads', $fields);
$additional_mail_header .= "Message-ID: <${id_for_parent}>\n"; $additional_mail_header .= "Message-ID: " . $message_id . "\n";
$log_msg = "include/enotify: No previous notification found for this parent:\n" . $log_msg = "include/enotify: No previous notification found for this parent:\n" .
" parent: ${params['parent']}\n" . " uid : ${params['uid']}\n"; " parent: ${params['parent']}\n" . " uid : ${params['uid']}\n";
Logger::log($log_msg, Logger::DEBUG); Logger::log($log_msg, Logger::DEBUG);
} else { } else {
// If not, just "follow" the thread. // If not, just "follow" the thread.
$additional_mail_header .= "References: <${id_for_parent}>\nIn-Reply-To: <${id_for_parent}>\n"; $additional_mail_header .= "References: " . $message_id . "\nIn-Reply-To: " . $message_id . "\n";
Logger::log("There's already a notification for this parent.", Logger::DEBUG); Logger::log("There's already a notification for this parent.", Logger::DEBUG);
} }
} }

View file

@ -141,4 +141,9 @@ server {
location ~ /\. { location ~ /\. {
deny all; deny all;
} }
# deny access to the CLI scripts
location ^~ /bin {
deny all;
}
} }

View file

@ -669,10 +669,18 @@ class DBA
*/ */
public static function mergeConditions(array ...$conditions) public static function mergeConditions(array ...$conditions)
{ {
if (count($conditions) == 1) {
return current($conditions);
}
$conditionStrings = []; $conditionStrings = [];
$result = []; $result = [];
foreach ($conditions as $key => $condition) { foreach ($conditions as $key => $condition) {
if (!$condition) {
continue;
}
$condition = self::collapseCondition($condition); $condition = self::collapseCondition($condition);
$conditionStrings[] = array_shift($condition); $conditionStrings[] = array_shift($condition);

View file

@ -320,13 +320,18 @@ class APContact
$apcontact['updated'] = DateTimeFormat::utcNow(); $apcontact['updated'] = DateTimeFormat::utcNow();
DBA::update('apcontact', $apcontact, ['url' => $url], true);
// We delete the old entry when the URL is changed // We delete the old entry when the URL is changed
if (($url != $apcontact['url']) && DBA::exists('apcontact', ['url' => $url]) && DBA::exists('apcontact', ['url' => $apcontact['url']])) { if ($url != $apcontact['url']) {
Logger::info('Delete changed profile url', ['old' => $url, 'new' => $apcontact['url']]);
DBA::delete('apcontact', ['url' => $url]); DBA::delete('apcontact', ['url' => $url]);
} }
if (DBA::exists('apcontact', ['url' => $apcontact['url']])) {
DBA::update('apcontact', $apcontact, ['url' => $apcontact['url']]);
} else {
DBA::replace('apcontact', $apcontact);
}
Logger::info('Updated profile', ['url' => $url]); Logger::info('Updated profile', ['url' => $url]);
return $apcontact; return $apcontact;

View file

@ -201,19 +201,7 @@ class Item
return []; return [];
} }
if (empty($condition) || !is_array($condition)) { $condition = DBA::mergeConditions(['iid' => $pinned], $condition);
$condition = ['iid' => $pinned];
} else {
reset($condition);
$first_key = key($condition);
if (!is_int($first_key)) {
$condition['iid'] = $pinned;
} else {
$values_string = substr(str_repeat("?, ", count($pinned)), 0, -2);
$condition[0] = '(' . $condition[0] . ") AND `iid` IN (" . $values_string . ")";
$condition = array_merge($condition, $pinned);
}
}
return self::selectThreadForUser($uid, $selected, $condition, $params); return self::selectThreadForUser($uid, $selected, $condition, $params);
} }

View file

@ -51,8 +51,8 @@ class UserItem
*/ */
public static function setNotification(int $iid) public static function setNotification(int $iid)
{ {
$fields = ['id', 'uri-id', 'uid', 'body', 'parent', 'gravity', 'tag', $fields = ['id', 'uri-id', 'parent-uri-id', 'uid', 'body', 'parent', 'gravity', 'tag',
'contact-id', 'thr-parent', 'parent-uri', 'author-id', 'verb']; 'private', 'contact-id', 'thr-parent', 'parent-uri', 'author-id', 'verb'];
$item = Item::selectFirst($fields, ['id' => $iid, 'origin' => false]); $item = Item::selectFirst($fields, ['id' => $iid, 'origin' => false]);
if (!DBA::isResult($item)) { if (!DBA::isResult($item)) {
return; return;
@ -63,14 +63,26 @@ class UserItem
return; return;
} }
// fetch all users in the thread if ($item['uid'] == 0) {
$uids = [];
} else {
// Always include the item user
$uids = [$item['uid']];
}
// Add every user who participated so far in this thread
// This can only happen with participations on global items. (means: uid = 0)
$users = DBA::p("SELECT DISTINCT(`contact`.`uid`) FROM `item` $users = DBA::p("SELECT DISTINCT(`contact`.`uid`) FROM `item`
INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND `contact`.`uid` != 0 INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND `contact`.`uid` != 0
WHERE `parent` IN (SELECT `parent` FROM `item` WHERE `id`=?)", $iid); WHERE `parent` IN (SELECT `parent` FROM `item` WHERE `id`=?)", $iid);
while ($user = DBA::fetch($users)) { while ($user = DBA::fetch($users)) {
self::setNotificationForUser($item, $user['uid']); $uids[] = $user['uid'];
} }
DBA::close($users); DBA::close($users);
foreach (array_unique($uids) as $uid) {
self::setNotificationForUser($item, $uid);
}
} }
/** /**

View file

@ -44,7 +44,7 @@ class Contact extends BaseAdmin
$contact_id = Model\Contact::getIdForURL($contact_url); $contact_id = Model\Contact::getIdForURL($contact_url);
if ($contact_id) { if ($contact_id) {
Model\Contact::block($contact_id, $block_reason); Model\Contact::block($contact_id, $block_reason);
notice(DI::l10n()->t('The contact has been blocked from the node')); info(DI::l10n()->t('The contact has been blocked from the node'));
} else { } else {
notice(DI::l10n()->t('Could not find any contact entry for this URL (%s)', $contact_url)); notice(DI::l10n()->t('Could not find any contact entry for this URL (%s)', $contact_url));
} }
@ -54,7 +54,7 @@ class Contact extends BaseAdmin
foreach ($contacts as $uid) { foreach ($contacts as $uid) {
Model\Contact::unblock($uid); Model\Contact::unblock($uid);
} }
notice(DI::l10n()->tt('%s contact unblocked', '%s contacts unblocked', count($contacts))); info(DI::l10n()->tt('%s contact unblocked', '%s contacts unblocked', count($contacts)));
} }
DI::baseUrl()->redirect('admin/blocklist/contact'); DI::baseUrl()->redirect('admin/blocklist/contact');

View file

@ -58,14 +58,14 @@ class Users extends BaseAdmin
foreach ($users as $uid) { foreach ($users as $uid) {
User::block($uid); User::block($uid);
} }
notice(DI::l10n()->tt('%s user blocked', '%s users blocked', count($users))); info(DI::l10n()->tt('%s user blocked', '%s users blocked', count($users)));
} }
if (!empty($_POST['page_users_unblock'])) { if (!empty($_POST['page_users_unblock'])) {
foreach ($users as $uid) { foreach ($users as $uid) {
User::block($uid, false); User::block($uid, false);
} }
notice(DI::l10n()->tt('%s user unblocked', '%s users unblocked', count($users))); info(DI::l10n()->tt('%s user unblocked', '%s users unblocked', count($users)));
} }
if (!empty($_POST['page_users_delete'])) { if (!empty($_POST['page_users_delete'])) {
@ -77,21 +77,21 @@ class Users extends BaseAdmin
} }
} }
notice(DI::l10n()->tt('%s user deleted', '%s users deleted', count($users))); info(DI::l10n()->tt('%s user deleted', '%s users deleted', count($users)));
} }
if (!empty($_POST['page_users_approve'])) { if (!empty($_POST['page_users_approve'])) {
foreach ($pending as $hash) { foreach ($pending as $hash) {
User::allow($hash); User::allow($hash);
} }
notice(DI::l10n()->tt('%s user approved', '%s users approved', count($pending))); info(DI::l10n()->tt('%s user approved', '%s users approved', count($pending)));
} }
if (!empty($_POST['page_users_deny'])) { if (!empty($_POST['page_users_deny'])) {
foreach ($pending as $hash) { foreach ($pending as $hash) {
User::deny($hash); User::deny($hash);
} }
notice(DI::l10n()->tt('%s registration revoked', '%s registrations revoked', count($pending))); info(DI::l10n()->tt('%s registration revoked', '%s registrations revoked', count($pending)));
} }
DI::baseUrl()->redirect('admin/users'); DI::baseUrl()->redirect('admin/users');

View file

@ -131,7 +131,7 @@ class Group extends BaseModule
throw new \Exception(DI::l10n()->t('Bad request.'), 400); throw new \Exception(DI::l10n()->t('Bad request.'), 400);
} }
notice($message); info($message);
System::jsonExit(['status' => 'OK', 'message' => $message]); System::jsonExit(['status' => 'OK', 'message' => $message]);
} catch (\Exception $e) { } catch (\Exception $e) {
notice($e->getMessage()); notice($e->getMessage());

View file

@ -119,7 +119,7 @@ class Invite extends BaseModule
} }
} }
notice(DI::l10n()->tt('%d message sent.', '%d messages sent.', $total)); info(DI::l10n()->tt('%d message sent.', '%d messages sent.', $total));
} }
public static function content(array $parameters = []) public static function content(array $parameters = [])

View file

@ -232,7 +232,18 @@ class Status extends BaseProfile
$items = DBA::toArray($items_stmt); $items = DBA::toArray($items_stmt);
if ($pager->getStart() == 0 && !empty($a->profile['uid'])) { if ($pager->getStart() == 0 && !empty($a->profile['uid'])) {
$pinned_items = Item::selectPinned($a->profile['uid'], ['uri', 'pinned']); $condition = ['private' => [Item::PUBLIC, Item::UNLISTED]];
if (remote_user()) {
$permissionSets = DI::permissionSet()->selectByContactId(remote_user(), $a->profile['uid']);
if (!empty($permissionSets)) {
$condition = ['psid' => array_merge($permissionSets->column('id'),
[DI::permissionSet()->getIdFromACL($a->profile['uid'], '', '', '', '')])];
}
} elseif ($a->profile['uid'] == local_user()) {
$condition = [];
}
$pinned_items = Item::selectPinned($a->profile['uid'], ['uri', 'pinned'], $condition);
$pinned = Item::inArray($pinned_items); $pinned = Item::inArray($pinned_items);
$items = array_merge($items, $pinned); $items = array_merge($items, $pinned);
} }

View file

@ -57,7 +57,7 @@ class Recovery extends BaseModule
if (RecoveryCode::existsForUser(local_user(), $recovery_code)) { if (RecoveryCode::existsForUser(local_user(), $recovery_code)) {
RecoveryCode::markUsedForUser(local_user(), $recovery_code); RecoveryCode::markUsedForUser(local_user(), $recovery_code);
Session::set('2fa', true); Session::set('2fa', true);
notice(DI::l10n()->t('Remaining recovery codes: %d', RecoveryCode::countValidForUser(local_user()))); info(DI::l10n()->t('Remaining recovery codes: %d', RecoveryCode::countValidForUser(local_user())));
DI::auth()->setForUser($a, $a->user, true, true); DI::auth()->setForUser($a, $a->user, true, true);
} else { } else {

View file

@ -187,7 +187,7 @@ class Crop extends BaseSettings
Worker::add(PRIORITY_LOW, 'Directory', Session::get('my_url')); Worker::add(PRIORITY_LOW, 'Directory', Session::get('my_url'));
} }
notice(DI::l10n()->t('Profile picture successfully updated.')); info(DI::l10n()->t('Profile picture successfully updated.'));
DI::baseUrl()->redirect('profile/' . DI::app()->user['nickname']); DI::baseUrl()->redirect('profile/' . DI::app()->user['nickname']);
} }

View file

@ -74,13 +74,13 @@ class AppSpecific extends BaseSettings
DI::baseUrl()->redirect('settings/2fa/app_specific?t=' . self::getFormSecurityToken('settings_2fa_password')); DI::baseUrl()->redirect('settings/2fa/app_specific?t=' . self::getFormSecurityToken('settings_2fa_password'));
} else { } else {
self::$appSpecificPassword = AppSpecificPassword::generateForUser(local_user(), $_POST['description'] ?? ''); self::$appSpecificPassword = AppSpecificPassword::generateForUser(local_user(), $_POST['description'] ?? '');
notice(DI::l10n()->t('New app-specific password generated.')); info(DI::l10n()->t('New app-specific password generated.'));
} }
break; break;
case 'revoke_all' : case 'revoke_all' :
AppSpecificPassword::deleteAllForUser(local_user()); AppSpecificPassword::deleteAllForUser(local_user());
notice(DI::l10n()->t('App-specific passwords successfully revoked.')); info(DI::l10n()->t('App-specific passwords successfully revoked.'));
DI::baseUrl()->redirect('settings/2fa/app_specific?t=' . self::getFormSecurityToken('settings_2fa_password')); DI::baseUrl()->redirect('settings/2fa/app_specific?t=' . self::getFormSecurityToken('settings_2fa_password'));
break; break;
} }
@ -90,7 +90,7 @@ class AppSpecific extends BaseSettings
self::checkFormSecurityTokenRedirectOnError('settings/2fa/app_specific', 'settings_2fa_app_specific'); self::checkFormSecurityTokenRedirectOnError('settings/2fa/app_specific', 'settings_2fa_app_specific');
if (AppSpecificPassword::deleteForUser(local_user(), $_POST['revoke_id'])) { if (AppSpecificPassword::deleteForUser(local_user(), $_POST['revoke_id'])) {
notice(DI::l10n()->t('App-specific password successfully revoked.')); info(DI::l10n()->t('App-specific password successfully revoked.'));
} }
DI::baseUrl()->redirect('settings/2fa/app_specific?t=' . self::getFormSecurityToken('settings_2fa_password')); DI::baseUrl()->redirect('settings/2fa/app_specific?t=' . self::getFormSecurityToken('settings_2fa_password'));

View file

@ -64,7 +64,7 @@ class Index extends BaseSettings
DI::pConfig()->delete(local_user(), '2fa', 'verified'); DI::pConfig()->delete(local_user(), '2fa', 'verified');
Session::remove('2fa'); Session::remove('2fa');
notice(DI::l10n()->t('Two-factor authentication successfully disabled.')); info(DI::l10n()->t('Two-factor authentication successfully disabled.'));
DI::baseUrl()->redirect('settings/2fa'); DI::baseUrl()->redirect('settings/2fa');
} }
break; break;

View file

@ -63,7 +63,7 @@ class Recovery extends BaseSettings
if ($_POST['action'] == 'regenerate') { if ($_POST['action'] == 'regenerate') {
RecoveryCode::regenerateForUser(local_user()); RecoveryCode::regenerateForUser(local_user());
notice(DI::l10n()->t('New recovery codes successfully generated.')); info(DI::l10n()->t('New recovery codes successfully generated.'));
DI::baseUrl()->redirect('settings/2fa/recovery?t=' . self::getFormSecurityToken('settings_2fa_password')); DI::baseUrl()->redirect('settings/2fa/recovery?t=' . self::getFormSecurityToken('settings_2fa_password'));
} }
} }

View file

@ -75,7 +75,7 @@ class Verify extends BaseSettings
DI::pConfig()->set(local_user(), '2fa', 'verified', true); DI::pConfig()->set(local_user(), '2fa', 'verified', true);
Session::set('2fa', true); Session::set('2fa', true);
notice(DI::l10n()->t('Two-factor authentication successfully activated.')); info(DI::l10n()->t('Two-factor authentication successfully activated.'));
DI::baseUrl()->redirect('settings/2fa'); DI::baseUrl()->redirect('settings/2fa');
} else { } else {
@ -132,7 +132,7 @@ class Verify extends BaseSettings
'$help_label' => DI::l10n()->t('Help'), '$help_label' => DI::l10n()->t('Help'),
'$message' => DI::l10n()->t('<p>Please scan this QR Code with your authenticator app and submit the provided code.</p>'), '$message' => DI::l10n()->t('<p>Please scan this QR Code with your authenticator app and submit the provided code.</p>'),
'$qrcode_image' => $qrcode_image, '$qrcode_image' => $qrcode_image,
'$qrcode_url_message' => DI::l10n()->t('<p>Or you can open the following URL in your mobile devicde:</p><p><a href="%s">%s</a></p>', $otpauthUrl, $shortOtpauthUrl), '$qrcode_url_message' => DI::l10n()->t('<p>Or you can open the following URL in your mobile device:</p><p><a href="%s">%s</a></p>', $otpauthUrl, $shortOtpauthUrl),
'$manual_message' => $manual_message, '$manual_message' => $manual_message,
'$company' => $company, '$company' => $company,
'$holder' => $holder, '$holder' => $holder,

View file

@ -93,15 +93,17 @@ class Probe
"following", "followers", "inbox", "outbox", "sharedinbox", "following", "followers", "inbox", "outbox", "sharedinbox",
"priority", "network", "pubkey", "manually-approve", "baseurl", "gsid"]; "priority", "network", "pubkey", "manually-approve", "baseurl", "gsid"];
$numeric_fields = ["gsid", "hide", "account-type", "manually-approve"];
$newdata = []; $newdata = [];
foreach ($fields as $field) { foreach ($fields as $field) {
if (isset($data[$field])) { if (isset($data[$field])) {
if (in_array($field, ["gsid", "hide", "account-type", "manually-approve"])) { if (in_array($field, $numeric_fields)) {
$newdata[$field] = (int)$data[$field]; $newdata[$field] = (int)$data[$field];
} else { } else {
$newdata[$field] = $data[$field]; $newdata[$field] = $data[$field];
} }
} elseif ($field != "gsid") { } elseif (!in_array($field, $numeric_fields)) {
$newdata[$field] = ""; $newdata[$field] = "";
} else { } else {
$newdata[$field] = null; $newdata[$field] = null;

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff