Merge remote-tracking branch 'upstream/develop' into server-detection

This commit is contained in:
Michael 2022-07-16 12:44:21 +00:00
commit 8b7cb5d9ef
328 changed files with 13242 additions and 10211 deletions

View file

@ -134,6 +134,7 @@ class Site extends BaseAdmin
$temppath = (!empty($_POST['temppath']) ? trim($_POST['temppath']) : '');
$singleuser = (!empty($_POST['singleuser']) ? trim($_POST['singleuser']) : '');
$only_tag_search = !empty($_POST['only_tag_search']);
$compute_group_counts = !empty($_POST['compute_group_counts']);
$check_new_version_url = (!empty($_POST['check_new_version_url']) ? trim($_POST['check_new_version_url']) : 'none');
$worker_queues = (!empty($_POST['worker_queues']) ? intval($_POST['worker_queues']) : 10);
@ -304,6 +305,7 @@ class Site extends BaseAdmin
DI::config()->set('system', 'temppath', $temppath);
DI::config()->set('system', 'only_tag_search' , $only_tag_search);
DI::config()->set('system', 'compute_group_counts', $compute_group_counts);
DI::config()->set('system', 'worker_queues' , $worker_queues);
DI::config()->set('system', 'worker_fastlane' , $worker_fastlane);
@ -534,6 +536,7 @@ class Site extends BaseAdmin
'$max_display_comments' => ['max_display_comments', DI::l10n()->t('Maximum numbers of comments per post on the display page'), DI::config()->get('system', 'max_display_comments'), DI::l10n()->t('How many comments should be shown on the single view for each post? Default value is 1000.')],
'$temppath' => ['temppath', DI::l10n()->t('Temp path'), DI::config()->get('system', 'temppath'), DI::l10n()->t('If you have a restricted system where the webserver can\'t access the system temp path, enter another path here.')],
'$only_tag_search' => ['only_tag_search', DI::l10n()->t('Only search in tags'), DI::config()->get('system', 'only_tag_search'), DI::l10n()->t('On large systems the text search can slow down the system extremely.')],
'$compute_group_counts' => ['compute_group_counts', DI::l10n()->t('Generate counts per contact group when calculating network count'), DI::config()->get('system', 'compute_group_counts'), DI::l10n()->t('On systems with users that heavily use contact groups the query can be very expensive.')],
'$worker_queues' => ['worker_queues', DI::l10n()->t('Maximum number of parallel workers'), DI::config()->get('system', 'worker_queues'), DI::l10n()->t('On shared hosters set this to %d. On larger systems, values of %d are great. Default value is %d.', 5, 20, 10)],
'$worker_fastlane' => ['worker_fastlane', DI::l10n()->t('Enable fastlane'), DI::config()->get('system', 'worker_fastlane'), DI::l10n()->t('When enabed, the fastlane mechanism starts an additional worker if processes with higher priority are blocked by processes of lower priority.')],

View file

@ -54,12 +54,12 @@ class Summary extends BaseAdmin
$warningtext[] = DI::l10n()->t('Template engine (%s) error: %s', $templateEngine::$name, $error);
}
if (DBA::count(['information_schema' => 'tables'], ['engine' => 'myisam', 'table_schema' => DBA::databaseName()])) {
if (DBA::count('information_schema.tables', ['engine' => 'myisam', 'table_schema' => DBA::databaseName()])) {
$warningtext[] = DI::l10n()->t('Your DB still runs with MyISAM tables. You should change the engine type to InnoDB. As Friendica will use InnoDB only features in the future, you should change this! See <a href="%s">here</a> for a guide that may be helpful converting the table engines. You may also use the command <tt>php bin/console.php dbstructure toinnodb</tt> of your Friendica installation for an automatic conversion.<br />', 'https://dev.mysql.com/doc/refman/5.7/en/converting-tables-to-innodb.html');
}
// are there InnoDB tables in Antelope in the DB? If so, trigger a warning message
if (DBA::count(['information_schema' => 'tables'], ['ENGINE' => 'InnoDB', 'ROW_FORMAT' => ['COMPACT', 'REDUNDANT'], 'table_schema' => DBA::databaseName()])) {
if (DBA::count('information_schema.tables', ['ENGINE' => 'InnoDB', 'ROW_FORMAT' => ['COMPACT', 'REDUNDANT'], 'table_schema' => DBA::databaseName()])) {
$warningtext[] = DI::l10n()->t('Your DB still runs with InnoDB tables in the Antelope file format. You should change the file format to Barracuda. Friendica is using features that are not provided by the Antelope format. See <a href="%s">here</a> for a guide that may be helpful converting the table engines. You may also use the command <tt>php bin/console.php dbstructure toinnodb</tt> of your Friendica installation for an automatic conversion.<br />', 'https://dev.mysql.com/doc/refman/5.7/en/innodb-file-format.html');
}

View file

@ -203,7 +203,7 @@ class Statuses extends BaseApi
if (!empty($request['scheduled_at'])) {
$item['guid'] = Item::guid($item, true);
$item['uri'] = Item::newURI($item['uid'], $item['guid']);
$item['uri'] = Item::newURI($item['guid']);
$id = Post\Delayed::add($item['uri'], $item, PRIORITY_HIGH, Post\Delayed::PREPARED, $request['scheduled_at']);
if (empty($id)) {
DI::mstdnError()->InternalError();

View file

@ -43,7 +43,10 @@ require_once 'boot.php';
abstract class BaseAdmin extends BaseModule
{
/**
* Checks admin access and throws exceptions if not logged-in administrator
*
* @param bool $interactive
* @return void
* @throws HTTPException\ForbiddenException
* @throws HTTPException\InternalServerErrorException
*/

View file

@ -48,7 +48,7 @@ class BaseSettings extends BaseModule
'label' => DI::l10n()->t('Two-factor authentication'),
'url' => 'settings/2fa',
'selected' => ((DI::args()->getArgc() > 1) && (DI::args()->getArgv()[1] === '2fa') ? 'active' : ''),
'accesskey' => 'o',
'accesskey' => '2',
];
$tabs[] = [

View file

@ -186,7 +186,7 @@ class Contact extends BaseModule
$follow_widget = Widget::follow();
}
$account_widget = Widget::accounttypes($_SERVER['REQUEST_URI'], $accounttype);
$account_widget = Widget::accountTypes($_SERVER['REQUEST_URI'], $accounttype);
$networks_widget = Widget::networks($_SERVER['REQUEST_URI'], $nets);
$rel_widget = Widget::contactRels($_SERVER['REQUEST_URI'], $rel);
$groups_widget = Widget::groups($_SERVER['REQUEST_URI'], $group);

View file

@ -141,7 +141,7 @@ class Contacts extends BaseModule
'$paginate' => $pager->renderFull($total),
]);
DI::page()['aside'] .= Widget::accounttypes($_SERVER['REQUEST_URI'], $accounttype);
DI::page()['aside'] .= Widget::accountTypes($_SERVER['REQUEST_URI'], $accounttype);
return $o;
}

View file

@ -82,7 +82,7 @@ class Poke extends BaseModule
$actor = Contact::getById($a->getContactId());
$uri = Model\Item::newURI($uid);
$uri = Model\Item::newURI();
$arr = [];

View file

@ -475,7 +475,10 @@ class Profile extends BaseModule
}
/**
* Updates contact from probing
*
* @param int $contact_id Id of the contact with uid != 0
* @return void
* @throws HTTPException\InternalServerErrorException
* @throws \ImagickException
*/

View file

@ -90,7 +90,7 @@ class Community extends BaseModule
Nav::setSelected('community');
DI::page()['aside'] .= Widget::accounttypes('community/' . self::$content, self::$accountTypeString);
DI::page()['aside'] .= Widget::accountTypes('community/' . self::$content, self::$accountTypeString);
if (local_user() && DI::config()->get('system', 'community_no_sharer')) {
$path = self::$content;

View file

@ -86,13 +86,13 @@ class Network extends BaseModule
$module = 'network';
DI::page()['aside'] .= Widget::accounttypes($module, self::$accountTypeString);
DI::page()['aside'] .= Widget::accountTypes($module, self::$accountTypeString);
DI::page()['aside'] .= Group::sidebarWidget($module, $module . '/group', 'standard', self::$groupId);
DI::page()['aside'] .= ForumManager::widget($module . '/forum', local_user(), self::$forumContactId);
DI::page()['aside'] .= Widget::postedByYear($module . '/archive', local_user(), false);
DI::page()['aside'] .= Widget::networks($module, !self::$forumContactId ? self::$network : '');
DI::page()['aside'] .= Widget\SavedSearches::getHTML(DI::args()->getQueryString());
DI::page()['aside'] .= Widget::fileAs('filed', null);
DI::page()['aside'] .= Widget::fileAs('filed', '');
$arr = ['query' => DI::args()->getQueryString()];
Hook::callAll('network_content_init', $arr);

View file

@ -59,12 +59,13 @@ class Notify extends BaseModule
}
}
private static function dispatchPublic($postdata)
private static function dispatchPublic(array $postdata)
{
$msg = Diaspora::decodeRaw($postdata, '', true);
if (!$msg) {
if (!is_array($msg)) {
// We have to fail silently to be able to hand it over to the salmon parser
return false;
Logger::warning('Diaspora::decodeRaw() has failed for some reason.');
return;
}
// Fetch the corresponding public contact
@ -88,10 +89,10 @@ class Notify extends BaseModule
System::xmlExit($ret, 'Done');
}
private static function dispatchPrivate($user, $postdata)
private static function dispatchPrivate(array $user, string $postdata)
{
$msg = Diaspora::decodeRaw($postdata, $user['prvkey'] ?? '');
if (!$msg) {
if (!is_array($msg)) {
System::xmlExit(4, 'Unable to parse message');
}

View file

@ -34,6 +34,6 @@ class Poll extends BaseModule
protected function rawContent(array $request = [])
{
$last_update = $request['last_update'] ?? '';
System::httpExit(OStatus::feed($this->parameters['nickname'], $last_update, 10), Response::TYPE_ATOM);
System::httpExit(OStatus::feed($this->parameters['nickname'], $last_update, 10) ?? '', Response::TYPE_ATOM);
}
}

View file

@ -123,7 +123,7 @@ class ActivityPubConversion extends BaseModule
'content' => visible_whitespace(var_export($object_data, true))
];
$item = ActivityPub\Processor::createItem($object_data);
$item = ActivityPub\Processor::createItem(new ActivityPub\FetchQueue(), $object_data);
$results[] = [
'title' => DI::l10n()->t('Result Item'),

View file

@ -112,7 +112,7 @@ class Directory extends BaseModule
*
* @throws \Exception
*/
public static function formatEntry(array $contact, $photo_size = 'photo')
public static function formatEntry(array $contact, string $photo_size = 'photo'): array
{
$itemurl = (($contact['addr'] != "") ? $contact['addr'] : $contact['url']);
@ -166,7 +166,7 @@ class Directory extends BaseModule
'img_hover' => $contact['name'],
'name' => $contact['name'],
'details' => $details,
'account_type' => Model\Contact::getAccountType($contact['contact-type']),
'account_type' => Model\Contact::getAccountType($contact['contact-type'] ?? 0),
'profile' => $profile,
'location' => $location_e,
'tags' => $contact['pub_keywords'],

View file

@ -21,14 +21,29 @@
namespace Friendica\Module\HTTPException;
use Friendica\App;
use Friendica\BaseModule;
use Friendica\Core\L10n;
use Friendica\Core\System;
use Friendica\DI;
use Friendica\Module\Response;
use Friendica\Network\HTTPException;
use Friendica\Util\Profiler;
use Psr\Http\Message\ResponseInterface;
use Psr\Log\LoggerInterface;
class PageNotFound extends BaseModule
{
/** @var string */
private $remoteAddress;
public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, App\Request $request, array $server, array $parameters = [])
{
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->remoteAddress = $request->getRemoteAddress();
}
protected function content(array $request = []): string
{
throw new HTTPException\NotFoundException(DI::l10n()->t('Page not found.'));
@ -58,7 +73,7 @@ class PageNotFound extends BaseModule
$this->logger->debug('index.php: page not found.', [
'request_uri' => $this->server['REQUEST_URI'],
'address' => $this->server['REMOTE_ADDR'],
'address' => $this->remoteAddress,
'query' => $this->server['QUERY_STRING']
]);

View file

@ -170,7 +170,7 @@ class Install extends BaseModule
return;
}
$this->installer->installDatabase($configCache->get('system', 'basepath'));
$this->installer->installDatabase();
// install allowed themes to register theme hooks
// this is same as "Reload active theme" in /admin/themes
@ -363,7 +363,7 @@ class Install extends BaseModule
* @return string The text for the next steps
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
private function whatNext()
private function whatNext(): string
{
$baseurl = $this->baseUrl->get();
return
@ -383,6 +383,7 @@ class Install extends BaseModule
* @param string $cat The category of the setting
* @param string $key The key of the setting
* @param null|string $default The default value
* @return void
*/
private function checkSetting(Cache $configCache, array $post, string $cat, string $key, ?string $default = null)
{

View file

@ -45,7 +45,7 @@ class Maintenance extends BaseModule
$exception = new HTTPException\ServiceUnavailableException($reason);
header($_SERVER["SERVER_PROTOCOL"] . ' ' . $exception->getCode() . ' ' . DI::l10n()->t('System down for maintenance'));
header($_SERVER['SERVER_PROTOCOL'] . ' ' . $exception->getCode() . ' ' . DI::l10n()->t('System down for maintenance'));
$tpl = Renderer::getMarkupTemplate('exception.tpl');

View file

@ -131,7 +131,7 @@ class NoScrape extends BaseModule
$profile_fields = ['about', 'locality', 'region', 'postal-code', 'country-name', 'xmpp', 'matrix'];
foreach ($profile_fields as $field) {
if (!empty($owner[$field])) {
$json_info["$field"] = $owner[$field];
$json_info[$field] = $owner[$field];
}
}

View file

@ -113,7 +113,8 @@ class Ping extends BaseModule
}
DBA::close($items);
if ($network_count) {
$compute_group_counts = DI::config()->get('system','compute_group_counts');
if ($network_count && $compute_group_counts) {
// Find out how unseen network posts are spread across groups
$group_counts = Group::countUnseen();
if (DBA::isResult($group_counts)) {

View file

@ -50,9 +50,12 @@ class OpenSearch extends BaseModule
'@attributes' => [
'xmlns' => 'http://a9.com/-/spec/opensearch/1.1',
],
'ShortName' => "Friendica $hostname",
'Description' => "Search in Friendica $hostname",
'Contact' => 'https://github.com/friendica/friendica/issues',
'ShortName' => "Friendica $hostname",
'Description' => "Search in Friendica $hostname",
'Contact' => 'https://github.com/friendica/friendica/issues',
'InputEncoding' => 'UTF-8',
'OutputEncoding' => 'UTF-8',
'Developer' => 'Friendica Developer Team',
],
], $xml);

View file

@ -174,7 +174,7 @@ class PermissionTooltip extends \Friendica\BaseModule
* @param int $uriId
* @return string
*/
private function fetchReceivers(int $uriId):string
private function fetchReceivers(int $uriId): string
{
$own_url = '';
$uid = local_user();

View file

@ -60,17 +60,17 @@ class Photo extends BaseModule
{
$totalstamp = microtime(true);
if (isset($_SERVER["HTTP_IF_MODIFIED_SINCE"])) {
header("Last-Modified: " . gmdate("D, d M Y H:i:s", time()) . " GMT");
if (!empty($_SERVER["HTTP_IF_NONE_MATCH"])) {
header("Etag: " . $_SERVER["HTTP_IF_NONE_MATCH"]);
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT');
if (!empty($_SERVER['HTTP_IF_NONE_MATCH'])) {
header('Etag: ' . $_SERVER['HTTP_IF_NONE_MATCH']);
}
header("Expires: " . gmdate("D, d M Y H:i:s", time() + (31536000)) . " GMT");
header("Cache-Control: max-age=31536000");
if (function_exists("header_remove")) {
header_remove("Last-Modified");
header_remove("Expires");
header_remove("Cache-Control");
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + (31536000)) . ' GMT');
header('Cache-Control: max-age=31536000');
if (function_exists('header_remove')) {
header_remove('Last-Modified');
header_remove('Expires');
header_remove('Cache-Control');
}
throw new NotModifiedException();
}
@ -128,11 +128,11 @@ class Photo extends BaseModule
throw new HTTPException\NotFoundException(DI::l10n()->t('The Photo is not available.'));
}
$photo = self::getPhotoByid($id, $this->parameters['type'], $customsize ?: Proxy::PIXEL_SMALL);
$photo = self::getPhotoById($id, $this->parameters['type'], $customsize ?: Proxy::PIXEL_SMALL);
} else {
$photoid = pathinfo($this->parameters['name'], PATHINFO_FILENAME);
$scale = 0;
if (substr($photoid, -2, 1) == "-") {
if (substr($photoid, -2, 1) == '-') {
$scale = intval(substr($photoid, -1, 1));
$photoid = substr($photoid, 0, -2);
}
@ -148,7 +148,7 @@ class Photo extends BaseModule
throw new 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);
$stamp = microtime(true);
@ -179,35 +179,35 @@ class Photo extends BaseModule
}
// if customsize is set and image is not a gif, resize it
if ($photo['type'] !== "image/gif" && $customsize > 0 && $customsize <= Proxy::PIXEL_THUMB && $square_resize) {
if ($photo['type'] !== 'image/gif' && $customsize > 0 && $customsize <= Proxy::PIXEL_THUMB && $square_resize) {
$img = new Image($imgdata, $photo['type']);
$img->scaleToSquare($customsize);
$imgdata = $img->asString();
} elseif ($photo['type'] !== "image/gif" && $customsize > 0) {
} elseif ($photo['type'] !== 'image/gif' && $customsize > 0) {
$img = new Image($imgdata, $photo['type']);
$img->scaleDown($customsize);
$imgdata = $img->asString();
}
if (function_exists("header_remove")) {
header_remove("Pragma");
header_remove("pragma");
if (function_exists('header_remove')) {
header_remove('Pragma');
header_remove('pragma');
}
header("Content-type: " . $photo['type']);
header('Content-type: ' . $photo['type']);
$stamp = microtime(true);
if (!$cacheable) {
// it is a private photo that they have no permission to view.
// tell the browser not to cache it, in case they authenticate
// and subsequently have permission to see it
header("Cache-Control: no-store, no-cache, must-revalidate");
header('Cache-Control: no-store, no-cache, must-revalidate');
} else {
$md5 = $photo['hash'] ?: md5($imgdata);
header("Last-Modified: " . gmdate("D, d M Y H:i:s", time()) . " GMT");
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT');
header("Etag: \"{$md5}\"");
header("Expires: " . gmdate("D, d M Y H:i:s", time() + (31536000)) . " GMT");
header("Cache-Control: max-age=31536000");
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + (31536000)) . ' GMT');
header('Cache-Control: max-age=31536000');
}
$checksum = microtime(true) - $stamp;
@ -228,10 +228,18 @@ class Photo extends BaseModule
System::exit();
}
private static function getPhotoByid(int $id, $type, $customsize)
/**
* Fetches photo record by given id number, type and custom size
*
* @param int $id Photo id
* @param string $type Photo type
* @param int $customsize Custom size (?)
* @return array|bool Array on success, false on error
*/
private static function getPhotoById(int $id, string $type, int $customsize)
{
switch($type) {
case "preview":
case 'preview':
$media = DBA::selectFirst('post-media', ['preview', 'url', 'mimetype', 'type', 'uri-id'], ['id' => $id]);
if (empty($media)) {
return false;
@ -250,8 +258,8 @@ class Photo extends BaseModule
return MPhoto::getPhoto($matches[1], $matches[2]);
}
return MPhoto::createPhotoForExternalResource($url, (int)local_user(), $media['mimetype']);
case "media":
return MPhoto::createPhotoForExternalResource($url, (int)local_user(), $media['mimetype'] ?? '');
case 'media':
$media = DBA::selectFirst('post-media', ['url', 'mimetype', 'uri-id'], ['id' => $id, 'type' => Post\Media::IMAGE]);
if (empty($media)) {
return false;
@ -262,14 +270,14 @@ class Photo extends BaseModule
}
return MPhoto::createPhotoForExternalResource($media['url'], (int)local_user(), $media['mimetype']);
case "link":
case 'link':
$link = DBA::selectFirst('post-link', ['url', 'mimetype'], ['id' => $id]);
if (empty($link)) {
return false;
}
return MPhoto::createPhotoForExternalResource($link['url'], (int)local_user(), $link['mimetype']);
case "contact":
return MPhoto::createPhotoForExternalResource($link['url'], (int)local_user(), $link['mimetype'] ?? '');
case 'contact':
$fields = ['uid', 'uri-id', 'url', 'nurl', 'avatar', 'photo', 'xmpp', 'addr', 'network', 'failed', 'updated'];
$contact = Contact::getById($id, $fields);
if (empty($contact)) {
@ -287,7 +295,7 @@ class Photo extends BaseModule
} else {
$scale = 4;
}
$photo = MPhoto::selectFirst([], ["scale" => $scale, "uid" => $contact['uid'], "profile" => 1]);
$photo = MPhoto::selectFirst([], ['scale' => $scale, 'uid' => $contact['uid'], 'profile' => 1]);
if (!empty($photo)) {
return $photo;
}
@ -330,7 +338,7 @@ class Photo extends BaseModule
}
if ($update) {
Logger::info('Invalid file, contact update initiated', ['cid' => $id, 'url' => $contact['url'], 'avatar' => $url]);
Worker::add(PRIORITY_LOW, "UpdateContact", $id);
Worker::add(PRIORITY_LOW, 'UpdateContact', $id);
} else {
Logger::info('Invalid file', ['cid' => $id, 'url' => $contact['url'], 'avatar' => $url]);
}
@ -352,7 +360,7 @@ class Photo extends BaseModule
}
}
return MPhoto::createPhotoForExternalResource($url, 0, $mimetext);
case "header":
case 'header':
$fields = ['uid', 'url', 'header', 'network', 'gsid'];
$contact = Contact::getById($id, $fields);
if (empty($contact)) {
@ -367,37 +375,37 @@ class Photo extends BaseModule
$url = Contact::getDefaultHeader($contact);
}
return MPhoto::createPhotoForExternalResource($url);
case "banner":
$photo = MPhoto::selectFirst([], ["scale" => 3, 'uid' => $id, 'photo-type' => MPhoto::USER_BANNER]);
case 'banner':
$photo = MPhoto::selectFirst([], ['scale' => 3, 'uid' => $id, 'photo-type' => MPhoto::USER_BANNER]);
if (!empty($photo)) {
return $photo;
}
return MPhoto::createPhotoForExternalResource(DI::baseUrl() . '/images/friendica-banner.jpg');
case "profile":
case "custom":
case 'profile':
case 'custom':
$scale = 4;
break;
case "micro":
case 'micro':
$scale = 6;
break;
case "avatar":
case 'avatar':
default:
$scale = 5;
}
$photo = MPhoto::selectFirst([], ["scale" => $scale, "uid" => $id, "profile" => 1]);
$photo = MPhoto::selectFirst([], ['scale' => $scale, 'uid' => $id, 'profile' => 1]);
if (empty($photo)) {
$contact = DBA::selectFirst('contact', [], ['uid' => $id, 'self' => true]) ?: [];
switch($type) {
case "profile":
case "custom":
case 'profile':
case 'custom':
$default = Contact::getDefaultAvatar($contact, Proxy::SIZE_SMALL);
break;
case "micro":
case 'micro':
$default = Contact::getDefaultAvatar($contact, Proxy::SIZE_MICRO);
break;
case "avatar":
case 'avatar':
default:
$default = Contact::getDefaultAvatar($contact, Proxy::SIZE_THUMB);
}

View file

@ -55,17 +55,17 @@ class Proxy extends BaseModule
throw new \Friendica\Network\HTTPException\NotFoundException();
}
if (isset($_SERVER["HTTP_IF_MODIFIED_SINCE"])) {
header("Last-Modified: " . gmdate("D, d M Y H:i:s", time()) . " GMT");
if (!empty($_SERVER["HTTP_IF_NONE_MATCH"])) {
header("Etag: " . $_SERVER["HTTP_IF_NONE_MATCH"]);
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT');
if (!empty($_SERVER['HTTP_IF_NONE_MATCH'])) {
header('Etag: ' . $_SERVER['HTTP_IF_NONE_MATCH']);
}
header("Expires: " . gmdate("D, d M Y H:i:s", time() + (31536000)) . " GMT");
header("Cache-Control: max-age=31536000");
if (function_exists("header_remove")) {
header_remove("Last-Modified");
header_remove("Expires");
header_remove("Cache-Control");
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + (31536000)) . ' GMT');
header('Cache-Control: max-age=31536000');
if (function_exists('header_remove')) {
header_remove('Last-Modified');
header_remove('Expires');
header_remove('Cache-Control');
}
throw new NotModifiedException();
}
@ -123,7 +123,7 @@ class Proxy extends BaseModule
* ]
* @throws \Exception
*/
private function getRequestInfo()
private function getRequestInfo(): array
{
$size = ProxyUtils::PIXEL_LARGE;
$sizetype = '';
@ -187,6 +187,7 @@ class Proxy extends BaseModule
* Output the image with cache headers
*
* @param Image $img
* @return void
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
private static function responseImageHttpCache(Image $img)

View file

@ -21,11 +21,13 @@
namespace Friendica\Module\Search;
use Friendica\App;
use Friendica\Content\Nav;
use Friendica\Content\Pager;
use Friendica\Content\Text\HTML;
use Friendica\Content\Widget;
use Friendica\Core\Cache\Enum\Duration;
use Friendica\Core\L10n;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Core\Search;
@ -37,11 +39,24 @@ use Friendica\Model\Item;
use Friendica\Model\Post;
use Friendica\Model\Tag;
use Friendica\Module\BaseSearch;
use Friendica\Module\Response;
use Friendica\Network\HTTPException;
use Friendica\Util\Network;
use Friendica\Util\Profiler;
use Psr\Log\LoggerInterface;
class Index extends BaseSearch
{
/** @var string */
private $remoteAddress;
public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, App\Request $request, array $server, array $parameters = [])
{
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->remoteAddress = $request->getRemoteAddress();
}
protected function content(array $request = []): string
{
$search = (!empty($_GET['q']) ? trim(rawurldecode($_GET['q'])) : '');
@ -66,7 +81,7 @@ class Index extends BaseSearch
if ($crawl_permit_period == 0)
$crawl_permit_period = 10;
$remote = $_SERVER['REMOTE_ADDR'];
$remote = $this->remoteAddress;
$result = DI::cache()->get('remote_search:' . $remote);
if (!is_null($result)) {
$resultdata = json_decode($result);

View file

@ -31,7 +31,6 @@ use Friendica\Core\System;
use Friendica\Model\Profile;
use Friendica\Model\User\Cookie;
use Friendica\Module\Response;
use Friendica\Security\TwoFactor;
use Friendica\Util\Profiler;
use Psr\Log\LoggerInterface;
@ -46,17 +45,14 @@ class Logout extends BaseModule
protected $cookie;
/** @var IHandleSessions */
protected $session;
/** @var TwoFactor\Repository\TrustedBrowser */
protected $trustedBrowserRepo;
public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, TwoFactor\Repository\TrustedBrowser $trustedBrowserRepo, ICanCache $cache, Cookie $cookie, IHandleSessions $session, array $server, array $parameters = [])
public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, ICanCache $cache, Cookie $cookie, IHandleSessions $session, array $server, array $parameters = [])
{
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->cache = $cache;
$this->cookie = $cookie;
$this->session = $session;
$this->trustedBrowserRepo = $trustedBrowserRepo;
$this->cache = $cache;
$this->cookie = $cookie;
$this->session = $session;
}
@ -73,9 +69,9 @@ class Logout extends BaseModule
Hook::callAll("logging_out");
// Remove this trusted browser as it won't be able to be used ever again after the cookie is cleared
if ($this->cookie->get('trusted')) {
$this->trustedBrowserRepo->removeForUser(local_user(), $this->cookie->get('trusted'));
// If this is a trusted browser, redirect to the 2fa signout page
if ($this->cookie->get('2fa_cookie_hash')) {
$this->baseUrl->redirect('2fa/signout');
}
$this->cookie->clear();

View file

@ -0,0 +1,129 @@
<?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\Security\TwoFactor;
use Friendica\App;
use Friendica\BaseModule;
use Friendica\Core\L10n;
use Friendica\Core\Renderer;
use Friendica\Core\Session\Capability\IHandleSessions;
use Friendica\Model\User\Cookie;
use Friendica\Module\Response;
use Friendica\Network\HTTPException\NotFoundException;
use Friendica\Util\Profiler;
use Friendica\Security\TwoFactor;
use Psr\Log\LoggerInterface;
/**
* Page 4: Logout dialog for trusted browsers
*
* @package Friendica\Module\TwoFactor
*/
class SignOut extends BaseModule
{
protected $errors = [];
/** @var IHandleSessions */
protected $session;
/** @var Cookie */
protected $cookie;
/** @var TwoFactor\Repository\TrustedBrowser */
protected $trustedBrowserRepository;
public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, IHandleSessions $session, Cookie $cookie, TwoFactor\Repository\TrustedBrowser $trustedBrowserRepository, Profiler $profiler, Response $response, array $server, array $parameters = [])
{
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->session = $session;
$this->cookie = $cookie;
$this->trustedBrowserRepository = $trustedBrowserRepository;
}
protected function post(array $request = [])
{
if (!local_user() || !($this->cookie->get('2fa_cookie_hash'))) {
return;
}
$action = $request['action'] ?? '';
if (!empty($action)) {
self::checkFormSecurityTokenRedirectOnError('2fa', 'twofactor_signout');
switch ($action) {
case 'trust_and_sign_out':
$trusted = $this->cookie->get('2fa_cookie_hash');
$this->cookie->reset(['2fa_cookie_hash' => $trusted]);
$this->session->clear();
info($this->t('Logged out.'));
$this->baseUrl->redirect();
break;
case 'sign_out':
$this->trustedBrowserRepository->removeForUser(local_user(), $this->cookie->get('2fa_cookie_hash'));
$this->cookie->clear();
$this->session->clear();
info($this->t('Logged out.'));
$this->baseUrl->redirect();
break;
default:
$this->baseUrl->redirect();
}
}
}
protected function content(array $request = []): string
{
if (!local_user() || !($this->cookie->get('2fa_cookie_hash'))) {
$this->baseUrl->redirect();
}
try {
$trustedBrowser = $this->trustedBrowserRepository->selectOneByHash($this->cookie->get('2fa_cookie_hash'));
if (!$trustedBrowser->trusted) {
$trusted = $this->cookie->get('2fa_cookie_hash');
$this->cookie->reset(['2fa_cookie_hash' => $trusted]);
$this->session->clear();
info($this->t('Logged out.'));
$this->baseUrl->redirect();
}
} catch (TwoFactor\Exception\TrustedBrowserNotFoundException $exception) {
$this->cookie->clear();
$this->session->clear();
info($this->t('Logged out.'));
$this->baseUrl->redirect();
}
return Renderer::replaceMacros(Renderer::getMarkupTemplate('twofactor/signout.tpl'), [
'$form_security_token' => self::getFormSecurityToken('twofactor_signout'),
'$title' => $this->t('Sign out of this browser?'),
'$message' => $this->t('<p>If you trust this browser, you will not be asked for verification code the next time you sign in.</p>'),
'$sign_out_label' => $this->t('Sign out'),
'$cancel_label' => $this->t('Cancel'),
'$trust_and_sign_out_label' => $this->t('Trust and sign out'),
]);
}
}

View file

@ -0,0 +1,146 @@
<?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\Security\TwoFactor;
use Friendica\App;
use Friendica\BaseModule;
use Friendica\Core\L10n;
use Friendica\Core\Renderer;
use Friendica\Core\Session\Capability\IHandleSessions;
use Friendica\Model\User;
use Friendica\Model\User\Cookie;
use Friendica\Module\Response;
use Friendica\Network\HTTPException\FoundException;
use Friendica\Network\HTTPException\MovedPermanentlyException;
use Friendica\Network\HTTPException\TemporaryRedirectException;
use Friendica\Security\Authentication;
use Friendica\Security\TwoFactor\Exception\TrustedBrowserNotFoundException;
use Friendica\Security\TwoFactor\Exception\TrustedBrowserPersistenceException;
use Friendica\Util\Profiler;
use Friendica\Security\TwoFactor;
use Psr\Log\LoggerInterface;
/**
* Page 2: Trust Browser dialog
*
* @package Friendica\Module\TwoFactor
*/
class Trust extends BaseModule
{
/** @var App */
protected $app;
/** @var Authentication */
protected $auth;
/** @var IHandleSessions */
protected $session;
/** @var Cookie */
protected $cookie;
/** @var TwoFactor\Factory\TrustedBrowser */
protected $trustedBrowserFactory;
/** @var TwoFactor\Repository\TrustedBrowser */
protected $trustedBrowserRepository;
public function __construct(App $app, Authentication $auth, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, IHandleSessions $session, Cookie $cookie, TwoFactor\Factory\TrustedBrowser $trustedBrowserFactory, TwoFactor\Repository\TrustedBrowser $trustedBrowserRepositoy, Response $response, array $server, array $parameters = [])
{
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->app = $app;
$this->auth = $auth;
$this->session = $session;
$this->cookie = $cookie;
$this->trustedBrowserFactory = $trustedBrowserFactory;
$this->trustedBrowserRepository = $trustedBrowserRepositoy;
}
protected function post(array $request = [])
{
if (!local_user() || !$this->session->get('2fa')) {
$this->logger->info('Invalid call', ['request' => $request]);
return;
}
$action = $request['action'] ?? '';
if (!empty($action)) {
self::checkFormSecurityTokenRedirectOnError('2fa', 'twofactor_trust');
switch ($action) {
case 'trust':
case 'dont_trust':
$trustedBrowser = $this->trustedBrowserFactory->createForUserWithUserAgent(local_user(), $this->server['HTTP_USER_AGENT'], $action === 'trust');
try {
$this->trustedBrowserRepository->save($trustedBrowser);
// The string is sent to the browser to be sent back with each request
if (!$this->cookie->set('2fa_cookie_hash', $trustedBrowser->cookie_hash)) {
notice($this->t('Couldn\'t save browser to Cookie.'));
};
} catch (TrustedBrowserPersistenceException $exception) {
$this->logger->warning('Unexpected error when saving the trusted browser.', ['trustedBrowser' => $trustedBrowser, 'exception' => $exception]);
}
break;
}
try {
$this->auth->setForUser($this->app, User::getById($this->app->getLoggedInUserId()), true, true);
} catch (FoundException | TemporaryRedirectException | MovedPermanentlyException $e) {
// exception wanted!
throw $e;
} catch (\Exception $e) {
$this->logger->warning('Unexpected error during authentication.', ['user' => $this->app->getLoggedInUserId(), 'exception' => $exception]);
}
}
}
protected function content(array $request = []): string
{
if (!local_user() || !$this->session->get('2fa')) {
$this->baseUrl->redirect();
}
if ($this->cookie->get('2fa_cookie_hash')) {
try {
$trustedBrowser = $this->trustedBrowserRepository->selectOneByHash($this->cookie->get('2fa_cookie_hash'));
if (!$trustedBrowser->trusted) {
$this->auth->setForUser($this->app, User::getById($this->app->getLoggedInUserId()), true, true);
$this->baseUrl->redirect();
}
} catch (TrustedBrowserNotFoundException $exception) {
$this->logger->notice('Trusted Browser of the cookie not found.', ['cookie_hash' => $this->cookie->get('trusted'), 'uid' => $this->app->getLoggedInUserId(), 'exception' => $exception]);
} catch (TrustedBrowserPersistenceException $exception) {
$this->logger->warning('Unexpected persistence exception.', ['cookie_hash' => $this->cookie->get('trusted'), 'uid' => $this->app->getLoggedInUserId(), 'exception' => $exception]);
} catch (\Exception $exception) {
$this->logger->warning('Unexpected exception.', ['cookie_hash' => $this->cookie->get('trusted'), 'uid' => $this->app->getLoggedInUserId(), 'exception' => $exception]);
}
}
return Renderer::replaceMacros(Renderer::getMarkupTemplate('twofactor/trust.tpl'), [
'$form_security_token' => self::getFormSecurityToken('twofactor_trust'),
'$title' => $this->t('Trust this browser?'),
'$message' => $this->t('<p>If you choose to trust this browser, you will not be asked for a verification code the next time you sign in.</p>'),
'$not_now_label' => $this->t('Not now'),
'$dont_trust_label' => $this->t('Don\'t trust'),
'$trust_label' => $this->t('Trust'),
]);
}
}

View file

@ -21,13 +21,17 @@
namespace Friendica\Module\Security\TwoFactor;
use Friendica\App;
use Friendica\BaseModule;
use Friendica\Core\L10n;
use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues;
use Friendica\Core\Renderer;
use Friendica\Core\Session;
use Friendica\DI;
use Friendica\Model\User;
use Friendica\Core\Session\Capability\IHandleSessions;
use Friendica\Module\Response;
use Friendica\Util\Profiler;
use PragmaRX\Google2FA\Google2FA;
use Friendica\Security\TwoFactor;
use Psr\Log\LoggerInterface;
/**
* Page 1: Authenticator code verification
@ -36,7 +40,20 @@ use Friendica\Security\TwoFactor;
*/
class Verify extends BaseModule
{
private static $errors = [];
protected $errors = [];
/** @var IHandleSessions */
protected $session;
/** @var IManagePersonalConfigValues */
protected $pConfig;
public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, IManagePersonalConfigValues $pConfig, IHandleSessions $session, array $server, array $parameters = [])
{
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->session = $session;
$this->pConfig = $pConfig;
}
protected function post(array $request = [])
{
@ -44,36 +61,20 @@ class Verify extends BaseModule
return;
}
if (($_POST['action'] ?? '') == 'verify') {
if (($request['action'] ?? '') === 'verify') {
self::checkFormSecurityTokenRedirectOnError('2fa', 'twofactor_verify');
$a = DI::app();
$code = $request['verify_code'] ?? '';
$code = $_POST['verify_code'] ?? '';
$valid = (new Google2FA())->verifyKey(DI::pConfig()->get(local_user(), '2fa', 'secret'), $code);
$valid = (new Google2FA())->verifyKey($this->pConfig->get(local_user(), '2fa', 'secret'), $code);
// The same code can't be used twice even if it's valid
if ($valid && Session::get('2fa') !== $code) {
Session::set('2fa', $code);
if ($valid && $this->session->get('2fa') !== $code) {
$this->session->set('2fa', $code);
// Trust this browser feature
if (!empty($_REQUEST['trust_browser'])) {
$trustedBrowserFactory = new TwoFactor\Factory\TrustedBrowser(DI::logger());
$trustedBrowserRepository = new TwoFactor\Repository\TrustedBrowser(DI::dba(), DI::logger(), $trustedBrowserFactory);
$trustedBrowser = $trustedBrowserFactory->createForUserWithUserAgent(local_user(), $_SERVER['HTTP_USER_AGENT']);
$trustedBrowserRepository->save($trustedBrowser);
// The string is sent to the browser to be sent back with each request
DI::cookie()->set('trusted', $trustedBrowser->cookie_hash);
}
// Resume normal login workflow
DI::auth()->setForUser($a, User::getById($a->getLoggedInUserId()), true, true);
$this->baseUrl->redirect('2fa/trust');
} else {
self::$errors[] = DI::l10n()->t('Invalid code, please retry.');
$this->errors[] = $this->t('Invalid code, please retry.');
}
}
}
@ -81,25 +82,24 @@ class Verify extends BaseModule
protected function content(array $request = []): string
{
if (!local_user()) {
DI::baseUrl()->redirect();
$this->baseUrl->redirect();
}
// Already authenticated with 2FA token
if (Session::get('2fa')) {
DI::baseUrl()->redirect();
if ($this->session->get('2fa')) {
$this->baseUrl->redirect();
}
return Renderer::replaceMacros(Renderer::getMarkupTemplate('twofactor/verify.tpl'), [
'$form_security_token' => self::getFormSecurityToken('twofactor_verify'),
'$title' => DI::l10n()->t('Two-factor authentication'),
'$message' => DI::l10n()->t('<p>Open the two-factor authentication app on your device to get an authentication code and verify your identity.</p>'),
'$errors_label' => DI::l10n()->tt('Error', 'Errors', count(self::$errors)),
'$errors' => self::$errors,
'$recovery_message' => DI::l10n()->t('Dont have your phone? <a href="%s">Enter a two-factor recovery code</a>', '2fa/recovery'),
'$verify_code' => ['verify_code', DI::l10n()->t('Please enter a code from your authentication app'), '', '', DI::l10n()->t('Required'), 'autofocus autocomplete="off" placeholder="000000"', 'tel'],
'$trust_browser' => ['trust_browser', DI::l10n()->t('This is my two-factor authenticator app device'), !empty($_REQUEST['trust_browser'])],
'$verify_label' => DI::l10n()->t('Verify code and complete login'),
'$title' => $this->t('Two-factor authentication'),
'$message' => $this->t('<p>Open the two-factor authentication app on your device to get an authentication code and verify your identity.</p>'),
'$errors_label' => $this->tt('Error', 'Errors', count($this->errors)),
'$errors' => $this->errors,
'$recovery_message' => $this->t('If you do not have access to your authentication code you can use a <a href="%s">two-factor recovery code</a>.', '2fa/recovery'),
'$verify_code' => ['verify_code', $this->t('Please enter a code from your authentication app'), '', '', $this->t('Required'), 'autofocus autocomplete="one-time-code" placeholder="000000" inputmode="numeric" pattern="[0-9]*"'],
'$verify_label' => $this->t('Verify code and complete login'),
]);
}
}

View file

@ -24,6 +24,7 @@ namespace Friendica\Module\Settings\TwoFactor;
use Friendica\Core\Renderer;
use Friendica\Core\Session;
use Friendica\DI;
use Friendica\Network\HTTPException\FoundException;
use Friendica\Security\TwoFactor\Model\AppSpecificPassword;
use Friendica\Security\TwoFactor\Model\RecoveryCode;
use Friendica\Model\User;
@ -44,8 +45,8 @@ class Index extends BaseSettings
try {
User::getIdFromPasswordAuthentication(local_user(), $_POST['password'] ?? '');
$has_secret = (bool) DI::pConfig()->get(local_user(), '2fa', 'secret');
$verified = DI::pConfig()->get(local_user(), '2fa', 'verified');
$has_secret = (bool)DI::pConfig()->get(local_user(), '2fa', 'secret');
$verified = DI::pConfig()->get(local_user(), '2fa', 'verified');
switch ($_POST['action'] ?? '') {
case 'enable':
@ -54,7 +55,8 @@ class Index extends BaseSettings
DI::pConfig()->set(local_user(), '2fa', 'secret', $Google2FA->generateSecretKey(32));
DI::baseUrl()->redirect('settings/2fa/recovery?t=' . self::getFormSecurityToken('settings_2fa_password'));
DI::baseUrl()
->redirect('settings/2fa/recovery?t=' . self::getFormSecurityToken('settings_2fa_password'));
}
break;
case 'disable':
@ -70,27 +72,33 @@ class Index extends BaseSettings
break;
case 'recovery':
if ($has_secret) {
DI::baseUrl()->redirect('settings/2fa/recovery?t=' . self::getFormSecurityToken('settings_2fa_password'));
DI::baseUrl()
->redirect('settings/2fa/recovery?t=' . self::getFormSecurityToken('settings_2fa_password'));
}
break;
case 'app_specific':
if ($has_secret) {
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;
case 'trusted':
if ($has_secret) {
DI::baseUrl()->redirect('settings/2fa/trusted?t=' . self::getFormSecurityToken('settings_2fa_password'));
DI::baseUrl()
->redirect('settings/2fa/trusted?t=' . self::getFormSecurityToken('settings_2fa_password'));
}
break;
case 'configure':
if (!$verified) {
DI::baseUrl()->redirect('settings/2fa/verify?t=' . self::getFormSecurityToken('settings_2fa_password'));
DI::baseUrl()
->redirect('settings/2fa/verify?t=' . self::getFormSecurityToken('settings_2fa_password'));
}
break;
}
} catch (FoundException $exception) {
// Nothing to do here
} catch (\Exception $e) {
notice(DI::l10n()->t('Wrong Password'));
notice(DI::l10n()->t($e->getMessage()));
}
}

View file

@ -77,7 +77,7 @@ class Trusted extends BaseSettings
self::checkFormSecurityTokenRedirectOnError('settings/2fa/trusted', 'settings_2fa_trusted');
switch ($_POST['action']) {
case 'remove_all' :
case 'remove_all':
$this->trustedBrowserRepo->removeAllForUser(local_user());
info($this->t('Trusted browsers successfully removed.'));
$this->baseUrl->redirect('settings/2fa/trusted?t=' . self::getFormSecurityToken('settings_2fa_password'));
@ -118,29 +118,31 @@ class Trusted extends BaseSettings
$result = $parser->parse($trustedBrowser->user_agent);
$uaData = [
'os' => $result->os->family,
'device' => $result->device->family,
'browser' => $result->ua->family,
'os' => $result->os->family,
'device' => $result->device->family,
'browser' => $result->ua->family,
'trusted_labeled' => $trustedBrowser->trusted ? $this->t('Yes') : $this->t('No'),
];
return $trustedBrowser->toArray() + $dates + $uaData;
}, $trustedBrowsers->getArrayCopy());
return Renderer::replaceMacros(Renderer::getMarkupTemplate('settings/twofactor/trusted_browsers.tpl'), [
'$form_security_token' => self::getFormSecurityToken('settings_2fa_trusted'),
'$form_security_token' => self::getFormSecurityToken('settings_2fa_trusted'),
'$password_security_token' => self::getFormSecurityToken('settings_2fa_password'),
'$title' => $this->t('Two-factor Trusted Browsers'),
'$message' => $this->t('Trusted browsers are individual browsers you chose to skip two-factor authentication to access Friendica. Please use this feature sparingly, as it can negate the benefit of two-factor authentication.'),
'$device_label' => $this->t('Device'),
'$os_label' => $this->t('OS'),
'$browser_label' => $this->t('Browser'),
'$created_label' => $this->t('Trusted'),
'$last_used_label' => $this->t('Last Use'),
'$remove_label' => $this->t('Remove'),
'$remove_all_label' => $this->t('Remove All'),
'$title' => $this->t('Two-factor Trusted Browsers'),
'$message' => $this->t('Trusted browsers are individual browsers you chose to skip two-factor authentication to access Friendica. Please use this feature sparingly, as it can negate the benefit of two-factor authentication.'),
'$device_label' => $this->t('Device'),
'$os_label' => $this->t('OS'),
'$browser_label' => $this->t('Browser'),
'$trusted_label' => $this->t('Trusted'),
'$created_label' => $this->t('Created At'),
'$last_used_label' => $this->t('Last Use'),
'$remove_label' => $this->t('Remove'),
'$remove_all_label' => $this->t('Remove All'),
'$trusted_browsers' => $trustedBrowserDisplay,
'$trusted_browsers' => $trustedBrowserDisplay,
]);
}
}

View file

@ -124,7 +124,7 @@ class UserExport extends BaseSettings
*/
private static function exportMultiRow(string $query)
{
$dbStructure = DBStructure::definition(DI::app()->getBasePath(), false);
$dbStructure = DI::dbaDefinition()->getAll();
preg_match("/\s+from\s+`?([a-z\d_]+)`?/i", $query, $match);
$table = $match[1];
@ -156,7 +156,7 @@ class UserExport extends BaseSettings
*/
private static function exportRow(string $query)
{
$dbStructure = DBStructure::definition(DI::app()->getBasePath(), false);
$dbStructure = DI::dbaDefinition()->getAll();
preg_match("/\s+from\s+`?([a-z\d_]+)`?/i", $query, $match);
$table = $match[1];