Merge branch 'develop' into rework-addon-class

This commit is contained in:
Art4 2025-06-04 06:27:08 +00:00
commit 1723417f43
30 changed files with 1573 additions and 1220 deletions

View file

@ -13,6 +13,9 @@ if (php_sapi_name() !== 'cli') {
exit();
}
// Ensure that te console is executed from the base path of the installation
chdir(dirname(__DIR__));
require dirname(__DIR__) . '/vendor/autoload.php';
$container = \Friendica\Core\DiceContainer::fromBasePath(dirname(__DIR__));

View file

@ -36,7 +36,7 @@
"friendica/json-ld": "^1.0",
"geekwright/po": "^2.0",
"guzzlehttp/guzzle": "^7",
"guzzlehttp/oauth-subscriber": "^0.6",
"guzzlehttp/oauth-subscriber": "^0.8",
"kornrunner/blurhash": "^1.2",
"league/html-to-markdown": "^4.8",
"level-2/dice": "^4",
@ -67,6 +67,7 @@
"patrickschur/language-detection": "^5.0.0",
"pear/console_table": "^1.3",
"phpseclib/phpseclib": "^3.0",
"phrity/websocket": "^1.7",
"pragmarx/google2fa": "^5.0",
"pragmarx/recovery": "^0.2",
"psr/clock": "^1.0",
@ -76,7 +77,6 @@
"seld/cli-prompt": "^1.0",
"smarty/smarty": "^4",
"symfony/event-dispatcher": "^5.4",
"textalk/websocket": "^1.6",
"ua-parser/uap-php": "^3.9",
"xemlock/htmlpurifier-html5": "^0.1.11"
},

330
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "32af97f73ec49df2a6cfe98f11bc1d60",
"content-hash": "897b878d6db24b9a6437bd9f971478be",
"packages": [
{
"name": "asika/simple-console",
@ -893,22 +893,22 @@
},
{
"name": "guzzlehttp/guzzle",
"version": "7.8.1",
"version": "7.9.3",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "41042bc7ab002487b876a0683fc8dce04ddce104"
"reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104",
"reference": "41042bc7ab002487b876a0683fc8dce04ddce104",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/7b2f29fe81dc4da0ca0ea7d42107a0845946ea77",
"reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77",
"shasum": ""
},
"require": {
"ext-json": "*",
"guzzlehttp/promises": "^1.5.3 || ^2.0.1",
"guzzlehttp/psr7": "^1.9.1 || ^2.5.1",
"guzzlehttp/promises": "^1.5.3 || ^2.0.3",
"guzzlehttp/psr7": "^2.7.0",
"php": "^7.2.5 || ^8.0",
"psr/http-client": "^1.0",
"symfony/deprecation-contracts": "^2.2 || ^3.0"
@ -919,9 +919,9 @@
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"ext-curl": "*",
"php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999",
"guzzle/client-integration-tests": "3.0.2",
"php-http/message-factory": "^1.1",
"phpunit/phpunit": "^8.5.36 || ^9.6.15",
"phpunit/phpunit": "^8.5.39 || ^9.6.20",
"psr/log": "^1.1 || ^2.0 || ^3.0"
},
"suggest": {
@ -997,6 +997,10 @@
"rest",
"web service"
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/7.9.3"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
@ -1011,37 +1015,39 @@
"type": "tidelift"
}
],
"time": "2023-12-03T20:35:24+00:00"
"time": "2025-03-27T13:37:11+00:00"
},
{
"name": "guzzlehttp/oauth-subscriber",
"version": "0.6.0",
"version": "0.8.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/oauth-subscriber.git",
"reference": "8d6cab29f8397e5712d00a383eeead36108a3c1f"
"reference": "92b619b03bd21396e51c62e6bce83467d2ce8f53"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/oauth-subscriber/zipball/8d6cab29f8397e5712d00a383eeead36108a3c1f",
"reference": "8d6cab29f8397e5712d00a383eeead36108a3c1f",
"url": "https://api.github.com/repos/guzzle/oauth-subscriber/zipball/92b619b03bd21396e51c62e6bce83467d2ce8f53",
"reference": "92b619b03bd21396e51c62e6bce83467d2ce8f53",
"shasum": ""
},
"require": {
"guzzlehttp/guzzle": "^6.5|^7.2",
"guzzlehttp/psr7": "^1.7|^2.0",
"php": ">=5.5.0"
"guzzlehttp/guzzle": "^7.9",
"guzzlehttp/psr7": "^2.7",
"php": "^7.2.5 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "~4.0|^9.3.3"
"bamarni/composer-bin-plugin": "^1.8.2",
"phpunit/phpunit": "^8.5.36 || ^9.6.15"
},
"suggest": {
"ext-openssl": "Required to sign using RSA-SHA1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.6-dev"
"bamarni-bin": {
"bin-links": true,
"forward-command": false
}
},
"autoload": {
@ -1054,32 +1060,64 @@
"MIT"
],
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
},
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "George Mponos",
"email": "gmponos@gmail.com",
"homepage": "https://github.com/gmponos"
},
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com",
"homepage": "https://github.com/Nyholm"
}
],
"description": "Guzzle OAuth 1.0 subscriber",
"homepage": "http://guzzlephp.org/",
"keywords": [
"Guzzle",
"oauth"
],
"time": "2021-07-13T12:01:32+00:00"
"support": {
"issues": "https://github.com/guzzle/oauth-subscriber/issues",
"source": "https://github.com/guzzle/oauth-subscriber/tree/0.8.1"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://github.com/Nyholm",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/oauth-subscriber",
"type": "tidelift"
}
],
"time": "2025-01-06T19:15:59+00:00"
},
{
"name": "guzzlehttp/promises",
"version": "2.0.2",
"version": "2.2.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "bbff78d96034045e58e13dedd6ad91b5d1253223"
"reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/bbff78d96034045e58e13dedd6ad91b5d1253223",
"reference": "bbff78d96034045e58e13dedd6ad91b5d1253223",
"url": "https://api.github.com/repos/guzzle/promises/zipball/7c69f28996b0a6920945dd20b3857e499d9ca96c",
"reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c",
"shasum": ""
},
"require": {
@ -1087,7 +1125,7 @@
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"phpunit/phpunit": "^8.5.36 || ^9.6.15"
"phpunit/phpunit": "^8.5.39 || ^9.6.20"
},
"type": "library",
"extra": {
@ -1131,6 +1169,10 @@
"keywords": [
"promise"
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/2.2.0"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
@ -1145,20 +1187,20 @@
"type": "tidelift"
}
],
"time": "2023-12-03T20:19:20+00:00"
"time": "2025-03-27T13:27:01+00:00"
},
{
"name": "guzzlehttp/psr7",
"version": "2.6.2",
"version": "2.7.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221"
"reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221",
"reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/c2270caaabe631b3b44c85f99e5a04bbb8060d16",
"reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16",
"shasum": ""
},
"require": {
@ -1173,8 +1215,8 @@
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"http-interop/http-factory-tests": "^0.9",
"phpunit/phpunit": "^8.5.36 || ^9.6.15"
"http-interop/http-factory-tests": "0.9.0",
"phpunit/phpunit": "^8.5.39 || ^9.6.20"
},
"suggest": {
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
@ -1243,6 +1285,10 @@
"uri",
"url"
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/2.7.1"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
@ -1257,7 +1303,7 @@
"type": "tidelift"
}
],
"time": "2023-12-03T20:05:35+00:00"
"time": "2025-03-27T12:30:47+00:00"
},
{
"name": "kornrunner/blurhash",
@ -2814,6 +2860,66 @@
],
"time": "2024-03-03T02:14:58+00:00"
},
{
"name": "phrity/net-stream",
"version": "1.3.0",
"source": {
"type": "git",
"url": "https://github.com/sirn-se/phrity-net-stream.git",
"reference": "9105931b65ad90c75f4885a40b268b0f65802e3e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sirn-se/phrity-net-stream/zipball/9105931b65ad90c75f4885a40b268b0f65802e3e",
"reference": "9105931b65ad90c75f4885a40b268b0f65802e3e",
"shasum": ""
},
"require": {
"php": "^7.4 | ^8.0",
"phrity/util-errorhandler": "^1.0",
"psr/http-factory": "^1.0",
"psr/http-message": "^1.0 | ^2.0"
},
"require-dev": {
"php-coveralls/php-coveralls": "^2.0",
"phpunit/phpunit": "^9.0 | ^10.0",
"phrity/net-uri": "^1.1",
"squizlabs/php_codesniffer": "^3.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Phrity\\Net\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Sören Jensen",
"email": "sirn@sirn.se",
"homepage": "https://phrity.sirn.se"
}
],
"description": "Socket stream classes implementing PSR-7 Stream and PSR-17 StreamFactory",
"homepage": "https://phrity.sirn.se/net-stream",
"keywords": [
"Socket",
"client",
"psr-17",
"psr-7",
"server",
"stream",
"stream factory"
],
"support": {
"issues": "https://github.com/sirn-se/phrity-net-stream/issues",
"source": "https://github.com/sirn-se/phrity-net-stream/tree/1.3.0"
},
"time": "2023-10-22T10:47:03+00:00"
},
{
"name": "phrity/net-uri",
"version": "1.3.0",
@ -2912,6 +3018,67 @@
],
"time": "2024-09-12T06:49:16+00:00"
},
{
"name": "phrity/websocket",
"version": "1.7.3",
"source": {
"type": "git",
"url": "https://github.com/sirn-se/websocket-php.git",
"reference": "8a525da4457b599ab1960f24183f25626c96ce3c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sirn-se/websocket-php/zipball/8a525da4457b599ab1960f24183f25626c96ce3c",
"reference": "8a525da4457b599ab1960f24183f25626c96ce3c",
"shasum": ""
},
"require": {
"php": "^7.4 | ^8.0",
"phrity/net-stream": "^1.2",
"phrity/net-uri": "^1.2",
"phrity/util-errorhandler": "^1.0",
"psr/http-message": "^1.1 | ^2.0",
"psr/log": "^1.0 | ^2.0 | ^3.0"
},
"require-dev": {
"php-coveralls/php-coveralls": "^2.0",
"phpunit/phpunit": "^9.0 | ^10.0",
"phrity/net-mock": "^1.3",
"squizlabs/php_codesniffer": "^3.5"
},
"type": "library",
"autoload": {
"psr-4": {
"WebSocket\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"ISC"
],
"authors": [
{
"name": "Fredrik Liljegren"
},
{
"name": "Sören Jensen",
"email": "sirn@sirn.se",
"homepage": "https://phrity.sirn.se"
}
],
"description": "WebSocket client and server",
"homepage": "https://phrity.sirn.se/websocket",
"keywords": [
"client",
"server",
"websocket"
],
"support": {
"issues": "https://github.com/sirn-se/websocket-php/issues",
"source": "https://github.com/sirn-se/websocket-php/tree/1.7.3"
},
"time": "2024-05-31T13:43:32+00:00"
},
{
"name": "pragmarx/google2fa",
"version": "v5.0.0",
@ -3333,24 +3500,27 @@
"psr",
"psr-18"
],
"support": {
"source": "https://github.com/php-fig/http-client"
},
"time": "2023-09-23T14:17:50+00:00"
},
{
"name": "psr/http-factory",
"version": "1.0.2",
"version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-factory.git",
"reference": "e616d01114759c4c489f93b099585439f795fe35"
"reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35",
"reference": "e616d01114759c4c489f93b099585439f795fe35",
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
"reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
"shasum": ""
},
"require": {
"php": ">=7.0.0",
"php": ">=7.1",
"psr/http-message": "^1.0 || ^2.0"
},
"type": "library",
@ -3374,7 +3544,7 @@
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interfaces for PSR-7 HTTP message factories",
"description": "PSR-17: Common interfaces for PSR-7 HTTP message factories",
"keywords": [
"factory",
"http",
@ -3385,7 +3555,10 @@
"request",
"response"
],
"time": "2023-04-10T20:10:41+00:00"
"support": {
"source": "https://github.com/php-fig/http-factory"
},
"time": "2024-04-15T12:06:14+00:00"
},
{
"name": "psr/http-message",
@ -3435,6 +3608,9 @@
"request",
"response"
],
"support": {
"source": "https://github.com/php-fig/http-message/tree/1.1"
},
"time": "2023-04-04T09:50:52+00:00"
},
{
@ -3525,6 +3701,10 @@
}
],
"description": "A polyfill for getallheaders.",
"support": {
"issues": "https://github.com/ralouphie/getallheaders/issues",
"source": "https://github.com/ralouphie/getallheaders/tree/develop"
},
"time": "2019-03-08T08:55:37+00:00"
},
{
@ -3580,16 +3760,16 @@
},
{
"name": "smarty/smarty",
"version": "v4.5.1",
"version": "v4.5.3",
"source": {
"type": "git",
"url": "https://github.com/smarty-php/smarty.git",
"reference": "42b869e3a098b1c8ee07922ccded0e5a5dceadcd"
"reference": "9fc96a13dbaf546c3d7bcf95466726578cd4e0fa"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/smarty-php/smarty/zipball/42b869e3a098b1c8ee07922ccded0e5a5dceadcd",
"reference": "42b869e3a098b1c8ee07922ccded0e5a5dceadcd",
"url": "https://api.github.com/repos/smarty-php/smarty/zipball/9fc96a13dbaf546c3d7bcf95466726578cd4e0fa",
"reference": "9fc96a13dbaf546c3d7bcf95466726578cd4e0fa",
"shasum": ""
},
"require": {
@ -3637,7 +3817,12 @@
"keywords": [
"templating"
],
"time": "2024-03-18T14:19:07+00:00"
"support": {
"forum": "https://github.com/smarty-php/smarty/discussions",
"issues": "https://github.com/smarty-php/smarty/issues",
"source": "https://github.com/smarty-php/smarty/tree/v4.5.3"
},
"time": "2024-05-28T21:46:01+00:00"
},
{
"name": "spomky-labs/base64url",
@ -4076,57 +4261,6 @@
],
"time": "2024-09-09T11:45:10+00:00"
},
{
"name": "textalk/websocket",
"version": "1.6.3",
"source": {
"type": "git",
"url": "https://github.com/Textalk/websocket-php.git",
"reference": "67de79745b1a357caf812bfc44e0abf481cee012"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Textalk/websocket-php/zipball/67de79745b1a357caf812bfc44e0abf481cee012",
"reference": "67de79745b1a357caf812bfc44e0abf481cee012",
"shasum": ""
},
"require": {
"php": "^7.4 | ^8.0",
"phrity/net-uri": "^1.0",
"phrity/util-errorhandler": "^1.0",
"psr/http-message": "^1.0",
"psr/log": "^1.0 | ^2.0 | ^3.0"
},
"require-dev": {
"php-coveralls/php-coveralls": "^2.0",
"phpunit/phpunit": "^9.0",
"squizlabs/php_codesniffer": "^3.5"
},
"type": "library",
"autoload": {
"psr-4": {
"WebSocket\\": "lib"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"ISC"
],
"authors": [
{
"name": "Fredrik Liljegren"
},
{
"name": "Sören Jensen"
}
],
"description": "WebSocket client and server",
"support": {
"issues": "https://github.com/Textalk/websocket-php/issues",
"source": "https://github.com/Textalk/websocket-php/tree/1.6.3"
},
"time": "2022-11-07T18:59:33+00:00"
},
{
"name": "ua-parser/uap-php",
"version": "v3.9.14",

View file

@ -1,4 +1,5 @@
<?php
/**
* Copyright (C) 2010-2024, the Friendica project
* SPDX-FileCopyrightText: 2010-2024 the Friendica project
@ -131,7 +132,7 @@ function message_content()
$cmd = DI::args()->getArgv()[1];
if ($cmd === 'drop') {
$message = DBA::selectFirst('mail', ['convid'], ['id' => DI::args()->getArgv()[2], 'uid' => DI::userSession()->getLocalUserId()]);
if(!DBA::isResult($message)){
if (!DBA::isResult($message)) {
DI::sysmsg()->addNotice(DI::l10n()->t('Conversation not found.'));
DI::baseUrl()->redirect('message');
}
@ -141,7 +142,7 @@ function message_content()
}
$conversation = DBA::selectFirst('mail', ['id'], ['convid' => $message['convid'], 'uid' => DI::userSession()->getLocalUserId()]);
if(!DBA::isResult($conversation)){
if (!DBA::isResult($conversation)) {
DI::baseUrl()->redirect('message');
}
@ -207,7 +208,7 @@ function message_content()
$r = get_messages(DI::userSession()->getLocalUserId(), $pager->getStart(), $pager->getItemsPerPage());
if (!DBA::isResult($r)) {
DI::sysmsg()->addNotice(DI::l10n()->t('No messages.'));
$o .= DI::l10n()->t('You have no messages.');
return $o;
}
@ -222,7 +223,8 @@ function message_content()
$o .= $header;
$message = DBA::fetchFirst("
$message = DBA::fetchFirst(
"
SELECT `mail`.*, `contact`.`name`, `contact`.`url`, `contact`.`thumb`
FROM `mail`
LEFT JOIN `contact` ON `mail`.`contact-id` = `contact`.`id`
@ -245,7 +247,8 @@ function message_content()
} else {
$sql_extra = "AND `mail`.`parent-uri` = ?";
}
$messages_stmt = DBA::p("
$messages_stmt = DBA::p(
"
SELECT `mail`.*, `contact`.`name`, `contact`.`url`, `contact`.`thumb`
FROM `mail`
LEFT JOIN `contact` ON `mail`.`contact-id` = `contact`.`id`
@ -396,8 +399,7 @@ function get_messages(int $uid, int $start, int $limit): array
LEFT JOIN `contact` c ON m.`contact-id` = c.`id`
WHERE m.`uid` = ?
ORDER BY m2.`mailcreated` DESC
LIMIT ?, ?'
, $uid, $uid, $start, $limit));
LIMIT ?, ?', $uid, $uid, $start, $limit));
}
function render_messages(array $msg, string $t): string

View file

@ -1022,7 +1022,7 @@ function photos_content()
}
}
$tags = ['title' => DI::l10n()->t('Tags: '), 'tags' => $tag_arr];
if ($cmd === 'edit') {
if ($cmd === 'edit' && !empty($tag_arr)) {
$tags['removeanyurl'] = 'post/' . $link_item['id'] . '/tag/remove?return=' . urlencode(DI::args()->getCommand());
$tags['removetitle'] = DI::l10n()->t('[Select tags to remove]');
}

View file

@ -201,8 +201,8 @@ class Page implements ArrayAccess
$this->page['title'] = $l10n->t(ucfirst($args->getModuleName()));
}
// Prepend the sitename to the page title
$this->page['title'] = $config->get('config', 'sitename', '') . (!empty($this->page['title']) ? ' | ' . $this->page['title'] : '');
// Append the sitename to the page title
$this->page['title'] = (!empty($this->page['title']) ? $this->page['title'] . ' | ' : '') . $config->get('config', 'sitename', '');
if (!empty(Renderer::$theme['stylesheet'])) {
$stylesheet = Renderer::$theme['stylesheet'];

View file

@ -265,7 +265,10 @@ class Conversation
$phrase = $this->l10n->tt('<button type="button" %2$s>%1$d person</button> likes this', '<button type="button" %2$s>%1$d people</button> like this', $total, $spanatts);
break;
case 'dislike':
$phrase = $this->l10n->tt('<button type="button" %2$s>%1$d person</button> doesn\'t like this', '<button type="button" %2$s>%1$d peiple</button> don\'t like this', $total, $spanatts);
$dislike_translation_plural = '<button type="button" %2$s>%1$d people</button> don\'t like this';
// @deprecated 2025.04 this translation is scheduled for removal as a new translation has been added without the typo
$dislike_translation_plural = '<button type="button" %2$s>%1$d peiple</button> don\'t like this';
$phrase = $this->l10n->tt('<button type="button" %2$s>%1$d person</button> doesn\'t like this', $dislike_translation_plural, $total, $spanatts);
break;
case 'attendyes':
$phrase = $this->l10n->tt('<button type="button" %2$s>%1$d person</button> attends', '<button type="button" %2$s>%1$d people</button> attend', $total, $spanatts);

View file

@ -913,13 +913,18 @@ class BBCode
default:
$text = ($is_quote_share ? "\n" : '');
$contact = Contact::getByURL($attributes['profile'], false, ['network']);
$contact = Contact::getByURL($attributes['profile'], false, ['network', 'url', 'alias']);
$network = $contact['network'] ?? Protocol::PHANTOM;
if (!empty($contact)) {
$profile = Contact::getProfileLink($contact);
} else {
$profile = $attributes['profile'];
}
$gsid = ContactSelector::getServerIdForProfile($attributes['profile']);
$tpl = Renderer::getMarkupTemplate('shared_content.tpl');
$text .= self::SHARED_ANCHOR . Renderer::replaceMacros($tpl, [
'$profile' => $attributes['profile'],
'$profile' => $profile,
'$avatar' => $attributes['avatar'],
'$author' => $attributes['author'],
'$link' => $attributes['link'],
@ -1205,13 +1210,13 @@ class BBCode
*/
private static function normalizeVideoLinks(string $text): string
{
$text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/watch\?v\=(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $text);
$text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/embed\/(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $text);
$text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/shorts\/(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $text);
$text = preg_replace("/\[youtube\]https?:\/\/youtu.be\/(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $text);
$text = preg_replace("/\[vimeo\]https?:\/\/player.vimeo.com\/video\/([0-9]+)(.*?)\[\/vimeo\]/ism", '[vimeo]$1[/vimeo]', $text);
$text = preg_replace("/\[vimeo\]https?:\/\/vimeo.com\/([0-9]+)(.*?)\[\/vimeo\]/ism", '[vimeo]$1[/vimeo]', $text);
$text = preg_replace("/\[youtube\]https?:\/\/(www\.)?youtube\.com\/watch\?v\=(.*?)\[\/youtube\]/ism", '[youtube]$2[/youtube]', $text);
$text = preg_replace("/\[youtube\]https?:\/\/(www\.)?youtube\.com\/embed\/(.*?)\[\/youtube\]/ism", '[youtube]$2[/youtube]', $text);
$text = preg_replace("/\[youtube\]https?:\/\/(www\.)?youtube\.com\/shorts\/(.*?)\[\/youtube\]/ism", '[youtube]$2[/youtube]', $text);
$text = preg_replace("/\[youtube\]https?:\/\/youtu\.be\/(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $text);
$text = preg_replace("/\[youtube\]https?:\/\/m\.youtube\.com\/watch\?v\=(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $text);
$text = preg_replace("/\[vimeo\]https?:\/\/player\.vimeo\.com\/video\/([0-9]+)(.*?)\[\/vimeo\]/ism", '[vimeo]$1[/vimeo]', $text);
$text = preg_replace("/\[vimeo\]https?:\/\/vimeo\.com\/([0-9]+)(.*?)\[\/vimeo\]/ism", '[vimeo]$1[/vimeo]', $text);
return $text;
}
@ -1984,12 +1989,25 @@ class BBCode
'<a href="$2" class="mention hashtag" rel="tag">$1<span>$3</span></a>',
$text
);
} elseif (in_array($simple_html, [self::INTERNAL, self::EXTERNAL, self::TWITTER_API])) {
} elseif (in_array($simple_html, [self::EXTERNAL, self::TWITTER_API])) {
$text = preg_replace(
"/([@!])\[url\=(.*?)\](.*?)\[\/url\]/ism",
'<bdi>$1<a href="$2" class="userinfo mention" title="$3">$3</a></bdi>',
$text
);
} elseif ($simple_html == self::INTERNAL) {
if (preg_match_all("/([@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", $text, $matches, PREG_SET_ORDER)) {
foreach ($matches as $match) {
$contact = Contact::getByURL($match[2], false, ['network', 'url', 'alias']);
if (!empty($contact)) {
$url = Contact::getProfileLink($contact);
} else {
$url = $match[2];
}
$text = str_replace($match[0], '<bdi>' . $match[1] . '<a href="' . $url . '" class="userinfo mention" title="' . $match[3] . '">' . $match[3] . '</a></bdi>', $text);
}
}
} elseif ($simple_html == self::MASTODON_API) {
$text = preg_replace(
"/([@!])\[url\=(.*?)\](.*?)\[\/url\]/ism",

View file

@ -689,7 +689,7 @@ class HTML
public static function toMarkdown(string $html): string
{
DI::profiler()->startRecording('rendering');
$converter = new HtmlConverter(['hard_break' => true]);
$converter = new HtmlConverter(['hard_break' => true, 'strip_tags' => true]);
$markdown = $converter->convert($html);
DI::profiler()->stopRecording();

View file

@ -121,11 +121,14 @@ class Markdown
$s = str_replace('&#x2672;', html_entity_decode('&#x2672;', ENT_QUOTES, 'UTF-8'), $s);
//$s = preg_replace("/([^\]\=]|^)(https?\:\/\/)(vimeo|youtu|www\.youtube|soundcloud)([a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url=$2$3$4]$2$3$4[/url]',$s);
$s = BBCode::pregReplaceInTag('/\[url\=?(.*?)\]https?:\/\/www.youtube.com\/watch\?v\=(.*?)\[\/url\]/ism', '[youtube]$2[/youtube]', 'url', $s);
$s = BBCode::pregReplaceInTag('/\[url\=https?:\/\/www.youtube.com\/watch\?v\=(.*?)\].*?\[\/url\]/ism', '[youtube]$1[/youtube]', 'url', $s);
$s = BBCode::pregReplaceInTag('/\[url\=https?:\/\/www.youtube.com\/shorts\/(.*?)\].*?\[\/url\]/ism', '[youtube]$1[/youtube]', 'url', $s);
$s = BBCode::pregReplaceInTag('/\[url\=?(.*?)\]https?:\/\/vimeo.com\/([0-9]+)(.*?)\[\/url\]/ism', '[vimeo]$2[/vimeo]', 'url', $s);
$s = BBCode::pregReplaceInTag('/\[url\=https?:\/\/vimeo.com\/([0-9]+)\](.*?)\[\/url\]/ism', '[vimeo]$1[/vimeo]', 'url', $s);
$s = BBCode::pregReplaceInTag('/\[url\=?(.*?)\]https?:\/\/www\.youtube\.com\/watch\?v\=(.*?)\[\/url\]/ism', '[youtube]$2[/youtube]', 'url', $s);
$s = BBCode::pregReplaceInTag('/\[url\=https?:\/\/(www\.)?youtube\.com\/watch\?v\=(.*?)\].*?\[\/url\]/ism', '[youtube]$2[/youtube]', 'url', $s);
$s = BBCode::pregReplaceInTag('/\[url\=https?:\/\/(www\.)?youtube\.com\/embed\/(.*?)\].*?\[\/url\]/ism', '[youtube]$2[/youtube]', 'url', $s);
$s = BBCode::pregReplaceInTag('/\[url\=https?:\/\/(www\.)?youtube\.com\/shorts\/(.*?)\].*?\[\/url\]/ism', '[youtube]$2[/youtube]', 'url', $s);
$s = BBCode::pregReplaceInTag('/\[url\=https?:\/\/m\.youtube\.com\/watch\?v\=(.*?)\].*?\[\/url\]/ism', '[youtube]$1[/youtube]', 'url', $s);
$s = BBCode::pregReplaceInTag('/\[url\=?(.*?)\]https?:\/\/vimeo\.com\/([0-9]+)(.*?)\[\/url\]/ism', '[vimeo]$2[/vimeo]', 'url', $s);
$s = BBCode::pregReplaceInTag('/\[url\=?(.*?)\]https?:\/\/player\.vimeo\.com\/video\/([0-9]+)(.*?)\[\/url\]/ism', '[vimeo]$2[/vimeo]', 'url', $s);
$s = BBCode::pregReplaceInTag('/\[url\=https?:\/\/vimeo\.com\/([0-9]+)\](.*?)\[\/url\]/ism', '[vimeo]$1[/vimeo]', 'url', $s);
// remove duplicate adjacent code tags
$s = preg_replace('/(\[code\])+(.*?)(\[\/code\])+/ism', '[code]$2[/code]', $s);

View file

@ -35,7 +35,7 @@ class Widget
return Renderer::replaceMacros(Renderer::getMarkupTemplate('widget/follow.tpl'), [
'$connect' => DI::l10n()->t('Add New Contact'),
'$desc' => DI::l10n()->t('Enter address or web location'),
'$hint' => DI::l10n()->t('Example: bob@example.com, http://example.com/barbara'),
'$hint' => DI::l10n()->t('user@x.tld, x.tld/user'),
'$value' => $value,
'$follow' => DI::l10n()->t('Connect')
]);

View file

@ -3330,7 +3330,7 @@ class Item
}
$dom = new \DOMDocument();
if (!@$dom->loadHTML($html)) {
if (empty($html) || !@$dom->loadHTML($html)) {
return $html;
}

View file

@ -41,13 +41,13 @@ class Site extends BaseAdmin
return;
}
$sitename = (!empty($_POST['sitename']) ? trim($_POST['sitename']) : '');
$sitename = (!empty($_POST['sitename']) ? strip_tags(trim($_POST['sitename'])) : '');
$sender_email = (!empty($_POST['sender_email']) ? trim($_POST['sender_email']) : '');
$banner = (!empty($_POST['banner']) ? trim($_POST['banner']) : false);
$email_banner = (!empty($_POST['email_banner']) ? trim($_POST['email_banner']) : false);
$shortcut_icon = (!empty($_POST['shortcut_icon']) ? trim($_POST['shortcut_icon']) : '');
$touch_icon = (!empty($_POST['touch_icon']) ? trim($_POST['touch_icon']) : '');
$additional_info = (!empty($_POST['additional_info']) ? trim($_POST['additional_info']) : '');
$additional_info = (!empty($_POST['additional_info']) ? strip_tags(trim($_POST['additional_info'])) : '');
$language = (!empty($_POST['language']) ? trim($_POST['language']) : '');
$theme = (!empty($_POST['theme']) ? trim($_POST['theme']) : '');
$theme_mobile = (!empty($_POST['theme_mobile']) ? trim($_POST['theme_mobile']) : '');

View file

@ -254,7 +254,9 @@ class Contact extends BaseModule
$searching = true;
$search_hdr = $search;
$search_txt = preg_quote(trim($search, ' @!'));
$sql_extra .= " AND (`name` REGEXP ? OR `url` REGEXP ? OR `nick` REGEXP ? OR `addr` REGEXP ? OR `alias` REGEXP ?)";
$sql_extra .= " AND (CAST(`name` AS BINARY) REGEXP BINARY ? OR CAST(`url` AS BINARY) REGEXP BINARY ?";
$sql_extra .= " OR CAST(`nick` AS BINARY) REGEXP BINARY ? OR CAST(`addr` AS BINARY) REGEXP BINARY ?";
$sql_extra .= " OR CAST(`alias` AS BINARY) REGEXP BINARY ?)";
$sql_values[] = $search_txt;
$sql_values[] = $search_txt;
$sql_values[] = $search_txt;

View file

@ -26,7 +26,6 @@ use Friendica\Moderation\Entity\Report;
use Friendica\Module\Response;
use Friendica\Navigation\SystemMessages;
use Friendica\Network\HTTPException\ForbiddenException;
use Friendica\Util\Network;
use Friendica\Util\Profiler;
use Psr\Log\LoggerInterface;
@ -221,11 +220,19 @@ class Create extends BaseModule
}
if (DI::mode()->isMobile()) {
$itemsPerPage = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'itemspage_mobile_network',
DI::config()->get('system', 'itemspage_network_mobile'));
$itemsPerPage = DI::pConfig()->get(
DI::userSession()->getLocalUserId(),
'system',
'itemspage_mobile_network',
DI::config()->get('system', 'itemspage_network_mobile')
);
} else {
$itemsPerPage = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'itemspage_network',
DI::config()->get('system', 'itemspage_network'));
$itemsPerPage = DI::pConfig()->get(
DI::userSession()->getLocalUserId(),
'system',
'itemspage_network',
DI::config()->get('system', 'itemspage_network')
);
}
$pager = new Pager(DI::l10n(), DI::args()->getQueryString(), $itemsPerPage);
@ -260,6 +267,11 @@ class Create extends BaseModule
$contact = Contact::getById($request['cid'], ['url']);
$tpl = Renderer::getMarkupTemplate('moderation/report/create/summary.tpl');
$forward_translation = $this->t('Would you like to forward this report to the remote server?');
// @deprecated 2025.04 this translation is scheduled for removal as a new translation has been added without the typo
$forward_translation = $this->t('Would you ike to forward this report to the remote server?');
return Renderer::replaceMacros($tpl, [
'$l10n' => [
'title' => $this->t('Create Moderation Report'),
@ -280,7 +292,7 @@ class Create extends BaseModule
'$block' => ['contact_action', $this->t('Block contact'), self::CONTACT_ACTION_BLOCK, $this->t("Their posts won't appear in your Network page anymore, but their replies can appear in forum threads, with their content collapsed by default. They cannot follow you but still can have access to your public posts by other means.")],
'$display_forward' => !$this->baseUrl->isLocalUrl($contact['url']),
'$forward' => ['report_forward', $this->t('Forward report'), self::CONTACT_ACTION_BLOCK, $this->t('Would you ike to forward this report to the remote server?')],
'$forward' => ['report_forward', $this->t('Forward report'), self::CONTACT_ACTION_BLOCK, $forward_translation],
'$summary' => $this->getAside($request),
]);
@ -294,12 +306,18 @@ class Create extends BaseModule
}
switch ($request['category'] ?? 0) {
case Report::CATEGORY_SPAM: $category = $this->t('Spam'); break;
case Report::CATEGORY_ILLEGAL: $category = $this->t('Illegal Content'); break;
case Report::CATEGORY_SAFETY: $category = $this->t('Community Safety'); break;
case Report::CATEGORY_UNWANTED: $category = $this->t('Unwanted Content/Behavior'); break;
case Report::CATEGORY_VIOLATION: $category = $this->t('Rules Violation'); break;
case Report::CATEGORY_OTHER: $category = $this->t('Other'); break;
case Report::CATEGORY_SPAM: $category = $this->t('Spam');
break;
case Report::CATEGORY_ILLEGAL: $category = $this->t('Illegal Content');
break;
case Report::CATEGORY_SAFETY: $category = $this->t('Community Safety');
break;
case Report::CATEGORY_UNWANTED: $category = $this->t('Unwanted Content/Behavior');
break;
case Report::CATEGORY_VIOLATION: $category = $this->t('Rules Violation');
break;
case Report::CATEGORY_OTHER: $category = $this->t('Other');
break;
default: $category = '';
}

View file

@ -54,7 +54,7 @@ class Remove extends \Friendica\BaseModule
protected function content(array $request = []): string
{
$returnUrl = hex2bin($request['return'] ?? '');
$returnUrl = $request['return'] ?? '';
if (!$this->session->getLocalUserId()) {
$this->baseUrl->redirect($returnUrl);
@ -97,7 +97,7 @@ class Remove extends \Friendica\BaseModule
],
'$item_id' => $item_id,
'$return' => $returnUrl,
'$return' => urlencode($returnUrl),
'$tag_checkboxes' => $tag_checkboxes,
]);
}

View file

@ -128,8 +128,8 @@ class Photos extends \Friendica\Module\BaseProfile
$request = $hook_data['request'] ?? $request;
// Determine the album to use
$album = trim($request['album'] ?? '');
$newalbum = trim($request['newalbum'] ?? '');
$album = strip_tags(trim($request['album'] ?? ''));
$newalbum = strip_tags(trim($request['newalbum'] ?? ''));
$this->logger->debug('album= ' . $album . ' newalbum= ' . $newalbum);

View file

@ -192,6 +192,11 @@ class Channels extends BaseSettings
}
$t = Renderer::getMarkupTemplate('settings/channels.tpl');
$exclude_tags_translation = $this->t('Comma separated list of tags. If a post contain any of these tags, then it will not be part of this channel.');
// @deprecated 2025.04 this translation is scheduled for removal as a new translation has been added without the typo
$exclude_tags_translation = $this->t('Comma separated list of tags. If a post contain any of these tags, then it will not be part of nthis channel.');
return Renderer::replaceMacros($t, [
'open' => count($channels) == 0,
'label' => ["new_label", $this->t('Label'), '', $this->t('Short name for the channel. It is displayed on the channels widget.'), $this->t('Required')],
@ -199,7 +204,7 @@ class Channels extends BaseSettings
'access_key' => ["new_access_key", $this->t("Access Key"), '', $this->t('When you want to access this channel via an access key, you can define it here. Pay attention to not use an already used one.')],
'circle' => ['new_circle', $this->t('Circle/Channel'), 0, $this->t('Select a circle or channel, that your channel should be based on.'), $circles],
'include_tags' => ["new_include_tags", $this->t("Include Tags"), '', $this->t('Comma separated list of tags. A post will be used when it contains any of the listed tags.')],
'exclude_tags' => ["new_exclude_tags", $this->t("Exclude Tags"), '', $this->t('Comma separated list of tags. If a post contain any of these tags, then it will not be part of nthis channel.')],
'exclude_tags' => ["new_exclude_tags", $this->t("Exclude Tags"), '', $exclude_tags_translation],
'min_size' => ["new_min_size", $this->t("Minimum Size"), '', $this->t('Minimum post size. Leave empty for no minimum size. The size is calculated without links, attached posts, mentions or hashtags.')],
'max_size' => ["new_max_size", $this->t("Maximum Size"), '', $this->t('Maximum post size. Leave empty for no maximum size. The size is calculated without links, attached posts, mentions or hashtags.')],
'text_search' => ["new_text_search", $this->t("Full Text Search"), '', $this->t('Search terms for the body, supports the "boolean mode" operators from MariaDB. See the help for a complete list of operators and additional keywords: %s', '<a href="help/Channels">help/Channels</a>')],

View file

@ -99,7 +99,7 @@ class Index extends BaseSettings
new ArrayFilterEvent(ArrayFilterEvent::PROFILE_SETTINGS_POST, $request),
)->getArray();
$dob = trim($request['dob'] ?? '');
$dob = $this->cleanInput($request['dob'] ?? '');
if ($dob && !in_array($dob, ['0000-00-00', DBA::NULL_DATE])) {
$y = substr($dob, 0, 4);
@ -121,18 +121,18 @@ class Index extends BaseSettings
}
}
$username = trim($request['username'] ?? '');
$username = $this->cleanInputText($request['username'] ?? '');
if (!$username) {
$this->systemMessages->addNotice($this->t('Display Name is required.'));
return;
}
$about = trim($request['about']);
$address = trim($request['address']);
$locality = trim($request['locality']);
$region = trim($request['region']);
$postal_code = trim($request['postal_code']);
$country_name = trim($request['country_name']);
$about = $this->cleanInputText($request['about']);
$address = $this->cleanInputText($request['address']);
$locality = $this->cleanInputText($request['locality']);
$region = $this->cleanInputText($request['region']);
$postal_code = $this->cleanInputText($request['postal_code']);
$country_name = $this->cleanInputText($request['country_name']);
$pub_keywords = self::cleanKeywords(trim($request['pub_keywords']));
$prv_keywords = self::cleanKeywords(trim($request['prv_keywords']));
$xmpp = $this->cleanInput(trim($request['xmpp']));
@ -377,9 +377,14 @@ class Index extends BaseSettings
return $profileFields;
}
private function cleanInputText(string $input): string
{
return trim(strip_tags($input));
}
private function cleanInput(string $input): string
{
return str_replace(['<', '>', '"', ' '], '', $input);
return str_replace(['<', '>', '"', "'", ' '], '', $input);
}
private static function cleanKeywords($keywords): string
@ -389,7 +394,7 @@ class Index extends BaseSettings
$cleaned = [];
foreach ($keywords as $keyword) {
$keyword = trim($keyword);
$keyword = trim(str_replace(['<', '>', '"', "'"], '', $keyword));
$keyword = trim($keyword, '#');
if ($keyword != '') {
$cleaned[] = $keyword;

View file

@ -133,7 +133,7 @@ class Actor
}
$directory = $this->atprotocol->get(ATProtocol::DIRECTORY . '/' . $profile->did);
if (!empty($directory)) {
if (!empty($directory->service)) {
foreach ($directory->service as $service) {
if (($service->id == '#atproto_pds') && ($service->type == 'AtprotoPersonalDataServer') && !empty($service->serviceEndpoint)) {
$fields['baseurl'] = $service->serviceEndpoint;
@ -145,12 +145,14 @@ class Actor
$fields['gsid'] = GServer::getRealID($fields['baseurl'], true);
}
if (!empty($directory->verificationMethod)) {
foreach ($directory->verificationMethod as $method) {
if (!empty($method->publicKeyMultibase)) {
$fields['pubkey'] = $method->publicKeyMultibase;
}
}
}
}
Contact::update($fields, ['nurl' => $profile->did, 'network' => Protocol::BLUESKY]);

View file

@ -84,6 +84,8 @@ class Jetstream
$timeout_limit = 10;
$timestamp = $this->keyValue->get('jetstream_timestamp') ?? 0;
$cursor = '';
$this->logger->notice('Start listening');
while (true) {
if ($timestamp) {
$cursor = '&cursor=' . $timestamp;
@ -97,7 +99,7 @@ class Jetstream
$this->client->setTimeout($timeout);
$this->client->setLogger($this->logger);
} catch (\WebSocket\ConnectionException $e) {
$this->logger->error('Error while trying to establish the connection', ['code' => $e->getCode(), 'message' => $e->getMessage()]);
$this->logger->error('Error while trying to establish the connection', ['code' => $e->getCode(), 'message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine()]);
echo "Connection wasn't established.\n";
exit(1);
}
@ -106,6 +108,11 @@ class Jetstream
while (true) {
try {
$message = $this->client->receive();
if (empty($message)) {
$this->logger->notice('Empty message received');
break;
}
$data = json_decode($message);
if (is_object($data)) {
$timestamp = $data->time_us;
@ -124,8 +131,9 @@ class Jetstream
break;
}
$this->logger->notice('Timeout', ['duration' => $timeout_duration, 'timestamp' => $timestamp, 'code' => $e->getCode(), 'message' => $e->getMessage()]);
break;
} else {
$this->logger->error('Error', ['code' => $e->getCode(), 'message' => $e->getMessage()]);
$this->logger->error('Error while trying to receive a message', ['code' => $e->getCode(), 'message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine()]);
break;
}
}
@ -134,9 +142,10 @@ class Jetstream
try {
$this->client->close();
} catch (\WebSocket\ConnectionException $e) {
$this->logger->error('Error while trying to close the connection', ['code' => $e->getCode(), 'message' => $e->getMessage()]);
$this->logger->error('Error while trying to close the connection', ['code' => $e->getCode(), 'message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine()]);
}
}
$this->logger->notice('Stop listening');
}
/**
@ -232,7 +241,7 @@ class Jetstream
try {
$this->client->send(json_encode($update));
} catch (\WebSocket\ConnectionException $e) {
$this->logger->error('Error while trying to send options.', ['code' => $e->getCode(), 'message' => $e->getMessage()]);
$this->logger->error('Error while trying to send options.', ['code' => $e->getCode(), 'message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine()]);
}
}

View file

@ -506,14 +506,11 @@ class Processor
break;
case 'app.bsky.richtext.facet#mention':
$contact = Contact::getByURL($feature->did, null, ['id']);
if (!empty($contact['id'])) {
$url = $this->baseURL . '/contact/' . $contact['id'];
$url = $feature->did;
if (substr($linktext, 0, 1) == '@') {
$prefix .= '@';
$linktext = substr($linktext, 1);
}
}
break;
case 'app.bsky.richtext.facet#tag':

View file

@ -2065,7 +2065,7 @@ class Receiver
}
foreach ($object_data['tags'] as $tag) {
if (HTTPSignature::isValidContentType($tag['mediaType'] ?? '', $tag['href'])) {
if (HTTPSignature::isValidContentType($tag['mediaType'] ?? '', $tag['href'] ?? '')) {
$object_data['quote-url'] = $tag['href'];
}
}

View file

@ -132,13 +132,13 @@ class PermissionSet extends BaseRepository
}
if (!empty($user_contact_str)) {
$condition = ["`uid` = ? AND (NOT (LOCATE(?, `deny_cid`) OR LOCATE(?, `deny_cid`) OR deny_gid REGEXP ?)
AND (LOCATE(?, allow_cid) OR LOCATE(?, allow_cid) OR allow_gid REGEXP ? OR (allow_cid = '' AND allow_gid = '')))",
$condition = ["`uid` = ? AND (NOT (LOCATE(?, `deny_cid`) OR LOCATE(?, `deny_cid`) OR CAST(deny_gid AS BINARY) REGEXP BINARY ?)
AND (LOCATE(?, allow_cid) OR LOCATE(?, allow_cid) OR CAST(allow_gid AS BINARY) REGEXP BINARY ? OR (allow_cid = '' AND allow_gid = '')))",
$uid, $user_contact_str, $public_contact_str, $circle_str,
$user_contact_str, $public_contact_str, $circle_str];
} else {
$condition = ["`uid` = ? AND (NOT (LOCATE(?, `deny_cid`) OR deny_gid REGEXP ?)
AND (LOCATE(?, allow_cid) OR allow_gid REGEXP ? OR (allow_cid = '' AND allow_gid = '')))",
$condition = ["`uid` = ? AND (NOT (LOCATE(?, `deny_cid`) OR CAST(deny_gid AS BINARY) REGEXP BINARY ?)
AND (LOCATE(?, allow_cid) OR CAST(allow_gid AS BINARY) REGEXP BINARY ? OR (allow_cid = '' AND allow_gid = '')))",
$uid, $public_contact_str, $circle_str, $public_contact_str, $circle_str];
}

View file

@ -105,8 +105,8 @@ class Security
}
$sql = sprintf(
" AND (NOT (deny_cid REGEXP '<%d>' OR deny_gid REGEXP '%s')
AND (allow_cid REGEXP '<%d>' OR allow_gid REGEXP '%s'
" AND (NOT (CAST(deny_cid AS BINARY) REGEXP BINARY '<%d>' OR CAST(deny_gid AS BINARY) REGEXP BINARY '%s')
AND (CAST(allow_cid AS BINARY) REGEXP BINARY '<%d>' OR CAST(allow_gid AS BINARY) REGEXP BINARY '%s'
OR (allow_cid = '' AND allow_gid = ''))" . $acc_sql . ") ",
intval($remote_contact),
DBA::escape($circleIds),

View file

@ -88,6 +88,11 @@ return [
'uri' => 'https://friendica.local/profile/mutualcontact',
'guid' => '46',
],
[
'id' => 49,
'uri' => 'https://domain.tld/profile/remotecontact',
'guid' => '49',
],
[
'id' => 100,
'uri' => 'https://friendica.local/posts/100',
@ -214,6 +219,23 @@ return [
'network' => Protocol::DFRN,
'location' => 'DFRN',
],
[
'id' => 49,
'uid' => 0,
'uri-id' => 43,
'name' => 'Remote user',
'nick' => 'remotecontact',
'self' => 0,
'nurl' => 'http://domain.tld/profile/remotecontact',
'url' => 'https://domain.tld/profile/remotecontact',
'alias' => 'https://domain.tld/~remotecontact',
'about' => 'User used in tests',
'pending' => 0,
'blocked' => 0,
'rel' => Contact::FOLLOWER,
'network' => Protocol::ACTIVITYPUB,
'location' => 'AP',
],
],
'apcontact' => [
[

View file

@ -73,51 +73,51 @@ class BBCodeTest extends FixtureTestCase
],
'no-protocol' => [
'data' => 'example.com/path',
'assertHTML' => false
'assertHTML' => false,
],
'wrong-protocol' => [
'data' => 'ftp://example.com',
'assertHTML' => false
'assertHTML' => false,
],
'wrong-domain-without-path' => [
'data' => 'http://example',
'assertHTML' => false
'assertHTML' => false,
],
'wrong-domain-with-path' => [
'data' => 'http://example/path',
'assertHTML' => false
'assertHTML' => false,
],
'bug-6857-domain-start' => [
'data' => "http://\nexample.com",
'assertHTML' => false
'assertHTML' => false,
],
'bug-6857-domain-end' => [
'data' => "http://example\n.com",
'assertHTML' => false
'assertHTML' => false,
],
'bug-6857-tld' => [
'data' => "http://example.\ncom",
'assertHTML' => false
'assertHTML' => false,
],
'bug-6857-end' => [
'data' => "http://example.com\ntest",
'assertHTML' => false
'assertHTML' => false,
],
'bug-6901' => [
'data' => "http://example.com<ul>",
'assertHTML' => false
'assertHTML' => false,
],
'bug-7150' => [
'data' => html_entity_decode('http://example.com&nbsp;', ENT_QUOTES, 'UTF-8'),
'assertHTML' => false
'assertHTML' => false,
],
'bug-7271-query-string-brackets' => [
'data' => 'https://example.com/search?q=square+brackets+[url]',
'assertHTML' => true
'assertHTML' => true,
],
'bug-7271-path-brackets' => [
'data' => 'http://example.com/path/to/file[3].html',
'assertHTML' => true
'assertHTML' => true,
],
];
}
@ -215,19 +215,19 @@ class BBCodeTest extends FixtureTestCase
],
'bug-9611-purify-xss-nobb' => [
'expectedHTML' => '<span>dare to move your mouse here</span>',
'text' => '[nobb]<span onmouseover="alert(0)">dare to move your mouse here</span>[/nobb]'
'text' => '[nobb]<span onmouseover="alert(0)">dare to move your mouse here</span>[/nobb]',
],
'bug-9611-purify-xss-noparse' => [
'expectedHTML' => '<span>dare to move your mouse here</span>',
'text' => '[noparse]<span onmouseover="alert(0)">dare to move your mouse here</span>[/noparse]'
'text' => '[noparse]<span onmouseover="alert(0)">dare to move your mouse here</span>[/noparse]',
],
'bug-9611-purify-xss-attributes' => [
'expectedHTML' => '<span>dare to move your mouse here</span>',
'text' => '[color="onmouseover=alert(0) style="]dare to move your mouse here[/color]'
'text' => '[color="onmouseover=alert(0) style="]dare to move your mouse here[/color]',
],
'bug-9611-purify-attributes-correct' => [
'expectedHTML' => '<span style="color:#FFFFFF;">dare to move your mouse here</span>',
'text' => '[color=FFFFFF]dare to move your mouse here[/color]'
'text' => '[color=FFFFFF]dare to move your mouse here[/color]',
],
'bug-9639-span-classes' => [
'expectedHTML' => '<span class="arbitrary classes">Test</span>',
@ -308,11 +308,16 @@ Karl Marx - Die ursprüngliche Akkumulation
],
'bug-12701-quotes' => [
'expected' => '[![abc"fgh](https://domain.tld/photo/86912721086415cdc8e0a03226831581-1.png)](https://domain.tld/photos/user/image/86912721086415cdc8e0a03226831581)',
'text' => '[url=https://domain.tld/photos/user/image/86912721086415cdc8e0a03226831581][img=https://domain.tld/photo/86912721086415cdc8e0a03226831581-1.png]abc"fgh[/img][/url]'
'text' => '[url=https://domain.tld/photos/user/image/86912721086415cdc8e0a03226831581][img=https://domain.tld/photo/86912721086415cdc8e0a03226831581-1.png]abc"fgh[/img][/url]',
],
'bug-12701-no-quotes' => [
'expected' => '[![abcfgh](https://domain.tld/photo/86912721086415cdc8e0a03226831581-1.png "abcfgh")](https://domain.tld/photos/user/image/86912721086415cdc8e0a03226831581)',
'text' => '[url=https://domain.tld/photos/user/image/86912721086415cdc8e0a03226831581][img=https://domain.tld/photo/86912721086415cdc8e0a03226831581-1.png]abcfgh[/img][/url]'
'text' => '[url=https://domain.tld/photos/user/image/86912721086415cdc8e0a03226831581][img=https://domain.tld/photo/86912721086415cdc8e0a03226831581-1.png]abcfgh[/img][/url]',
],
/** @see https://github.com/friendica/friendica/pull/14908 */
'task-14908-strip-tags' => [
'expected' => 'Norddeutscher Bürger !\[Noddeutscher Bürger - Bismark Brötchen (Roger Cziwerny - pixapay)\](/rscamo/……)',
'text' => '[class=postbox-ocean]Norddeutscher Bürger ![Noddeutscher Bürger - Bismark Brötchen (Roger Cziwerny - pixapay)](/rscamo/……)[/class]',
],
];
}
@ -345,7 +350,7 @@ Karl Marx - Die ursprüngliche Akkumulation
'bug-10692-start-line' => [
'#[url=https://friendica.local/search?tag=L160]L160[/url]',
'#L160',
]
],
];
}
@ -362,6 +367,62 @@ Karl Marx - Die ursprüngliche Akkumulation
self::assertEquals($expected, $actual);
}
public function dataExpandVideoLinks(): array
{
return [
/** @see https://github.com/friendica/friendica/pull/14940 */
'task-14940-youtube-watch-with-www' => [
'expectedBBCode' => '[url=https://www.youtube.com/watch?v=hfwbmTzBFT0]https://www.youtube.com/watch?v=hfwbmTzBFT0[/url]',
'text' => '[youtube]https://www.youtube.com/watch?v=hfwbmTzBFT0[/youtube]',
],
'task-14940-youtube-watch-without-www' => [
'expectedBBCode' => '[url=https://www.youtube.com/watch?v=hfwbmTzBFT0]https://www.youtube.com/watch?v=hfwbmTzBFT0[/url]',
'text' => '[youtube]https://youtube.com/watch?v=hfwbmTzBFT0[/youtube]',
],
'task-14940-youtube-shorts-with-www' => [
'expectedBBCode' => '[url=https://www.youtube.com/watch?v=hfwbmTzBFT0]https://www.youtube.com/watch?v=hfwbmTzBFT0[/url]',
'text' => '[youtube]https://www.youtube.com/shorts/hfwbmTzBFT0[/youtube]',
],
'task-14940-youtube-shorts-without-www' => [
'expectedBBCode' => '[url=https://www.youtube.com/watch?v=hfwbmTzBFT0]https://www.youtube.com/watch?v=hfwbmTzBFT0[/url]',
'text' => '[youtube]https://youtube.com/shorts/hfwbmTzBFT0[/youtube]',
],
'task-14940-youtube-embed-with-www' => [
'expectedBBCode' => '[url=https://www.youtube.com/watch?v=hfwbmTzBFT0]https://www.youtube.com/watch?v=hfwbmTzBFT0[/url]',
'text' => '[youtube]https://www.youtube.com/embed/hfwbmTzBFT0[/youtube]',
],
'task-14940-youtube-embed-without-www' => [
'expectedBBCode' => '[url=https://www.youtube.com/watch?v=hfwbmTzBFT0]https://www.youtube.com/watch?v=hfwbmTzBFT0[/url]',
'text' => '[youtube]https://youtube.com/embed/hfwbmTzBFT0[/youtube]',
],
'task-14940-youtube-mobile' => [
'expectedBBCode' => '[url=https://www.youtube.com/watch?v=hfwbmTzBFT0]https://www.youtube.com/watch?v=hfwbmTzBFT0[/url]',
'text' => '[youtube]https://m.youtube.com/watch?v=hfwbmTzBFT0[/youtube]',
],
'task-14940-vimeo' => [
'expectedBBCode' => '[url=https://vimeo.com/2345345]https://vimeo.com/2345345[/url]',
'text' => '[vimeo]https://vimeo.com/2345345[/vimeo]',
],
'task-14940-player-vimeo' => [
'expectedBBCode' => '[url=https://vimeo.com/2345345]https://vimeo.com/2345345[/url]',
'text' => '[vimeo]https://player.vimeo.com/video/2345345[/vimeo]',
],
];
}
/**
* @dataProvider dataExpandVideoLinks
*
* @param string $expected Expected BBCode output
* @param string $text Input text
*/
public function testExpandVideoLinks(string $expected, string $text)
{
$actual = BBCode::expandVideoLinks($text);
self::assertEquals($expected, $actual);
}
public function dataGetAbstract(): array
{
return [
@ -615,4 +676,27 @@ Lucas: For the right price, yes.[/share]',
self::assertEquals($expected, $actual);
}
public function dataProfileLink(): array
{
return [
'mention' => [
'expected' => 'Test 1: <bdi>@<a href="https://domain.tld/~remotecontact" class="userinfo mention" title="Remote contact">Remote contact</a></bdi>',
'text' => 'Test 1: @[url=https://domain.tld/profile/remotecontact]Remote contact[/url]',
],
];
}
/**
* @dataProvider dataProfileLink
*
* @param string $expected Expected BBCode output
* @param string $text Input text
*/
public function testProfileLink(string $expected, string $text)
{
$actual = BBCode::convertForUriId(0, $text);
self::assertEquals($expected, $actual);
}
}

View file

@ -53,6 +53,48 @@ class MarkdownTest extends FixtureTestCase
'expectedBBCode' => 'with the <sup> and </sup> tag',
'markdown' => 'with the &lt;sup&gt; and &lt;/sup&gt; tag',
],
/** @see https://github.com/friendica/friendica/pull/14940 */
'task-14940-youtube-watch-with-www' => [
'expectedBBCode' => '[youtube]hfwbmTzBFT0[/youtube]',
'markdown' => '[url=https://www.youtube.com/watch?v=hfwbmTzBFT0]https://www.youtube.com/watch?v=hfwbmTzBFT0[/url]',
],
'task-14940-youtube-watch-without-www' => [
'expectedBBCode' => '[youtube]hfwbmTzBFT0[/youtube]',
'markdown' => '[url=https://youtube.com/watch?v=hfwbmTzBFT0]https://youtube.com/watch?v=hfwbmTzBFT0[/url]',
],
'task-14940-youtube-shorts-with-www' => [
'expectedBBCode' => '[youtube]hfwbmTzBFT0[/youtube]',
'markdown' => '[url=https://www.youtube.com/shorts/hfwbmTzBFT0]https://www.youtube.com/shorts/hfwbmTzBFT0[/url]',
],
'task-14940-youtube-shorts-without-www' => [
'expectedBBCode' => '[youtube]hfwbmTzBFT0[/youtube]',
'markdown' => '[url=https://youtube.com/shorts/hfwbmTzBFT0]https://youtube.com/shorts/hfwbmTzBFT0[/url]',
],
'task-14940-youtube-embed-with-www' => [
'expectedBBCode' => '[youtube]hfwbmTzBFT0[/youtube]',
'markdown' => '[url=https://www.youtube.com/embed/hfwbmTzBFT0]https://www.youtube.com/embed/hfwbmTzBFT0[/url]',
],
'task-14940-youtube-embed-without-www' => [
'expectedBBCode' => '[youtube]hfwbmTzBFT0[/youtube]',
'markdown' => '[url=https://youtube.com/embed/hfwbmTzBFT0]https://youtube.com/embed/hfwbmTzBFT0[/url]',
],
'task-14940-youtube-mobile' => [
'expectedBBCode' => '[youtube]hfwbmTzBFT0[/youtube]',
'markdown' => '[url=https://m.youtube.com/watch?v=hfwbmTzBFT0]https://m.youtube.com/watch?v=hfwbmTzBFT0[/url]',
],
// @todo - should we really ignore the URL content in favor of parsing the link of the body?
'task-14940-vimeo-custom-url' => [
'expectedBBCode' => '[vimeo]2345345[/vimeo]',
'markdown' => '[url=https://no.thing]https://vimeo.com/2345345[/url]',
],
'task-14940-vimeo-custom-text' => [
'expectedBBCode' => '[vimeo]2345345[/vimeo]',
'markdown' => '[url=https://vimeo.com/2345345]CustomText[/url]',
],
'task-14940-player-vimeo' => [
'expectedBBCode' => '[vimeo]2345345[/vimeo]',
'markdown' => '[url=https://player.vimeo.com/video/2345345]https://player.vimeo.com/video/2345345[/url]',
],
];
}

File diff suppressed because it is too large Load diff

View file

@ -572,6 +572,11 @@ nav.navbar {
}
}
button#main-menu {
align-items: center;
display: flex;
gap: 5px;
}
#topbar-first .navbar-toggle {
margin-top: 5px;
margin-bottom: 0;
@ -602,7 +607,6 @@ nav.navbar .nav > li > button:focus {
margin-left: 20px;
}
#topbar-first .nav > .account img {
margin-left: 10px;
height: 32px;
width: 32px;
border-radius: 3px;
@ -784,7 +788,6 @@ nav.navbar .nav > li > button:focus {
/* The Top Nav Bar user menu */
#topbar-first .account .user-title {
text-align: right;
margin-top: 7px;
}
#topbar-first .account .user-title span {
color: $nav_icon_color;
@ -2460,7 +2463,7 @@ input[type="range"].form-control {
.form-group-search .form-button-search {
position: absolute;
top: 4px;
top: 2px;
right: 4px;
border-radius: 30px;
}