Merge remote-tracking branch 'upstream/develop' into http-417

This commit is contained in:
Michael 2019-10-17 21:37:24 +00:00
commit 36ba7fa79c
316 changed files with 39229 additions and 36498 deletions

View file

@ -1,10 +1,14 @@
codecov:
branch: develop
ci:
- drone.friendi.ca
coverage: coverage:
precision: 2
round: down
range: "70...100"
status: status:
project: project: off
default: patch: off
target: auto
threshold: null
base: auto
comment: off comment: off

439
.drone.yml Normal file
View file

@ -0,0 +1,439 @@
kind: pipeline
name: mysql8.0-php7.1
steps:
- name: mysql8.0-php7.1
image: friendicaci/php7.1:php7.1.32
commands:
- NOCOVERAGE=true ./autotest.sh mysql
environment:
MYSQL_USERNAME: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
MYSQL_HOST: mysql
services:
- name: mysql
image: mysql:8.0
command: [ "--default-authentication-plugin=mysql_native_password" ]
environment:
MYSQL_ROOT_PASSWORD: friendica
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
volumes:
- name: cache
path: /var/lib/mysql
volumes:
- name: cache
temp: {}
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: mysql8.0-php7.2
steps:
- name: mysql8.0-php7.2
image: friendicaci/php7.2:php7.2.22
commands:
- NOCOVERAGE=true ./autotest.sh mysql
environment:
MYSQL_USERNAME: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
MYSQL_HOST: mysql
services:
- name: mysql
image: mysql:8.0
command: [ "--default-authentication-plugin=mysql_native_password" ]
environment:
MYSQL_ROOT_PASSWORD: friendica
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
volumes:
- name: cache
path: /var/lib/mysql
volumes:
- name: cache
temp: {}
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: mysql8.0-php7.3
steps:
- name: mysql8.0-php7.3
image: friendicaci/php7.3:php7.3.9
commands:
- NOCOVERAGE=true ./autotest.sh mysql
environment:
MYSQL_USERNAME: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
MYSQL_HOST: mysql
services:
- name: mysql
image: mysql:8.0
command: [ "--default-authentication-plugin=mysql_native_password" ]
environment:
MYSQL_ROOT_PASSWORD: friendica
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
volumes:
- name: cache
path: /var/lib/mysql
volumes:
- name: cache
temp: {}
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: mariadb10.1-php7.1
steps:
- name: mariadb10.1-php7.1
image: friendicaci/php7.1:php7.1.32
commands:
- phpenmod xdebug
- sleep 20
- ./autotest.sh mariadb
- wget https://codecov.io/bash -O codecov.sh
- sh -c "if [ '$DRONE_BUILD_EVENT' = 'pull_request' ]; then bash codecov.sh -B $DRONE_BRANCH -C $DRONE_COMMIT -P $DRONE_PULL_REQUEST -t 5ce7d64e-07b4-4adf-8700-e2eae27e14ec -f tests/autotest-clover.xml; fi"
- sh -c "if [ '$DRONE_BUILD_EVENT' != 'pull_request' ]; then bash codecov.sh -B $DRONE_BRANCH -C $DRONE_COMMIT -t 5ce7d64e-07b4-4adf-8700-e2eae27e14ec -f tests/autotest-clover.xml; fi"
environment:
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
MYSQL_HOST: mariadb
services:
- name: mariadb
image: mariadb:10.1
environment:
MYSQL_ROOT_PASSWORD: friendica
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
volumes:
- name: cache
path: /var/lib/mysql
volumes:
- name: cache
temp: {}
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: mariadb10.1-php7.2
steps:
- name: mariadb10.1-php7.2
image: friendicaci/php7.2:php7.2.22
commands:
- NOCOVERAGE=true ./autotest.sh mariadb
environment:
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
MYSQL_HOST: mariadb
services:
- name: mariadb
image: mariadb:10.1
environment:
MYSQL_ROOT_PASSWORD: friendica
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
volumes:
- name: cache
path: /var/lib/mysql
volumes:
- name: cache
temp: {}
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: mariadb10.1-php7.3
steps:
- name: mariadb10.1-php7.3
image: friendicaci/php7.3:php7.3.9
commands:
- NOCOVERAGE=true ./autotest.sh mariadb
environment:
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
MYSQL_HOST: mariadb
services:
- name: mariadb
image: mariadb:10.1
environment:
MYSQL_ROOT_PASSWORD: friendica
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
volumes:
- name: cache
path: /var/lib/mysql
volumes:
- name: cache
temp: {}
---
kind: pipeline
name: redis-php7.1
steps:
- name: redis-php7.1
image: friendicaci/php7.1:php7.1.32
commands:
- phpenmod xdebug
- sleep 20
- NOINSTALL=true TEST_SELECTION=REDIS ./autotest.sh mysql
- wget https://codecov.io/bash -O codecov.sh
- sh -c "if [ '$DRONE_BUILD_EVENT' = 'pull_request' ]; then bash codecov.sh -B $DRONE_BRANCH -C $DRONE_COMMIT -P $DRONE_PULL_REQUEST -t 5ce7d64e-07b4-4adf-8700-e2eae27e14ec -f tests/autotest-clover.xml; fi"
- sh -c "if [ '$DRONE_BUILD_EVENT' != 'pull_request' ]; then bash codecov.sh -B $DRONE_BRANCH -C $DRONE_COMMIT -t 5ce7d64e-07b4-4adf-8700-e2eae27e14ec -f tests/autotest-clover.xml; fi"
environment:
REDIS_HOST: redis
services:
- name: redis
image: redis
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: redis-php7.2
steps:
- name: redis-php7.2
image: friendicaci/php7.2:php7.2.22
commands:
- NOCOVERAGE=true NOINSTALL=true TEST_SELECTION=REDIS ./autotest.sh mysql
environment:
REDIS_HOST: redis
services:
- name: redis
image: redis
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: redis-php7.3
steps:
- name: redis-php7.3
image: friendicaci/php7.3:php7.3.9
commands:
- NOCOVERAGE=true NOINSTALL=true TEST_SELECTION=REDIS ./autotest.sh mysql
environment:
REDIS_HOST: redis
services:
- name: redis
image: redis
---
kind: pipeline
name: memcache-php7.1
steps:
- name: memcache-php7.1
image: friendicaci/php7.1:php7.1.32
commands:
- phpenmod xdebug
- sleep 20
- NOINSTALL=true TEST_SELECTION=MEMCACHE ./autotest.sh mysql
- wget https://codecov.io/bash -O codecov.sh
- sh -c "if [ '$DRONE_BUILD_EVENT' = 'pull_request' ]; then bash codecov.sh -B $DRONE_BRANCH -C $DRONE_COMMIT -P $DRONE_PULL_REQUEST -t 5ce7d64e-07b4-4adf-8700-e2eae27e14ec -f tests/autotest-clover.xml; fi"
- sh -c "if [ '$DRONE_BUILD_EVENT' != 'pull_request' ]; then bash codecov.sh -B $DRONE_BRANCH -C $DRONE_COMMIT -t 5ce7d64e-07b4-4adf-8700-e2eae27e14ec -f tests/autotest-clover.xml; fi"
environment:
MEMCACHE_HOST: memcached
services:
- name: memcached
image: memcached
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: memcache-php7.2
steps:
- name: memcache-php7.2
image: friendicaci/php7.2:php7.2.22
commands:
- NOCOVERAGE=true NOINSTALL=true TEST_SELECTION=MEMCACHE ./autotest.sh mysql
environment:
MEMCACHE_HOST: memcached
services:
- name: memcached
image: memcached
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: memcache-php7.3
steps:
- name: memcache-php7.3
image: friendicaci/php7.3:php7.3.9
commands:
- NOCOVERAGE=true NOINSTALL=true TEST_SELECTION=MEMCACHE ./autotest.sh mysql
environment:
MEMCACHE_HOST: memcached
services:
- name: memcached
image: memcached
---
kind: pipeline
name: memcached-php7.1
steps:
- name: memcached-php7.1
image: friendicaci/php7.1:php7.1.32
commands:
- phpenmod xdebug
- sleep 20
- NOINSTALL=true TEST_SELECTION=MEMCACHED ./autotest.sh mysql
- wget https://codecov.io/bash -O codecov.sh
- sh -c "if [ '$DRONE_BUILD_EVENT' = 'pull_request' ]; then bash codecov.sh -B $DRONE_BRANCH -C $DRONE_COMMIT -P $DRONE_PULL_REQUEST -t 5ce7d64e-07b4-4adf-8700-e2eae27e14ec -f tests/autotest-clover.xml; fi"
- sh -c "if [ '$DRONE_BUILD_EVENT' != 'pull_request' ]; then bash codecov.sh -B $DRONE_BRANCH -C $DRONE_COMMIT -t 5ce7d64e-07b4-4adf-8700-e2eae27e14ec -f tests/autotest-clover.xml; fi"
environment:
MEMCACHED_HOST: memcached
services:
- name: memcached
image: memcached
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: memcached-php7.2
steps:
- name: memcached-php7.2
image: friendicaci/php7.2:php7.2.22
commands:
- NOCOVERAGE=true NOINSTALL=true TEST_SELECTION=MEMCACHED ./autotest.sh mysql
environment:
MEMCACHED_HOST: memcached
services:
- name: memcached
image: memcached
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: memcached-php7.3
steps:
- name: memcached-php7.3
image: friendicaci/php7.3:php7.3.9
commands:
- NOCOVERAGE=true NOINSTALL=true TEST_SELECTION=MEMCACHED ./autotest.sh mysql
environment:
MEMCACHED_HOST: memcached
services:
- name: memcached
image: memcached

View file

@ -26,4 +26,4 @@ before_script:
- phpenv config-add .travis/redis.ini - phpenv config-add .travis/redis.ini
- phpenv config-add .travis/memcached.ini - phpenv config-add .travis/memcached.ini
after_success: bash <(curl -s https://codecov.io/bash) script: vendor/bin/phpunit --configuration tests/phpunit.xml

View file

@ -1,24 +1,44 @@
Version 2019.09-dev (UNRELEASED) Version 2019.12-dev (unreleased)
Friendica Core: Friendica Core:
Update to the translations (CS, DE, FR, JA, NL) [translation teams] Enhanced the manage functionality [annando]
Fixed some problems with the remote auth functionality [annando]
Added router configuration file [nupplaphil]
Added drone.io as CI service [nupplaphil]
Friendica Addons:
mailstream:
Support for new img format was added [mexon]
BB Code is now included as plaintext [mexon]
Logging format is enhanced [mexon]
ActivityPub "announce" notifications are not included [mexon]
Closed Issues:
1071, 7548, 7657, 7681
Version 2019.09 (2019-09-29)
Friendica Core:
Update to the translations (CS, DE, EN GB, EN US, FR, JA, NL, PL) [translation teams]
Update to the themes (frio, vier) [JeroenED, MrPetovan, tobiasd, vinzv] Update to the themes (frio, vier) [JeroenED, MrPetovan, tobiasd, vinzv]
Update to the documentation [guzzisti, vinzv] Update to the documentation [annando, tobiasd, guzzisti, vinzv]
Enhanced the log output of the background process [annando] Enhanced the log output of the background process [annando]
Enhanced the vcard translation in the profile (JeroenED) Enhanced the vcard translation in the profile [JeroenED]
Enhanced the delivery count [annando] Enhanced the delivery count [annando]
Enhanced ActivityPub envelopes [MrPetovan] Enhanced ActivityPub envelopes [MrPetovan]
Enhanced communication about deleted accounts via AP [annando]
Enhanced the following process [annando] Enhanced the following process [annando]
Enhanced the tests [nupplaphil] Enhanced the tests [nupplaphil]
Enhanced the frontend worker [annando] Enhanced the front-end worker [annando]
Enhanced the img format to allow alternative texts [annando] Enhanced the img format to allow alternative texts [annando]
Enhanced the detection of supported protocols for contacts [annando] Enhanced the detection of supported protocols for contacts [annando]
Enhanced the reshare of items [annando] Enhanced the re-share of items [annando]
Enhanced 2FA process [MrPetovan] Enhanced 2FA process [MrPetovan]
Enhanced server wide theme settings [MrPetovan] Enhanced server wide theme settings [MrPetovan]
Enhanced config loading process [MrPetovan, nupplaphil] Enhanced config loading process [MrPetovan, nupplaphil]
Enhanced handling of emoticons [MrPetovan] Enhanced handling of emoticons [MrPetovan]
Fixed a bug in the admin panel leading to orphand options [tobiasd] Enhanced performance [annando]
Fixed a bug in the admin panel leading to orphaned options [tobiasd]
Fixed a problem that could lead to duplicated Pleroma contacts [annando] Fixed a problem that could lead to duplicated Pleroma contacts [annando]
Fixed a problem with the hide profile setting [annando]
Fixed the problem sending out the post when hitting the enter key in the ACL dialog [MrPetovan] Fixed the problem sending out the post when hitting the enter key in the ACL dialog [MrPetovan]
Fixed a bug in HTML special character escaping of event titles [MrPetovan] Fixed a bug in HTML special character escaping of event titles [MrPetovan]
Fixed a bug in HTML special character conversion in item titles [MrPetovan] Fixed a bug in HTML special character conversion in item titles [MrPetovan]
@ -26,7 +46,19 @@ Version 2019.09-dev (UNRELEASED)
Fixed a bug that prevented the display of images in some postings from diaspora* [MrPetovan] Fixed a bug that prevented the display of images in some postings from diaspora* [MrPetovan]
Fixed a bug in setting the permissions on uploaded images [annando] Fixed a bug in setting the permissions on uploaded images [annando]
Fixed a bug that lead to potentially unwanted importing threads started by contacts of contacts [annando] Fixed a bug that lead to potentially unwanted importing threads started by contacts of contacts [annando]
Fixed implicit self mentions [MrPetovan]
Fixed display of register links on closed nodes landing pages [MrPetovan] Fixed display of register links on closed nodes landing pages [MrPetovan]
Fixed the display of [spoiler] tags [MrPetovan]
Fixed an issue with photo permissions in private mails [annando]
Fixed a bug in the process of following Pleroma accounts [annando]
Fixed a bug that caused notifications about locally deleted items [annando]
Fixed the link to the source of an event [MrPetovan]
Fixed a problem that caused authors from twitter postings having no profile pic [annando]
Fixed a bug in BBCode -> Markdown conversation for font size [annando]
Fixed a BBCode parser problem with the audio tag [MrPetovan]
Fixed a session problem [annando]
Fixed a problem with the auto-installer [nupplaphil]
Fixed a bug with magic links redirection for non profiles [annando]
General code cleaning [annando, MrPetovan, nupplaphil] General code cleaning [annando, MrPetovan, nupplaphil]
Removed contacts auto completion (in /contacts [MrPetovan] Removed contacts auto completion (in /contacts [MrPetovan]
Replaced FontAwesome by ForkAwesome in frio theme [vinzv] Replaced FontAwesome by ForkAwesome in frio theme [vinzv]
@ -37,19 +69,29 @@ Version 2019.09-dev (UNRELEASED)
Added support of wildcards to server block lists [MrPetovan] Added support of wildcards to server block lists [MrPetovan]
Added app specific passwords when using 2FA [MrPetovan] Added app specific passwords when using 2FA [MrPetovan]
Added fetching of postings via URL to interact with public postings [annando] Added fetching of postings via URL to interact with public postings [annando]
Added opt-out flag for federated search engines and associated header information for profiles [annando]
Friendica Addons: Friendica Addons:
Update to the translation (CS, DE, FR, JA, NL SV) [translation teams] Update to the translation (CS, DE, EN GB, EN US, ES, FR, JA, NL SV) [translation teams]
General code cleanup [nupplaphil, Quix0r] General code cleanup [nupplaphil, Quix0r]
blockbot:
Added translations
Added more bots [annando]
Added admin panel settings [annando]
tumblr:
Changed used URLs to https adopting tumblrs change [annando]
twitter: twitter:
Enhanced handling of multi image postings [annando] Enhanced handling of multi image postings [annando]
Enhanced display of quoted tweets [MrPetovan]
Added alternative text support for images [annando] Added alternative text support for images [annando]
Closed Issues: Closed Issues:
3816, 4815, 6384, 6675, 7235, 7293, 7314, 7317, 7337, 7338, 7346, 870, 1605, 2199, 3239, 3816, 4117, 4815, 5721, 6384, 6521, 6553,
7350, 7367, 7383, 7396, 7397, 7401, 7406, 7408, 7426, 7428, 7456, 6675, 7212, 7235, 7285, 7293, 7314, 7317, 7337, 7338, 7346, 7350,
7442, 7457, 7468, 7471, 7473, 7488, 7497, 7498, 7501, 7507, 7522, 7367, 7383, 7396, 7397, 7401, 7406, 7408, 7426, 7428, 7456, 7442,
7527, 7536, 7542, 7545 7457, 7468, 7471, 7473, 7488, 7497, 7498, 7501, 7507, 7521, 7526,
7527, 7536, 7542, 7545, 7576, 7586, 7594, 7597, 7603, 7610, 7618,
7629, 7635, 7638, 7663, 7665, 7672
Version 2019.06 (2019-06-23) Version 2019.06 (2019-06-23)
Friendica Core: Friendica Core:

View file

@ -1 +1 @@
2019.09-rc 2019.12-dev

4
Vagrantfile vendored
View file

@ -6,8 +6,8 @@ server_timezone = "UTC"
public_folder = "/vagrant" public_folder = "/vagrant"
Vagrant.configure(2) do |config| Vagrant.configure(2) do |config|
# Set server to Ubuntu 16.04 # Set server to Debian 10 / Buster 64bit
config.vm.box = "ubuntu/xenial64" config.vm.box = "debian/buster64"
# Disable automatic box update checking. If you disable this, then # Disable automatic box update checking. If you disable this, then
# boxes will only be checked for updates when the user runs # boxes will only be checked for updates when the user runs

279
autotest.sh Executable file
View file

@ -0,0 +1,279 @@
#!/usr/bin/env bash
#
# This script is used for autotesting the Friendica codebase with different
# types of tests and environments.
#
# Currently, there are three types of autotesting possibilities:
# - "USEDOCKER=true ./autotest.sh" will start a database docker container for testing
# - "./autotest.sh" on the Drone CI environment will use the database container of the drone CI pipeline
# - "./autotest.sh" on a local environment will try to use the local database instance for testing
#
# You can specify a database (mysql, mariadb currently) for the db backend of Friendica ("./autotest.sh mysql")
# And you can specify some parameters for the test, like:
# - NOCOVERAGE=true ... Don't create a coverage XML (this is only useful if you will send coverage to codecov.io)
# - NOINSTALL=true ... Skip the whole Friendica installation process (e.g. you just test Caching drivers)
# - TEST_SELECTION= ... Specify which tests are used to run (based on the test-labeling)
# - XDEBUG_CONFIG= ... Set some XDEBUG specific environment settings for development
DATABASENAME=${MYSQL_DATABASE:-test}
DATABASEUSER=${MYSQL_USERNAME:-friendica}
DATABASEHOST=${MYSQL_HOST:-localhost}
BASEDIR=$PWD
DBCONFIGS="mysql mariadb"
TESTS="REDIS MEMCACHE MEMCACHED APCU NODB"
export MYSQL_DATABASE="$DATABASENAME"
export MYSQL_USERNAME="$DATABASEUSER"
export MYSQL_PASSWORD="friendica"
if [ -z "$PHP_EXE" ]; then
PHP_EXE=php
fi
PHP=$(which "$PHP_EXE")
# Use the Friendica internal composer
COMPOSER="$BASEDIR/bin/composer.phar"
set -e
_XDEBUG_CONFIG=$XDEBUG_CONFIG
unset XDEBUG_CONFIG
function show_syntax() {
echo -e "Syntax: ./autotest.sh [dbconfigname] [testfile]\n" >&2
echo -e "\t\"dbconfigname\" can be one of: $DBCONFIGS" >&2
echo -e "\t\"testfile\" is the name of a test file, for example lib/template.php" >&2
echo -e "\nDatabase environment variables:\n" >&2
echo -e "\t\"MYSQL_HOST\" Mysql Hostname (Default: localhost)" >&2
echo -e "\t\"MYSQL_USDRNAME\" Mysql Username (Default: friendica)" >&2
echo -e "\t\"MYSQL_DATABASE\" Mysql Database (Default: test)" >&2
echo -e "\nOther environment variables:\n" >&2
echo -e "\t\"TEST_SELECTION\" test a specific group of tests, can be one of: $TESTS" >&2
echo -e "\t\"NOINSTALL\" If set to true, skip the db and install process" >&2
echo -e "\t\"NOCOVERAGE\" If set to true, don't create a coverage output" >&2
echo -e "\t\"USEDOCKER\" If set to true, the DB server will be executed inside a docker container" >&2
echo -e "\nExample: NOCOVERAGE=true ./autotest.sh mysql src/Core/Cache/MemcacheTest.php" >&2
echo "will run the test suite from \"tests/src/Core/Cache/MemcacheTest.php\" without a Coverage" >&2
echo -e "\nIf no arguments are specified, all tests will be run with all database configs" >&2
}
if [ -x "$PHP" ]; then
echo "Using PHP executable $PHP"
else
echo "Could not find PHP executable $PHP_EXE" >&2
exit 3
fi
echo "Installing depdendencies"
$PHP "$COMPOSER" install
PHPUNIT="$BASEDIR/vendor/bin/phpunit"
if [ -x "$PHPUNIT" ]; then
echo "Using PHPUnit executable $PHPUNIT"
else
echo "Could not find PHPUnit executable after composer $PHPUNIT" >&2
exit 3
fi
if ! [ \( -w config -a ! -f config/local.config.php \) -o \( -f config/local.config.php -a -w config/local.config.php \) ]; then
echo "Please enable write permissions on config and config/config.php" >&2
exit 1
fi
if [ "$1" ]; then
FOUND=0
for DBCONFIG in $DBCONFIGS; do
if [ "$1" = "$DBCONFIG" ]; then
FOUND=1
break
fi
done
if [ $FOUND = 0 ]; then
echo -e "Unknown database config name \"$1\"\n" >&2
show_syntax
exit 2
fi
fi
# Back up existing (dev) config if one exists and backup not already there
if [ -f config/local.config.php ] && [ ! -f config/local.config-autotest-backup.php ]; then
mv config/local.config.php config/local.config-autotest-backup.php
fi
function cleanup_config() {
if [ -n "$DOCKER_CONTAINER_ID" ]; then
echo "Kill the docker $DOCKER_CONTAINER_ID"
docker stop "$DOCKER_CONTAINER_ID"
docker rm -f "$DOCKER_CONTAINER_ID"
fi
cd "$BASEDIR"
# Restore existing config
if [ -f config/local.config-autotest-backup.php ]; then
mv config/local.config-autotest-backup.php config/local.config.php
fi
}
# restore config on exit
trap cleanup_config EXIT
function execute_tests() {
DB=$1
echo "Setup environment for $DB testing ..."
# back to root folder
cd "$BASEDIR"
# backup current config
if [ -f config/local.config.php ]; then
mv config/local.config.php config/local.config-autotest-backup.php
fi
if [ -z "$NOINSTALL" ]; then
#drop database
if [ "$DB" == "mysql" ]; then
if [ -n "$USEDOCKER" ]; then
echo "Fire up the mysql docker"
DOCKER_CONTAINER_ID=$(docker run \
-e MYSQL_ROOT_PASSWORD=friendica \
-e MYSQL_USER="$DATABASEUSER" \
-e MYSQL_PASSWORD=friendica \
-e MYSQL_DATABASE="$DATABASENAME" \
-d mysql)
DATABASEHOST=$(docker inspect --format="{{.NetworkSettings.IPAddress}}" "$DOCKER_CONTAINER_ID")
else
if [ -z "$DRONE" ]; then # no need to drop the DB when we are on CI
if [ "mysql" != "$(mysql --version | grep -o mysql)" ]; then
echo "Your mysql binary is not provided by mysql"
echo "To use the docker container set the USEDOCKER environment variable"
exit 3
fi
mysql -u "$DATABASEUSER" -pfriendica -e "DROP DATABASE IF EXISTS $DATABASENAME" -h $DATABASEHOST || true
mysql -u "$DATABASEUSER" -pfriendica -e "CREATE DATABASE $DATABASENAME DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci" -h $DATABASEHOST
else
DATABASEHOST=mysql
fi
fi
echo "Waiting for MySQL $DATABASEHOST initialization..."
if ! bin/wait-for-connection $DATABASEHOST 3306 300; then
echo "[ERROR] Waited 300 seconds, no response" >&2
exit 1
fi
echo "MySQL is up."
fi
if [ "$DB" == "mariadb" ]; then
if [ -n "$USEDOCKER" ]; then
echo "Fire up the mariadb docker"
DOCKER_CONTAINER_ID=$(docker run \
-e MYSQL_ROOT_PASSWORD=friendica \
-e MYSQL_USER="$DATABASEUSER" \
-e MYSQL_PASSWORD=friendica \
-e MYSQL_DATABASE="$DATABASENAME" \
-d mariadb)
DATABASEHOST=$(docker inspect --format="{{.NetworkSettings.IPAddress}}" "$DOCKER_CONTAINER_ID")
else
if [ -z "$DRONE" ]; then # no need to drop the DB when we are on CI
if [ "MariaDB" != "$(mysql --version | grep -o MariaDB)" ]; then
echo "Your mysql binary is not provided by mysql"
echo "To use the docker container set the USEDOCKER environment variable"
exit 3
fi
mysql -u "$DATABASEUSER" -pfriendica -e "DROP DATABASE IF EXISTS $DATABASENAME" -h $DATABASEHOST || true
mysql -u "$DATABASEUSER" -pfriendica -e "CREATE DATABASE $DATABASENAME DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci" -h $DATABASEHOST
else
DATABASEHOST=mariadb
fi
fi
echo "Waiting for MariaDB $DATABASEHOST initialization..."
if ! bin/wait-for-connection $DATABASEHOST 3306 300; then
echo "[ERROR] Waited 300 seconds, no response" >&2
exit 1
fi
echo "MariaDB is up."
fi
if [ -n "$USEDOCKER" ]; then
echo "Initialize database..."
docker exec $DOCKER_CONTAINER_ID mysql -u root -pfriendica -e 'CREATE DATABASE IF NOT EXISTS $DATABASENAME;'
fi
export MYSQL_HOST="$DATABASEHOST"
#call installer
echo "Installing Friendica..."
"$PHP" ./bin/console.php autoinstall --dbuser="$DATABASEUSER" --dbpass=friendica --dbdata="$DATABASENAME" --dbhost="$DATABASEHOST" --url=https://friendica.local --admin=admin@friendica.local
fi
#test execution
echo "Testing..."
rm -fr "coverage-html"
mkdir "coverage-html"
if [[ "$_XDEBUG_CONFIG" ]]; then
export XDEBUG_CONFIG=$_XDEBUG_CONFIG
fi
COVER=''
if [ -z "$NOCOVERAGE" ]; then
COVER="--coverage-clover tests/autotest-clover.xml"
else
echo "No coverage"
fi
# per default, there is no cache installed
GROUP='--exclude-group REDIS,MEMCACHE,MEMCACHED,APCU'
if [ "$TEST_SELECTION" == "REDIS" ]; then
GROUP="--group REDIS"
fi
if [ "$TEST_SELECTION" == "MEMCACHE" ]; then
GROUP="--group MEMCACHE"
fi
if [ "$TEST_SELECTION" == "MEMCACHED" ]; then
GROUP="--group MEMCACHED"
fi
if [ "$TEST_SELECTION" == "APCU" ]; then
GROUP="--group APCU"
fi
if [ "$TEST_SELECTION" == "NODB" ]; then
GROUP="--exclude-group DB,SLOWDB"
fi
INPUT="$BASEDIR/tests"
if [ -n "$2" ]; then
INPUT="$INPUT/$2"
fi
echo "${PHPUNIT[@]}" --configuration tests/phpunit.xml $GROUP $COVER --log-junit "autotest-results.xml" "$INPUT" "$3"
"${PHPUNIT[@]}" --configuration tests/phpunit.xml $GROUP $COVER --log-junit "autotest-results.xml" "$INPUT" "$3"
RESULT=$?
if [ -n "$DOCKER_CONTAINER_ID" ]; then
echo "Kill the docker $DOCKER_CONTAINER_ID"
docker stop $DOCKER_CONTAINER_ID
docker rm -f $DOCKER_CONTAINER_ID
unset $DOCKER_CONTAINER_ID
fi
}
#
# Start the test execution
#
if [ -z "$1" ] && [ -n "$TEST_SELECTION" ]; then
# run all known database configs
for DBCONFIG in $DBCONFIGS; do
execute_tests "$DBCONFIG"
done
else
FILENAME="$2"
if [ -n "$2" ] && [ ! -f "tests/$FILENAME" ] && [ "${FILENAME:0:2}" != "--" ]; then
FILENAME="../$FILENAME"
fi
execute_tests "$1" "$FILENAME" "$3"
fi

View file

@ -36,6 +36,7 @@ use Dice\Dice;
use Friendica\App\Mode; use Friendica\App\Mode;
use Friendica\BaseObject; use Friendica\BaseObject;
use Friendica\Util\ExAuth; use Friendica\Util\ExAuth;
use Psr\Log\LoggerInterface;
if (sizeof($_SERVER["argv"]) == 0) { if (sizeof($_SERVER["argv"]) == 0) {
die(); die();
@ -54,6 +55,8 @@ chdir($directory);
require dirname(__DIR__) . '/vendor/autoload.php'; require dirname(__DIR__) . '/vendor/autoload.php';
$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php'); $dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['auth_ejabberd']]);
BaseObject::setDependencyInjection($dice); BaseObject::setDependencyInjection($dice);
$appMode = $dice->create(Mode::class); $appMode = $dice->create(Mode::class);

View file

@ -2,9 +2,11 @@
<?php <?php
use Dice\Dice; use Dice\Dice;
use Psr\Log\LoggerInterface;
require dirname(__DIR__) . '/vendor/autoload.php'; require dirname(__DIR__) . '/vendor/autoload.php';
$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php'); $dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['console']]);
(new Friendica\Core\Console($dice, $argv))->execute(); (new Friendica\Core\Console($dice, $argv))->execute();

View file

@ -12,6 +12,7 @@ use Friendica\Core\Config;
use Friendica\Core\Logger; use Friendica\Core\Logger;
use Friendica\Core\Worker; use Friendica\Core\Worker;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Psr\Log\LoggerInterface;
// Get options // Get options
$shortopts = 'f'; $shortopts = 'f';
@ -33,6 +34,7 @@ if (!file_exists("boot.php") && (sizeof($_SERVER["argv"]) != 0)) {
require dirname(__DIR__) . '/vendor/autoload.php'; require dirname(__DIR__) . '/vendor/autoload.php';
$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php'); $dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['daemon']]);
\Friendica\BaseObject::setDependencyInjection($dice); \Friendica\BaseObject::setDependencyInjection($dice);
$a = \Friendica\BaseObject::getApp(); $a = \Friendica\BaseObject::getApp();

View file

@ -48,9 +48,9 @@ sudo systemctl restart apache2
#Install mysql #Install mysql
echo ">>> Installing Mysql" echo ">>> Installing Mysql"
sudo debconf-set-selections <<< "mysql-server mysql-server/root_password password root" sudo debconf-set-selections <<< "mariadb-server mariadb-server/root_password password root"
sudo debconf-set-selections <<< "mysql-server mysql-server/root_password_again password root" sudo debconf-set-selections <<< "mariadb-server mariadb-server/root_password_again password root"
sudo apt-get install -qq mysql-server sudo apt-get install -qq mariadb-server
# enable remote access # enable remote access
# setting the mysql bind-address to allow connections from everywhere # setting the mysql bind-address to allow connections from everywhere
sed -i "s/bind-address.*/bind-address = 0.0.0.0/" /etc/mysql/my.cnf sed -i "s/bind-address.*/bind-address = 0.0.0.0/" /etc/mysql/my.cnf
@ -76,6 +76,9 @@ debconf-set-selections <<< "postfix postfix/main_mailer_type string 'Local Only'
sudo apt-get install -y postfix mailutils libmailutils-dev sudo apt-get install -y postfix mailutils libmailutils-dev
sudo echo -e "friendica1: vagrant\nfriendica2: vagrant\nfriendica3: vagrant\nfriendica4: vagrant\nfriendica5: vagrant" >> /etc/aliases && sudo newaliases sudo echo -e "friendica1: vagrant\nfriendica2: vagrant\nfriendica3: vagrant\nfriendica4: vagrant\nfriendica5: vagrant" >> /etc/aliases && sudo newaliases
# Friendica needs git for fetching some dependencies
sudo apt-get install -y git
#make the vagrant directory the docroot #make the vagrant directory the docroot
sudo rm -rf /var/www/ sudo rm -rf /var/www/
sudo ln -fs /vagrant /var/www sudo ln -fs /vagrant /var/www
@ -83,7 +86,7 @@ sudo ln -fs /vagrant /var/www
# install deps with composer # install deps with composer
sudo apt install unzip sudo apt install unzip
cd /var/www cd /var/www
php bin/composer.phar install sudo -u www-data php bin/composer.phar install
# initial config file for friendica in vagrant # initial config file for friendica in vagrant
cp /vagrant/mods/local.config.vagrant.php /vagrant/config/local.config.php cp /vagrant/mods/local.config.vagrant.php /vagrant/config/local.config.php

45
bin/wait-for-connection Executable file
View file

@ -0,0 +1,45 @@
#!/usr/bin/php
#
# This script tries to connect to a database for a given interval
# Useful in case of installation e.g. to wait for the database to not generate unnecessary errors
#
# Usage: php bin/wait-for-connection {HOST} {PORT} [{TIMEOUT}]
<?php
$timeout = 60;
switch ($argc) {
case 4:
$timeout = (float)$argv[3];
case 3:
$host = $argv[1];
$port = (int)$argv[2];
break;
default:
fwrite(STDERR, 'Usage: '.$argv[0].' host port [timeout]'."\n");
exit(2);
}
if ($timeout < 0) {
fwrite(STDERR, 'Timeout must be greater than zero'."\n");
exit(2);
}
if ($port < 1) {
fwrite(STDERR, 'Port must be an integer greater than zero'."\n");
exit(2);
}
$socketTimeout = (float)ini_get('default_socket_timeout');
if ($socketTimeout > $timeout) {
$socketTimeout = $timeout;
}
$stopTime = time() + $timeout;
do {
$sock = @fsockopen($host, $port, $errno, $errstr, $socketTimeout);
if ($sock !== false) {
fclose($sock);
fwrite(STDOUT, "\n");
exit(0);
}
sleep(1);
fwrite(STDOUT, '.');
} while (time() < $stopTime);
fwrite(STDOUT, "\n");
exit(1);

View file

@ -11,6 +11,7 @@ use Friendica\BaseObject;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\Update; use Friendica\Core\Update;
use Friendica\Core\Worker; use Friendica\Core\Worker;
use Psr\Log\LoggerInterface;
// Get options // Get options
$shortopts = 'sn'; $shortopts = 'sn';
@ -32,6 +33,7 @@ if (!file_exists("boot.php") && (sizeof($_SERVER["argv"]) != 0)) {
require dirname(__DIR__) . '/vendor/autoload.php'; require dirname(__DIR__) . '/vendor/autoload.php';
$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php'); $dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['worker']]);
BaseObject::setDependencyInjection($dice); BaseObject::setDependencyInjection($dice);
$a = BaseObject::getApp(); $a = BaseObject::getApp();

View file

@ -23,6 +23,7 @@ use Friendica\Core\Config;
use Friendica\Core\PConfig; use Friendica\Core\PConfig;
use Friendica\Core\Protocol; use Friendica\Core\Protocol;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Model\Term; use Friendica\Model\Term;
@ -31,7 +32,7 @@ use Friendica\Util\DateTimeFormat;
define('FRIENDICA_PLATFORM', 'Friendica'); define('FRIENDICA_PLATFORM', 'Friendica');
define('FRIENDICA_CODENAME', 'Dalmatian Bellflower'); define('FRIENDICA_CODENAME', 'Dalmatian Bellflower');
define('FRIENDICA_VERSION', '2019.09-rc'); define('FRIENDICA_VERSION', '2019.12-dev');
define('DFRN_PROTOCOL_VERSION', '2.23'); define('DFRN_PROTOCOL_VERSION', '2.23');
define('NEW_UPDATE_ROUTINE_VERSION', 1170); define('NEW_UPDATE_ROUTINE_VERSION', 1170);
@ -321,47 +322,6 @@ function get_app()
return BaseObject::getApp(); return BaseObject::getApp();
} }
/**
* Return the provided variable value if it exists and is truthy or the provided
* default value instead.
*
* Works with initialized variables and potentially uninitialized array keys
*
* Usages:
* - defaults($var, $default)
* - defaults($array, 'key', $default)
*
* @param array $args
* @brief Returns a defaut value if the provided variable or array key is falsy
* @return mixed
* @deprecated since version 2019.06, use native coalesce operator (??) instead
*/
function defaults(...$args)
{
if (count($args) < 2) {
throw new BadFunctionCallException('defaults() requires at least 2 parameters');
}
if (count($args) > 3) {
throw new BadFunctionCallException('defaults() cannot use more than 3 parameters');
}
if (count($args) === 3 && is_null($args[1])) {
throw new BadFunctionCallException('defaults($arr, $key, $def) $key is null');
}
// The default value always is the last argument
$return = array_pop($args);
if (count($args) == 2 && is_array($args[0]) && !empty($args[0][$args[1]])) {
$return = $args[0][$args[1]];
}
if (count($args) == 1 && !empty($args[0])) {
$return = $args[0];
}
return $return;
}
/** /**
* @brief Used to end the current process, after saving session state. * @brief Used to end the current process, after saving session state.
* @deprecated * @deprecated
@ -415,20 +375,14 @@ function public_contact()
*/ */
function remote_user() function remote_user()
{ {
// You cannot be both local and remote. if (empty($_SESSION['authenticated'])) {
// Unncommented by rabuzarus because remote authentication to local
// profiles wasn't possible anymore (2018-04-12).
// if (local_user()) {
// return false;
// }
if (empty($_SESSION)) {
return false; return false;
} }
if (!empty($_SESSION['authenticated']) && !empty($_SESSION['visitor_id'])) { if (!empty($_SESSION['visitor_id'])) {
return intval($_SESSION['visitor_id']); return intval($_SESSION['visitor_id']);
} }
return false; return false;
} }
@ -532,7 +486,7 @@ function is_site_admin()
$adminlist = explode(',', str_replace(' ', '', $admin_email)); $adminlist = explode(',', str_replace(' ', '', $admin_email));
return local_user() && $admin_email && in_array(defaults($a->user, 'email', ''), $adminlist); return local_user() && $admin_email && in_array($a->user['email'] ?? '', $adminlist);
} }
function explode_querystring($query) function explode_querystring($query)

564
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -533,7 +533,7 @@ Here is a complete list of all hook callbacks with file locations (as of 24-Sep-
Hook::callAll("parse_link", $arr); Hook::callAll("parse_link", $arr);
### mod/manage.php ### src/Module/Delegation.php
Hook::callAll('home_init', $ret); Hook::callAll('home_init', $ret);

View file

@ -602,6 +602,9 @@ While taking pictures in the woods I had a really strange encounter...</td>
The [abstract] element is not working with connectors where we post HTML directly, like Tumblr, Wordpress or Pump.io. The [abstract] element is not working with connectors where we post HTML directly, like Tumblr, Wordpress or Pump.io.
For the native connections--that is to e.g. Friendica, Hubzilla, Diaspora or GNU Social--the full posting is used and the contacts instance will display the posting as desired. For the native connections--that is to e.g. Friendica, Hubzilla, Diaspora or GNU Social--the full posting is used and the contacts instance will display the posting as desired.
For postings that are delivered via ActivityPub, the text from the abstract is placed in the summary field.
On Mastodon this field is used for the content warning.
## Special ## Special
<table class="bbcodes"> <table class="bbcodes">

View file

@ -81,6 +81,7 @@ Here's a few primers if you are new to Friendica or to the PSR-2 coding standard
* No closing PHP tag * No closing PHP tag
* No trailing spaces * No trailing spaces
* Array declarations use the new square brackets syntax * Array declarations use the new square brackets syntax
* Quoting style is single quotes by default, except for needed string interpolation, SQL query strings by convention and comments that should stay in natural language.
Don't worry, you don't have to know by heart the PSR-2 coding standards to start contributing to Friendica. Don't worry, you don't have to know by heart the PSR-2 coding standards to start contributing to Friendica.
There are a few tools you can use to check or fix your files before you commit. There are a few tools you can use to check or fix your files before you commit.

View file

@ -40,7 +40,7 @@ You are not required to do this, but the alternative is to log out and log back
This could get cumbersome if you manage several different forums/identities. This could get cumbersome if you manage several different forums/identities.
You may also appoint a delegate to manage your forum. You may also appoint a delegate to manage your forum.
Do this by visiting the [Delegation Setup Page](delegate). Do this by visiting the [Delegation Setup Page](settings/delegation).
This will provide you with a list of contacts on this system under "Potential Delegates". This will provide you with a list of contacts on this system under "Potential Delegates".
Selecting one or more persons will give them access to manage your forum. Selecting one or more persons will give them access to manage your forum.
They will be able to edit contacts, profiles, and all content for this account/page. They will be able to edit contacts, profiles, and all content for this account/page.

View file

@ -11,13 +11,13 @@ with your web browser.
You will need to be logged in at the time. You will need to be logged in at the time.
You will be asked for your password to confirm the request. You will be asked for your password to confirm the request.
If this matches your stored password, your account will immediately be blocked to all probing. If this matches your stored password, your account will immediately be marked as deleted.
Unlike some social networks we do **not** hold onto it for a grace period in case you change your mind. There is no grace period, this action cannot be reverted.
All your content and user data, etc is instantly removed. Most of your content and user data will be deleted shortly in the background.
For all intents and purposes, the account is gone in moments.
We then send out an "unfriend" signal to all of your contacts. We then send out a notification about the account removal to all of your contacts so that they can do the same with their copy of your data.
This signal deletes all content on those networks.
Unfortunately, due to limitations of the other networks, this only works well with Friendica contacts. For technical reasons some of your user data is still needed to transmit this removal message.
We allow four days for this, in case some servers were down and the unfriend signal was queued. This remaining data will be deleted after a period of around seven days.
After this, we finish off deleting the account.
To disallow impersonation we have to save your used nickname, so that it can't be used again to register on this node.

View file

@ -256,7 +256,7 @@ Eine komplette Liste aller Hook-Callbacks mit den zugehörigen Dateien (am 01-Ap
Hook::callAll("parse_link", $arr); Hook::callAll("parse_link", $arr);
### mod/manage.php ### src/Module/Delegation.php
Hook::callAll('home_init', $ret); Hook::callAll('home_init', $ret);

View file

@ -580,6 +580,9 @@ F&uuml;r Verbindungen zu Netzwerken, zu denen Friendica den HTML Code postet, wi
Bei nativen Verbindungen; das hei&szlig;t zu z.B. Friendica, Hubzilla, Diaspora oder GNU Social Kontakten; wird der ungek&uuml;rzte Beitrag &uuml;bertragen. Bei nativen Verbindungen; das hei&szlig;t zu z.B. Friendica, Hubzilla, Diaspora oder GNU Social Kontakten; wird der ungek&uuml;rzte Beitrag &uuml;bertragen.
Die Instanz des Kontakts k&uuml;mmert sich um die Darstellung. Die Instanz des Kontakts k&uuml;mmert sich um die Darstellung.
Wird ein Beitrag über das ActivityPub Protokoll &uuml;bermittelt, wird der Text des Abstracts f&uuml;r das "summary" (Zusammenfassung) Feld verwendet.
Dieses Feld wird von Mastodon f&uuml;r die Inhaltswarnung (content warning) verwendet.
## Special ## Special
<table class="bbcodes"> <table class="bbcodes">

View file

@ -38,7 +38,7 @@ Du musst das nicht machen, die Alternative ist allerdings, Dich immer wieder aus
Und das kann umständlich sein, wenn Du mehrere verschiedene Foren/Identitäten verwaltest. Und das kann umständlich sein, wenn Du mehrere verschiedene Foren/Identitäten verwaltest.
Du kannst ebenso jemanden wählen, der Dein Forum verwaltet. Du kannst ebenso jemanden wählen, der Dein Forum verwaltet.
Mach das, indem Du die [Delegations-Setup-Seite](/delegate) besuchst. Mach das, indem Du die [Delegations-Setup-Seite](/settings/delegation) besuchst.
Dort wird Dir eine Liste an "Potentiellen Bevollmächtigen" angezeigt. Dort wird Dir eine Liste an "Potentiellen Bevollmächtigen" angezeigt.
Die Auswahl einer oder mehrerer Personen gibt diesen die Möglichkeit, Dein Forum zu verwalten. Die Auswahl einer oder mehrerer Personen gibt diesen die Möglichkeit, Dein Forum zu verwalten.
Sie können Kontakte, Profile und alle Inhalte Deines Accounts/deiner Seite bearbeiten. Sie können Kontakte, Profile und alle Inhalte Deines Accounts/deiner Seite bearbeiten.

View file

@ -10,24 +10,14 @@ Wir freuen uns nicht, wenn Leute Friendica verlassen, aber wenn du deinen Accoun
in deinem Webbrowser. Du musst dabei eingeloggt sein. in deinem Webbrowser. Du musst dabei eingeloggt sein.
Du wirst nach deinem Passwort gefragt, um die Anfrage zu bestätigen. Du wirst nach deinem Passwort gefragt, um die Anfrage zu bestätigen.
Wenn dieses mit deinem gespeichertem Passwort übereinstimmt, dann wird dein Account sofort gelöscht. Wenn dieses mit deinem gespeichertem Passwort übereinstimmt, dann wird dein Account als "gelöscht" markiert.
Anders als andere Netzwerke, behalten wir die Daten **nicht** für eine gewisse Zeit, falls du deine Meinung noch änderst. Dies passiert sofort und kann nicht rückgängig gemacht werden.
Deine Nutzerdetails, deine Unterhaltungen, deine Photos, deine Freunde - alles; wird sofort gelöscht und du wirst ausgeloggt. Die meisten Deiner Inhalte und Benutzerdaten werden kurzfristig danach durch Hintergrundprozesse gelöscht.
Wenn Beiträge ablaufen, schicken wir Mitteilungen an Friendica, um diese zu löschen. Parallel dazu senden wir eine Mitteilung an die Server deiner Kontakte, damit sie deine dort vorliegenden Daten ebenfalls löschen.
Diaspora hat keine automatische Löschfunktion, so dass diese Funktion in dem Netzwerk deaktiviert ist. Wir haben keinen Einfluss darauf, wie sorgfältig und ob überhaupt diese Systeme der Löschaufforderung nachgehen.
Und hoffentlich ist klar, dass das Löschen auch in anderen Netzwerken nicht funktioniert.
Wenn du manuell einen Beitrag bzw. eine Reihe von Beiträgen löschst, dann senden wir individuelle Mitteilungen zu Friendica und Diaspora für jeden gelöschten Post.
Diaspora versäumt dieses oft. Aus technischen Gründen benötigen wir für die Übetragung dieser Mitteilung ein paar Benutzerdaten.
Diese Daten werden dann nach einer Frist von etwa sieben Tagen ebenfalls gelöscht.
Wenn du einen Beitrag löscht, aber jemand diesem Beitrag folgt, wird es trotzdem gelöscht. Wir speichern deinen Benutzernamen dauerhaft, damit sich niemand einen Account unter deinem Spitznamen anlegen kann.
Dein Wunsch hat Priorität.
Wenn du deinen Account löscht, dann löschen wir alle Beiträge, dein Profil, die Nutzerdaten etc. sofort.
Um einen Gesamtlöschauftrag zu versenden, bräuchten wir zunächst noch deinen Account; auch, um deinen Freunden zu zeigen, wer diese Anfrage stellt.
Das können wir nicht tun, wenn du keinen Account mehr hast.
Deine Freunde können möglicherweise noch deine Beiträge sehen, wenn dein Account gelöscht wurde, aber es gibt keinen öffentlichen Ort in Friendica mehr, wo diese angeschaut werden können.
Wenn du Freunde bei Diaspora hast, kann es sein, dass deine Beiträge weiterhin vorhanden und für andere aus diesem Netzwerk sichtbar sind.

View file

@ -177,6 +177,7 @@ Field parameter:
1. Label for the input box, 1. Label for the input box,
2. Current text for the box, 2. Current text for the box,
3. Help text for the input box. 3. Help text for the input box.
4. if set to "required" modern browser will check that this input box is filled when submitting the form,
### field_yesno.tpl ### field_yesno.tpl

View file

@ -48,9 +48,9 @@ use Friendica\Util\Proxy as ProxyUtils;
use Friendica\Util\Strings; use Friendica\Util\Strings;
use Friendica\Util\XML; use Friendica\Util\XML;
require_once 'mod/share.php'; require_once __DIR__ . '/../mod/share.php';
require_once 'mod/item.php'; require_once __DIR__ . '/../mod/item.php';
require_once 'mod/wall_upload.php'; require_once __DIR__ . '/../mod/wall_upload.php';
define('API_METHOD_ANY', '*'); define('API_METHOD_ANY', '*');
define('API_METHOD_GET', 'GET'); define('API_METHOD_GET', 'GET');
@ -162,6 +162,7 @@ function api_register_func($path, $func, $auth = false, $method = API_METHOD_ANY
* @brief Login API user * @brief Login API user
* *
* @param App $a App * @param App $a App
* @throws ForbiddenException
* @throws InternalServerErrorException * @throws InternalServerErrorException
* @throws UnauthorizedException * @throws UnauthorizedException
* @hook 'authenticate' * @hook 'authenticate'
@ -170,8 +171,6 @@ function api_register_func($path, $func, $auth = false, $method = API_METHOD_ANY
* 'password' => password from login form * 'password' => password from login form
* 'authenticated' => return status, * 'authenticated' => return status,
* 'user_record' => return authenticated user record * 'user_record' => return authenticated user record
* @hook 'logged_in'
* array $user logged user record
*/ */
function api_login(App $a) function api_login(App $a)
{ {
@ -182,7 +181,7 @@ function api_login(App $a)
list($consumer, $token) = $oauth1->verify_request($request); list($consumer, $token) = $oauth1->verify_request($request);
if (!is_null($token)) { if (!is_null($token)) {
$oauth1->loginUser($token->uid); $oauth1->loginUser($token->uid);
Hook::callAll('logged_in', $a->user); Session::set('allow_api', true);
return; return;
} }
echo __FILE__.__LINE__.__FUNCTION__ . "<pre>"; echo __FILE__.__LINE__.__FUNCTION__ . "<pre>";
@ -208,8 +207,8 @@ function api_login(App $a)
throw new UnauthorizedException("This API requires login"); throw new UnauthorizedException("This API requires login");
} }
$user = defaults($_SERVER, 'PHP_AUTH_USER', ''); $user = $_SERVER['PHP_AUTH_USER'] ?? '';
$password = defaults($_SERVER, 'PHP_AUTH_PW', ''); $password = $_SERVER['PHP_AUTH_PW'] ?? '';
// allow "user@server" login (but ignore 'server' part) // allow "user@server" login (but ignore 'server' part)
$at = strstr($user, "@", true); $at = strstr($user, "@", true);
@ -273,7 +272,7 @@ function api_check_method($method)
if ($method == "*") { if ($method == "*") {
return true; return true;
} }
return (stripos($method, defaults($_SERVER, 'REQUEST_METHOD', 'GET')) !== false); return (stripos($method, $_SERVER['REQUEST_METHOD'] ?? 'GET') !== false);
} }
/** /**
@ -323,7 +322,7 @@ function api_call(App $a)
$stamp = microtime(true); $stamp = microtime(true);
$return = call_user_func($info['func'], $type); $return = call_user_func($info['func'], $type);
$duration = (float) (microtime(true) - $stamp); $duration = floatval(microtime(true) - $stamp);
Logger::info(API_LOG_PREFIX . 'username {username}', ['module' => 'api', 'action' => 'call', 'username' => $a->user['username'], 'duration' => round($duration, 2)]); Logger::info(API_LOG_PREFIX . 'username {username}', ['module' => 'api', 'action' => 'call', 'username' => $a->user['username'], 'duration' => round($duration, 2)]);
@ -776,14 +775,14 @@ function api_get_user(App $a, $contact_id = null)
*/ */
function api_item_get_user(App $a, $item) function api_item_get_user(App $a, $item)
{ {
$status_user = api_get_user($a, defaults($item, 'author-id', null)); $status_user = api_get_user($a, $item['author-id'] ?? null);
$author_user = $status_user; $author_user = $status_user;
$status_user["protected"] = defaults($item, 'private', 0); $status_user["protected"] = $item['private'] ?? 0;
if (defaults($item, 'thr-parent', '') == defaults($item, 'uri', '')) { if (($item['thr-parent'] ?? '') == ($item['uri'] ?? '')) {
$owner_user = api_get_user($a, defaults($item, 'owner-id', null)); $owner_user = api_get_user($a, $item['owner-id'] ?? null);
} else { } else {
$owner_user = $author_user; $owner_user = $author_user;
} }
@ -947,7 +946,7 @@ function api_account_verify_credentials($type)
unset($_REQUEST["screen_name"]); unset($_REQUEST["screen_name"]);
unset($_GET["screen_name"]); unset($_GET["screen_name"]);
$skip_status = defaults($_REQUEST, 'skip_status', false); $skip_status = $_REQUEST['skip_status'] ?? false;
$user_info = api_get_user($a); $user_info = api_get_user($a);
@ -1518,10 +1517,12 @@ function api_search($type)
$count = $_REQUEST['count']; $count = $_REQUEST['count'];
} }
$since_id = defaults($_REQUEST, 'since_id', 0); $since_id = $_REQUEST['since_id'] ?? 0;
$max_id = defaults($_REQUEST, 'max_id', 0); $max_id = $_REQUEST['max_id'] ?? 0;
$page = (!empty($_REQUEST['page']) ? $_REQUEST['page'] - 1 : 0); $page = $_REQUEST['page'] ?? 1;
$start = $page * $count;
$start = max(0, ($page - 1) * $count);
$params = ['order' => ['id' => true], 'limit' => [$start, $count]]; $params = ['order' => ['id' => true], 'limit' => [$start, $count]];
if (preg_match('/^#(\w+)$/', $searchTerm, $matches) === 1 && isset($matches[1])) { if (preg_match('/^#(\w+)$/', $searchTerm, $matches) === 1 && isset($matches[1])) {
$searchTerm = $matches[1]; $searchTerm = $matches[1];
@ -1609,17 +1610,14 @@ function api_statuses_home_timeline($type)
// get last network messages // get last network messages
// params // params
$count = defaults($_REQUEST, 'count', 20); $count = $_REQUEST['count'] ?? 20;
$page = (!empty($_REQUEST['page']) ? $_REQUEST['page'] - 1 : 0); $page = $_REQUEST['page']?? 0;
if ($page < 0) { $since_id = $_REQUEST['since_id'] ?? 0;
$page = 0; $max_id = $_REQUEST['max_id'] ?? 0;
}
$since_id = defaults($_REQUEST, 'since_id', 0);
$max_id = defaults($_REQUEST, 'max_id', 0);
$exclude_replies = !empty($_REQUEST['exclude_replies']); $exclude_replies = !empty($_REQUEST['exclude_replies']);
$conversation_id = defaults($_REQUEST, 'conversation_id', 0); $conversation_id = $_REQUEST['conversation_id'] ?? 0;
$start = $page * $count; $start = max(0, ($page - 1) * $count);
$condition = ["`uid` = ? AND `gravity` IN (?, ?) AND `item`.`id` > ?", $condition = ["`uid` = ? AND `gravity` IN (?, ?) AND `item`.`id` > ?",
api_user(), GRAVITY_PARENT, GRAVITY_COMMENT, $since_id]; api_user(), GRAVITY_PARENT, GRAVITY_COMMENT, $since_id];
@ -1699,17 +1697,14 @@ function api_statuses_public_timeline($type)
// get last network messages // get last network messages
// params // params
$count = defaults($_REQUEST, 'count', 20); $count = $_REQUEST['count'] ?? 20;
$page = (!empty($_REQUEST['page']) ? $_REQUEST['page'] -1 : 0); $page = $_REQUEST['page'] ?? 1;
if ($page < 0) { $since_id = $_REQUEST['since_id'] ?? 0;
$page = 0; $max_id = $_REQUEST['max_id'] ?? 0;
}
$since_id = defaults($_REQUEST, 'since_id', 0);
$max_id = defaults($_REQUEST, 'max_id', 0);
$exclude_replies = (!empty($_REQUEST['exclude_replies']) ? 1 : 0); $exclude_replies = (!empty($_REQUEST['exclude_replies']) ? 1 : 0);
$conversation_id = defaults($_REQUEST, 'conversation_id', 0); $conversation_id = $_REQUEST['conversation_id'] ?? 0;
$start = $page * $count; $start = max(0, ($page - 1) * $count);
if ($exclude_replies && !$conversation_id) { if ($exclude_replies && !$conversation_id) {
$condition = ["`gravity` IN (?, ?) AND `iid` > ? AND NOT `private` AND `wall` AND NOT `user`.`hidewall` AND NOT `author`.`hidden`", $condition = ["`gravity` IN (?, ?) AND `iid` > ? AND NOT `private` AND `wall` AND NOT `user`.`hidewall` AND NOT `author`.`hidden`",
@ -1784,16 +1779,14 @@ function api_statuses_networkpublic_timeline($type)
throw new ForbiddenException(); throw new ForbiddenException();
} }
$since_id = defaults($_REQUEST, 'since_id', 0); $since_id = $_REQUEST['since_id'] ?? 0;
$max_id = defaults($_REQUEST, 'max_id', 0); $max_id = $_REQUEST['max_id'] ?? 0;
// pagination // pagination
$count = defaults($_REQUEST, 'count', 20); $count = $_REQUEST['count'] ?? 20;
$page = defaults($_REQUEST, 'page', 1); $page = $_REQUEST['page'] ?? 1;
if ($page < 1) {
$page = 1; $start = max(0, ($page - 1) * $count);
}
$start = ($page - 1) * $count;
$condition = ["`uid` = 0 AND `gravity` IN (?, ?) AND `thread`.`iid` > ? AND NOT `private`", $condition = ["`uid` = 0 AND `gravity` IN (?, ?) AND `thread`.`iid` > ? AND NOT `private`",
GRAVITY_PARENT, GRAVITY_COMMENT, $since_id]; GRAVITY_PARENT, GRAVITY_COMMENT, $since_id];
@ -1848,15 +1841,15 @@ function api_statuses_show($type)
} }
// params // params
$id = intval(defaults($a->argv, 3, 0)); $id = intval($a->argv[3] ?? 0);
if ($id == 0) { if ($id == 0) {
$id = intval(defaults($_REQUEST, 'id', 0)); $id = intval($_REQUEST['id'] ?? 0);
} }
// Hotot workaround // Hotot workaround
if ($id == 0) { if ($id == 0) {
$id = intval(defaults($a->argv, 4, 0)); $id = intval($a->argv[4] ?? 0);
} }
Logger::log('API: api_statuses_show: ' . $id); Logger::log('API: api_statuses_show: ' . $id);
@ -1927,24 +1920,21 @@ function api_conversation_show($type)
} }
// params // params
$id = intval(defaults($a->argv , 3 , 0)); $id = intval($a->argv[3] ?? 0);
$since_id = intval(defaults($_REQUEST, 'since_id', 0)); $since_id = intval($_REQUEST['since_id'] ?? 0);
$max_id = intval(defaults($_REQUEST, 'max_id' , 0)); $max_id = intval($_REQUEST['max_id'] ?? 0);
$count = intval(defaults($_REQUEST, 'count' , 20)); $count = intval($_REQUEST['count'] ?? 20);
$page = intval(defaults($_REQUEST, 'page' , 1)) - 1; $page = intval($_REQUEST['page'] ?? 1);
if ($page < 0) {
$page = 0;
}
$start = $page * $count; $start = max(0, ($page - 1) * $count);
if ($id == 0) { if ($id == 0) {
$id = intval(defaults($_REQUEST, 'id', 0)); $id = intval($_REQUEST['id'] ?? 0);
} }
// Hotot workaround // Hotot workaround
if ($id == 0) { if ($id == 0) {
$id = intval(defaults($a->argv, 4, 0)); $id = intval($a->argv[4] ?? 0);
} }
Logger::info(API_LOG_PREFIX . '{subaction}', ['module' => 'api', 'action' => 'conversation', 'subaction' => 'show', 'id' => $id]); Logger::info(API_LOG_PREFIX . '{subaction}', ['module' => 'api', 'action' => 'conversation', 'subaction' => 'show', 'id' => $id]);
@ -2013,15 +2003,15 @@ function api_statuses_repeat($type)
api_get_user($a); api_get_user($a);
// params // params
$id = intval(defaults($a->argv, 3, 0)); $id = intval($a->argv[3] ?? 0);
if ($id == 0) { if ($id == 0) {
$id = intval(defaults($_REQUEST, 'id', 0)); $id = intval($_REQUEST['id'] ?? 0);
} }
// Hotot workaround // Hotot workaround
if ($id == 0) { if ($id == 0) {
$id = intval(defaults($a->argv, 4, 0)); $id = intval($a->argv[4] ?? 0);
} }
Logger::log('API: api_statuses_repeat: '.$id); Logger::log('API: api_statuses_repeat: '.$id);
@ -2084,15 +2074,15 @@ function api_statuses_destroy($type)
api_get_user($a); api_get_user($a);
// params // params
$id = intval(defaults($a->argv, 3, 0)); $id = intval($a->argv[3] ?? 0);
if ($id == 0) { if ($id == 0) {
$id = intval(defaults($_REQUEST, 'id', 0)); $id = intval($_REQUEST['id'] ?? 0);
} }
// Hotot workaround // Hotot workaround
if ($id == 0) { if ($id == 0) {
$id = intval(defaults($a->argv, 4, 0)); $id = intval($a->argv[4] ?? 0);
} }
Logger::log('API: api_statuses_destroy: '.$id); Logger::log('API: api_statuses_destroy: '.$id);
@ -2138,15 +2128,12 @@ function api_statuses_mentions($type)
// get last network messages // get last network messages
// params // params
$since_id = defaults($_REQUEST, 'since_id', 0); $since_id = $_REQUEST['since_id'] ?? 0;
$max_id = defaults($_REQUEST, 'max_id' , 0); $max_id = $_REQUEST['max_id'] ?? 0;
$count = defaults($_REQUEST, 'count' , 20); $count = $_REQUEST['count'] ?? 20;
$page = defaults($_REQUEST, 'page' , 1); $page = $_REQUEST['page'] ?? 1;
if ($page < 1) {
$page = 1;
}
$start = ($page - 1) * $count; $start = max(0, ($page - 1) * $count);
$condition = ["`uid` = ? AND `gravity` IN (?, ?) AND `item`.`id` > ? AND `author-id` != ? $condition = ["`uid` = ? AND `gravity` IN (?, ?) AND `item`.`id` > ? AND `author-id` != ?
AND `item`.`parent` IN (SELECT `iid` FROM `thread` WHERE `thread`.`uid` = ? AND `thread`.`mention` AND NOT `thread`.`ignored`)", AND `item`.`parent` IN (SELECT `iid` FROM `thread` WHERE `thread`.`uid` = ? AND `thread`.`mention` AND NOT `thread`.`ignored`)",
@ -2208,18 +2195,16 @@ function api_statuses_user_timeline($type)
Logger::DEBUG Logger::DEBUG
); );
$since_id = defaults($_REQUEST, 'since_id', 0); $since_id = $_REQUEST['since_id'] ?? 0;
$max_id = defaults($_REQUEST, 'max_id', 0); $max_id = $_REQUEST['max_id'] ?? 0;
$exclude_replies = !empty($_REQUEST['exclude_replies']); $exclude_replies = !empty($_REQUEST['exclude_replies']);
$conversation_id = defaults($_REQUEST, 'conversation_id', 0); $conversation_id = $_REQUEST['conversation_id'] ?? 0;
// pagination // pagination
$count = defaults($_REQUEST, 'count', 20); $count = $_REQUEST['count'] ?? 20;
$page = defaults($_REQUEST, 'page', 1); $page = $_REQUEST['page'] ?? 1;
if ($page < 1) {
$page = 1; $start = max(0, ($page - 1) * $count);
}
$start = ($page - 1) * $count;
$condition = ["`uid` = ? AND `gravity` IN (?, ?) AND `item`.`id` > ? AND `item`.`contact-id` = ?", $condition = ["`uid` = ? AND `gravity` IN (?, ?) AND `item`.`id` > ? AND `item`.`contact-id` = ?",
api_user(), GRAVITY_PARENT, GRAVITY_COMMENT, $since_id, $user_info['cid']]; api_user(), GRAVITY_PARENT, GRAVITY_COMMENT, $since_id, $user_info['cid']];
@ -2298,9 +2283,9 @@ function api_favorites_create_destroy($type)
} }
$action = str_replace("." . $type, "", $a->argv[$action_argv_id]); $action = str_replace("." . $type, "", $a->argv[$action_argv_id]);
if ($a->argc == $action_argv_id + 2) { if ($a->argc == $action_argv_id + 2) {
$itemid = intval(defaults($a->argv, $action_argv_id + 1, 0)); $itemid = intval($a->argv[$action_argv_id + 1] ?? 0);
} else { } else {
$itemid = intval(defaults($_REQUEST, 'id', 0)); $itemid = intval($_REQUEST['id'] ?? 0);
} }
$item = Item::selectFirstForUser(api_user(), [], ['id' => $itemid, 'uid' => api_user()]); $item = Item::selectFirstForUser(api_user(), [], ['id' => $itemid, 'uid' => api_user()]);
@ -2380,15 +2365,12 @@ function api_favorites($type)
$ret = []; $ret = [];
} else { } else {
// params // params
$since_id = defaults($_REQUEST, 'since_id', 0); $since_id = $_REQUEST['since_id'] ?? 0;
$max_id = defaults($_REQUEST, 'max_id', 0); $max_id = $_REQUEST['max_id'] ?? 0;
$count = defaults($_GET, 'count', 20); $count = $_GET['count'] ?? 20;
$page = (!empty($_REQUEST['page']) ? $_REQUEST['page'] -1 : 0); $page = $_REQUEST['page'] ?? 1;
if ($page < 0) {
$page = 0;
}
$start = $page*$count; $start = max(0, ($page - 1) * $count);
$condition = ["`uid` = ? AND `gravity` IN (?, ?) AND `id` > ? AND `starred`", $condition = ["`uid` = ? AND `gravity` IN (?, ?) AND `id` > ? AND `starred`",
api_user(), GRAVITY_PARENT, GRAVITY_COMMENT, $since_id]; api_user(), GRAVITY_PARENT, GRAVITY_COMMENT, $since_id];
@ -2439,14 +2421,14 @@ function api_format_messages($item, $recipient, $sender)
'sender_id' => $sender['id'], 'sender_id' => $sender['id'],
'text' => "", 'text' => "",
'recipient_id' => $recipient['id'], 'recipient_id' => $recipient['id'],
'created_at' => api_date(defaults($item, 'created', DateTimeFormat::utcNow())), 'created_at' => api_date($item['created'] ?? DateTimeFormat::utcNow()),
'sender_screen_name' => $sender['screen_name'], 'sender_screen_name' => $sender['screen_name'],
'recipient_screen_name' => $recipient['screen_name'], 'recipient_screen_name' => $recipient['screen_name'],
'sender' => $sender, 'sender' => $sender,
'recipient' => $recipient, 'recipient' => $recipient,
'title' => "", 'title' => "",
'friendica_seen' => defaults($item, 'seen', 0), 'friendica_seen' => $item['seen'] ?? 0,
'friendica_parent_uri' => defaults($item, 'parent-uri', ''), 'friendica_parent_uri' => $item['parent-uri'] ?? '',
]; ];
// "uid" and "self" are only needed for some internal stuff, so remove it from here // "uid" and "self" are only needed for some internal stuff, so remove it from here
@ -2509,8 +2491,8 @@ function api_convert_item($item)
$statustext = trim($statustitle."\n\n".$statusbody); $statustext = trim($statustitle."\n\n".$statusbody);
} }
if ((defaults($item, 'network', Protocol::PHANTOM) == Protocol::FEED) && (mb_strlen($statustext)> 1000)) { if ((($item['network'] ?? Protocol::PHANTOM) == Protocol::FEED) && (mb_strlen($statustext)> 1000)) {
$statustext = mb_substr($statustext, 0, 1000) . "... \n" . defaults($item, 'plink', ''); $statustext = mb_substr($statustext, 0, 1000) . "... \n" . ($item['plink'] ?? '');
} }
$statushtml = BBCode::convert(api_clean_attachments($body), false); $statushtml = BBCode::convert(api_clean_attachments($body), false);
@ -2544,7 +2526,7 @@ function api_convert_item($item)
} }
// feeds without body should contain the link // feeds without body should contain the link
if ((defaults($item, 'network', Protocol::PHANTOM) == Protocol::FEED) && (strlen($item['body']) == 0)) { if ((($item['network'] ?? Protocol::PHANTOM) == Protocol::FEED) && (strlen($item['body']) == 0)) {
$statushtml .= BBCode::convert($item['plink']); $statushtml .= BBCode::convert($item['plink']);
} }
@ -2587,7 +2569,7 @@ function api_get_attachments(&$body)
} }
} }
if (strstr(defaults($_SERVER, 'HTTP_USER_AGENT', ''), "AndStatus")) { if (strstr($_SERVER['HTTP_USER_AGENT'] ?? '', 'AndStatus')) {
foreach ($images[0] as $orig) { foreach ($images[0] as $orig) {
$body = str_replace($orig, "", $body); $body = str_replace($orig, "", $body);
} }
@ -2607,7 +2589,7 @@ function api_get_attachments(&$body)
*/ */
function api_get_entitities(&$text, $bbcode) function api_get_entitities(&$text, $bbcode)
{ {
$include_entities = strtolower(defaults($_REQUEST, 'include_entities', "false")); $include_entities = strtolower($_REQUEST['include_entities'] ?? 'false');
if ($include_entities != "true") { if ($include_entities != "true") {
preg_match_all("/\[img](.*?)\[\/img\]/ism", $bbcode, $images); preg_match_all("/\[img](.*?)\[\/img\]/ism", $bbcode, $images);
@ -3040,6 +3022,8 @@ function api_format_item($item, $type = "json", $status_user = null, $author_use
'statusnet_conversation_id' => $item['parent'], 'statusnet_conversation_id' => $item['parent'],
'external_url' => System::baseUrl() . "/display/" . $item['guid'], 'external_url' => System::baseUrl() . "/display/" . $item['guid'],
'friendica_activities' => api_format_items_activities($item, $type), 'friendica_activities' => api_format_items_activities($item, $type),
'friendica_title' => $item['title'],
'friendica_html' => BBCode::convert($item['body'], false)
]; ];
if (count($converted["attachments"]) > 0) { if (count($converted["attachments"]) > 0) {
@ -3310,17 +3294,14 @@ function api_lists_statuses($type)
} }
// params // params
$count = defaults($_REQUEST, 'count', 20); $count = $_REQUEST['count'] ?? 20;
$page = (!empty($_REQUEST['page']) ? $_REQUEST['page'] - 1 : 0); $page = $_REQUEST['page'] ?? 1;
if ($page < 0) { $since_id = $_REQUEST['since_id'] ?? 0;
$page = 0; $max_id = $_REQUEST['max_id'] ?? 0;
}
$since_id = defaults($_REQUEST, 'since_id', 0);
$max_id = defaults($_REQUEST, 'max_id', 0);
$exclude_replies = (!empty($_REQUEST['exclude_replies']) ? 1 : 0); $exclude_replies = (!empty($_REQUEST['exclude_replies']) ? 1 : 0);
$conversation_id = defaults($_REQUEST, 'conversation_id', 0); $conversation_id = $_REQUEST['conversation_id'] ?? 0;
$start = $page * $count; $start = max(0, ($page - 1) * $count);
$condition = ["`uid` = ? AND `gravity` IN (?, ?) AND `id` > ? AND `group_member`.`gid` = ?", $condition = ["`uid` = ? AND `gravity` IN (?, ?) AND `id` > ? AND `group_member`.`gid` = ?",
api_user(), GRAVITY_PARENT, GRAVITY_COMMENT, $since_id, $_REQUEST['list_id']]; api_user(), GRAVITY_PARENT, GRAVITY_COMMENT, $since_id, $_REQUEST['list_id']];
@ -3380,12 +3361,10 @@ function api_statuses_f($qtype)
} }
// pagination // pagination
$count = defaults($_GET, 'count', 20); $count = $_GET['count'] ?? 20;
$page = defaults($_GET, 'page', 1); $page = $_GET['page'] ?? 1;
if ($page < 1) {
$page = 1; $start = max(0, ($page - 1) * $count);
}
$start = ($page - 1) * $count;
$user_info = api_get_user($a); $user_info = api_get_user($a);
@ -3632,7 +3611,7 @@ function api_ff_ids($type)
api_get_user($a); api_get_user($a);
$stringify_ids = defaults($_REQUEST, 'stringify_ids', false); $stringify_ids = $_REQUEST['stringify_ids'] ?? false;
$r = q( $r = q(
"SELECT `pcontact`.`id` FROM `contact` "SELECT `pcontact`.`id` FROM `contact`
@ -3807,9 +3786,9 @@ function api_direct_messages_destroy($type)
// params // params
$user_info = api_get_user($a); $user_info = api_get_user($a);
//required //required
$id = defaults($_REQUEST, 'id', 0); $id = $_REQUEST['id'] ?? 0;
// optional // optional
$parenturi = defaults($_REQUEST, 'friendica_parenturi', ""); $parenturi = $_REQUEST['friendica_parenturi'] ?? '';
$verbose = (!empty($_GET['friendica_verbose']) ? strtolower($_GET['friendica_verbose']) : "false"); $verbose = (!empty($_GET['friendica_verbose']) ? strtolower($_GET['friendica_verbose']) : "false");
/// @todo optional parameter 'include_entities' from Twitter API not yet implemented /// @todo optional parameter 'include_entities' from Twitter API not yet implemented
@ -3890,7 +3869,7 @@ function api_friendships_destroy($type)
throw new ForbiddenException(); throw new ForbiddenException();
} }
$contact_id = defaults($_REQUEST, 'user_id'); $contact_id = $_REQUEST['user_id'] ?? 0;
if (empty($contact_id)) { if (empty($contact_id)) {
Logger::notice(API_LOG_PREFIX . 'No user_id specified', ['module' => 'api', 'action' => 'friendships_destroy']); Logger::notice(API_LOG_PREFIX . 'No user_id specified', ['module' => 'api', 'action' => 'friendships_destroy']);
@ -3971,17 +3950,14 @@ function api_direct_messages_box($type, $box, $verbose)
throw new ForbiddenException(); throw new ForbiddenException();
} }
// params // params
$count = defaults($_GET, 'count', 20); $count = $_GET['count'] ?? 20;
$page = defaults($_REQUEST, 'page', 1) - 1; $page = $_REQUEST['page'] ?? 1;
if ($page < 0) {
$page = 0;
}
$since_id = defaults($_REQUEST, 'since_id', 0); $since_id = $_REQUEST['since_id'] ?? 0;
$max_id = defaults($_REQUEST, 'max_id', 0); $max_id = $_REQUEST['max_id'] ?? 0;
$user_id = defaults($_REQUEST, 'user_id', ''); $user_id = $_REQUEST['user_id'] ?? '';
$screen_name = defaults($_REQUEST, 'screen_name', ''); $screen_name = $_REQUEST['screen_name'] ?? '';
// caller user info // caller user info
unset($_REQUEST["user_id"]); unset($_REQUEST["user_id"]);
@ -3997,7 +3973,7 @@ function api_direct_messages_box($type, $box, $verbose)
$profile_url = $user_info["url"]; $profile_url = $user_info["url"];
// pagination // pagination
$start = $page * $count; $start = max(0, ($page - 1) * $count);
$sql_extra = ""; $sql_extra = "";
@ -4005,7 +3981,7 @@ function api_direct_messages_box($type, $box, $verbose)
if ($box=="sentbox") { if ($box=="sentbox") {
$sql_extra = "`mail`.`from-url`='" . DBA::escape($profile_url) . "'"; $sql_extra = "`mail`.`from-url`='" . DBA::escape($profile_url) . "'";
} elseif ($box == "conversation") { } elseif ($box == "conversation") {
$sql_extra = "`mail`.`parent-uri`='" . DBA::escape(defaults($_GET, 'uri', '')) . "'"; $sql_extra = "`mail`.`parent-uri`='" . DBA::escape($_GET['uri'] ?? '') . "'";
} elseif ($box == "all") { } elseif ($box == "all") {
$sql_extra = "true"; $sql_extra = "true";
} elseif ($box == "inbox") { } elseif ($box == "inbox") {
@ -4185,7 +4161,7 @@ function api_fr_photoalbum_delete($type)
throw new ForbiddenException(); throw new ForbiddenException();
} }
// input params // input params
$album = defaults($_REQUEST, 'album', ""); $album = $_REQUEST['album'] ?? '';
// we do not allow calls without album string // we do not allow calls without album string
if ($album == "") { if ($album == "") {
@ -4240,8 +4216,8 @@ function api_fr_photoalbum_update($type)
throw new ForbiddenException(); throw new ForbiddenException();
} }
// input params // input params
$album = defaults($_REQUEST, 'album', ""); $album = $_REQUEST['album'] ?? '';
$album_new = defaults($_REQUEST, 'album_new', ""); $album_new = $_REQUEST['album_new'] ?? '';
// we do not allow calls without album string // we do not allow calls without album string
if ($album == "") { if ($album == "") {
@ -4332,14 +4308,14 @@ function api_fr_photo_create_update($type)
throw new ForbiddenException(); throw new ForbiddenException();
} }
// input params // input params
$photo_id = defaults($_REQUEST, 'photo_id', null); $photo_id = $_REQUEST['photo_id'] ?? null;
$desc = defaults($_REQUEST, 'desc', (array_key_exists('desc', $_REQUEST) ? "" : null)) ; // extra check necessary to distinguish between 'not provided' and 'empty string' $desc = $_REQUEST['desc'] ?? null;
$album = defaults($_REQUEST, 'album', null); $album = $_REQUEST['album'] ?? null;
$album_new = defaults($_REQUEST, 'album_new', null); $album_new = $_REQUEST['album_new'] ?? null;
$allow_cid = defaults($_REQUEST, 'allow_cid', (array_key_exists('allow_cid', $_REQUEST) ? " " : null)); $allow_cid = $_REQUEST['allow_cid'] ?? null;
$deny_cid = defaults($_REQUEST, 'deny_cid' , (array_key_exists('deny_cid' , $_REQUEST) ? " " : null)); $deny_cid = $_REQUEST['deny_cid' ] ?? null;
$allow_gid = defaults($_REQUEST, 'allow_gid', (array_key_exists('allow_gid', $_REQUEST) ? " " : null)); $allow_gid = $_REQUEST['allow_gid'] ?? null;
$deny_gid = defaults($_REQUEST, 'deny_gid' , (array_key_exists('deny_gid' , $_REQUEST) ? " " : null)); $deny_gid = $_REQUEST['deny_gid' ] ?? null;
$visibility = !empty($_REQUEST['visibility']) && $_REQUEST['visibility'] !== "false"; $visibility = !empty($_REQUEST['visibility']) && $_REQUEST['visibility'] !== "false";
// do several checks on input parameters // do several checks on input parameters
@ -4470,7 +4446,7 @@ function api_fr_photo_delete($type)
} }
// input params // input params
$photo_id = defaults($_REQUEST, 'photo_id', null); $photo_id = $_REQUEST['photo_id'] ?? null;
// do several checks on input parameters // do several checks on input parameters
// we do not allow calls without photo id // we do not allow calls without photo id
@ -4557,7 +4533,7 @@ function api_account_update_profile_image($type)
throw new ForbiddenException(); throw new ForbiddenException();
} }
// input params // input params
$profile_id = defaults($_REQUEST, 'profile_id', 0); $profile_id = $_REQUEST['profile_id'] ?? 0;
// error if image data is missing // error if image data is missing
if (empty($_FILES['image'])) { if (empty($_FILES['image'])) {
@ -4689,9 +4665,10 @@ api_register_func('api/account/update_profile', 'api_account_update_profile', tr
*/ */
function check_acl_input($acl_string) function check_acl_input($acl_string)
{ {
if ($acl_string == null || $acl_string == " ") { if (empty($acl_string)) {
return false; return false;
} }
$contact_not_found = false; $contact_not_found = false;
// split <x><y><z> into array of cid's // split <x><y><z> into array of cid's
@ -4709,7 +4686,6 @@ function check_acl_input($acl_string)
} }
/** /**
*
* @param string $mediatype * @param string $mediatype
* @param array $media * @param array $media
* @param string $type * @param string $type
@ -4728,6 +4704,7 @@ function check_acl_input($acl_string)
* @throws ImagickException * @throws ImagickException
* @throws InternalServerErrorException * @throws InternalServerErrorException
* @throws NotFoundException * @throws NotFoundException
* @throws UnauthorizedException
*/ */
function save_media_to_database($mediatype, $media, $type, $album, $allow_cid, $deny_cid, $allow_gid, $deny_gid, $desc, $profile = 0, $visibility = false, $photo_id = null) function save_media_to_database($mediatype, $media, $type, $album, $allow_cid, $deny_cid, $allow_gid, $deny_gid, $desc, $profile = 0, $visibility = false, $photo_id = null)
{ {
@ -5062,8 +5039,8 @@ function prepare_photo_data($type, $scale, $photo_id)
*/ */
function api_friendica_remoteauth() function api_friendica_remoteauth()
{ {
$url = defaults($_GET, 'url', ''); $url = $_GET['url'] ?? '';
$c_url = defaults($_GET, 'c_url', ''); $c_url = $_GET['c_url'] ?? '';
if ($url === '' || $c_url === '') { if ($url === '' || $c_url === '') {
throw new BadRequestException("Wrong parameters."); throw new BadRequestException("Wrong parameters.");
@ -5081,7 +5058,7 @@ function api_friendica_remoteauth()
$cid = $contact['id']; $cid = $contact['id'];
$dfrn_id = defaults($contact, 'issued-id', $contact['dfrn-id']); $dfrn_id = $contact['issued-id'] ?? $contact['dfrn-id'];
if ($contact['duplex'] && $contact['issued-id']) { if ($contact['duplex'] && $contact['issued-id']) {
$orig_id = $contact['issued-id']; $orig_id = $contact['issued-id'];
@ -5416,7 +5393,7 @@ function api_in_reply_to($item)
*/ */
function api_clean_plain_items($text) function api_clean_plain_items($text)
{ {
$include_entities = strtolower(defaults($_REQUEST, 'include_entities', "false")); $include_entities = strtolower($_REQUEST['include_entities'] ?? 'false');
$text = BBCode::cleanPictureLinks($text); $text = BBCode::cleanPictureLinks($text);
$URLSearchString = "^\[\]"; $URLSearchString = "^\[\]";
@ -5554,7 +5531,7 @@ function api_friendica_group_show($type)
// params // params
$user_info = api_get_user($a); $user_info = api_get_user($a);
$gid = defaults($_REQUEST, 'gid', 0); $gid = $_REQUEST['gid'] ?? 0;
$uid = $user_info['uid']; $uid = $user_info['uid'];
// get data of the specified group id or all groups if not specified // get data of the specified group id or all groups if not specified
@ -5624,8 +5601,8 @@ function api_friendica_group_delete($type)
// params // params
$user_info = api_get_user($a); $user_info = api_get_user($a);
$gid = defaults($_REQUEST, 'gid', 0); $gid = $_REQUEST['gid'] ?? 0;
$name = defaults($_REQUEST, 'name', ""); $name = $_REQUEST['name'] ?? '';
$uid = $user_info['uid']; $uid = $user_info['uid'];
// error if no gid specified // error if no gid specified
@ -5691,7 +5668,7 @@ function api_lists_destroy($type)
// params // params
$user_info = api_get_user($a); $user_info = api_get_user($a);
$gid = defaults($_REQUEST, 'list_id', 0); $gid = $_REQUEST['list_id'] ?? 0;
$uid = $user_info['uid']; $uid = $user_info['uid'];
// error if no gid specified // error if no gid specified
@ -5813,7 +5790,7 @@ function api_friendica_group_create($type)
// params // params
$user_info = api_get_user($a); $user_info = api_get_user($a);
$name = defaults($_REQUEST, 'name', ""); $name = $_REQUEST['name'] ?? '';
$uid = $user_info['uid']; $uid = $user_info['uid'];
$json = json_decode($_POST['json'], true); $json = json_decode($_POST['json'], true);
$users = $json['user']; $users = $json['user'];
@ -5847,7 +5824,7 @@ function api_lists_create($type)
// params // params
$user_info = api_get_user($a); $user_info = api_get_user($a);
$name = defaults($_REQUEST, 'name', ""); $name = $_REQUEST['name'] ?? '';
$uid = $user_info['uid']; $uid = $user_info['uid'];
$success = group_create($name, $uid); $success = group_create($name, $uid);
@ -5887,8 +5864,8 @@ function api_friendica_group_update($type)
// params // params
$user_info = api_get_user($a); $user_info = api_get_user($a);
$uid = $user_info['uid']; $uid = $user_info['uid'];
$gid = defaults($_REQUEST, 'gid', 0); $gid = $_REQUEST['gid'] ?? 0;
$name = defaults($_REQUEST, 'name', ""); $name = $_REQUEST['name'] ?? '';
$json = json_decode($_POST['json'], true); $json = json_decode($_POST['json'], true);
$users = $json['user']; $users = $json['user'];
@ -5965,8 +5942,8 @@ function api_lists_update($type)
// params // params
$user_info = api_get_user($a); $user_info = api_get_user($a);
$gid = defaults($_REQUEST, 'list_id', 0); $gid = $_REQUEST['list_id'] ?? 0;
$name = defaults($_REQUEST, 'name', ""); $name = $_REQUEST['name'] ?? '';
$uid = $user_info['uid']; $uid = $user_info['uid'];
// error if no gid specified // error if no gid specified
@ -6015,7 +5992,7 @@ function api_friendica_activity($type)
$verb = strtolower($a->argv[3]); $verb = strtolower($a->argv[3]);
$verb = preg_replace("|\..*$|", "", $verb); $verb = preg_replace("|\..*$|", "", $verb);
$id = defaults($_REQUEST, 'id', 0); $id = $_REQUEST['id'] ?? 0;
$res = Item::performLike($id, $verb); $res = Item::performLike($id, $verb);
@ -6152,7 +6129,7 @@ function api_friendica_direct_messages_setseen($type)
// params // params
$user_info = api_get_user($a); $user_info = api_get_user($a);
$uid = $user_info['uid']; $uid = $user_info['uid'];
$id = defaults($_REQUEST, 'id', 0); $id = $_REQUEST['id'] ?? 0;
// return error if id is zero // return error if id is zero
if ($id == "") { if ($id == "") {
@ -6206,7 +6183,7 @@ function api_friendica_direct_messages_search($type, $box = "")
// params // params
$user_info = api_get_user($a); $user_info = api_get_user($a);
$searchstring = defaults($_REQUEST, 'searchstring', ""); $searchstring = $_REQUEST['searchstring'] ?? '';
$uid = $user_info['uid']; $uid = $user_info['uid'];
// error if no searchstring specified // error if no searchstring specified
@ -6273,7 +6250,7 @@ function api_friendica_profile_show($type)
} }
// input params // input params
$profile_id = defaults($_REQUEST, 'profile_id', 0); $profile_id = $_REQUEST['profile_id'] ?? 0;
// retrieve general information about profiles for user // retrieve general information about profiles for user
$multi_profiles = Feature::isEnabled(api_user(), 'multi_profiles'); $multi_profiles = Feature::isEnabled(api_user(), 'multi_profiles');

View file

@ -365,7 +365,7 @@ function localize_item(&$item)
'network' => $item['author-network'], 'url' => $item['author-link']]; 'network' => $item['author-network'], 'url' => $item['author-link']];
// Only create a redirection to a magic link when logged in // Only create a redirection to a magic link when logged in
if (!empty($item['plink']) && (local_user() || remote_user())) { if (!empty($item['plink']) && Session::isAuthenticated()) {
$item['plink'] = Contact::magicLinkByContact($author, $item['plink']); $item['plink'] = Contact::magicLinkByContact($author, $item['plink']);
} }
} }
@ -1208,7 +1208,7 @@ function status_editor(App $a, $x, $notes_cid = 0, $popup = false)
'$new_post' => L10n::t('New Post'), '$new_post' => L10n::t('New Post'),
'$return_path' => $query_str, '$return_path' => $query_str,
'$action' => 'item', '$action' => 'item',
'$share' => defaults($x, 'button', L10n::t('Share')), '$share' => ($x['button'] ?? '') ?: L10n::t('Share'),
'$upload' => L10n::t('Upload photo'), '$upload' => L10n::t('Upload photo'),
'$shortupload' => L10n::t('upload photo'), '$shortupload' => L10n::t('upload photo'),
'$attach' => L10n::t('Attach file'), '$attach' => L10n::t('Attach file'),
@ -1225,17 +1225,17 @@ function status_editor(App $a, $x, $notes_cid = 0, $popup = false)
'$shortsetloc' => L10n::t('set location'), '$shortsetloc' => L10n::t('set location'),
'$noloc' => L10n::t('Clear browser location'), '$noloc' => L10n::t('Clear browser location'),
'$shortnoloc' => L10n::t('clear location'), '$shortnoloc' => L10n::t('clear location'),
'$title' => defaults($x, 'title', ''), '$title' => $x['title'] ?? '',
'$placeholdertitle' => L10n::t('Set title'), '$placeholdertitle' => L10n::t('Set title'),
'$category' => defaults($x, 'category', ''), '$category' => $x['category'] ?? '',
'$placeholdercategory' => Feature::isEnabled(local_user(), 'categories') ? L10n::t("Categories \x28comma-separated list\x29") : '', '$placeholdercategory' => Feature::isEnabled(local_user(), 'categories') ? L10n::t("Categories \x28comma-separated list\x29") : '',
'$wait' => L10n::t('Please wait'), '$wait' => L10n::t('Please wait'),
'$permset' => L10n::t('Permission settings'), '$permset' => L10n::t('Permission settings'),
'$shortpermset' => L10n::t('permissions'), '$shortpermset' => L10n::t('permissions'),
'$wall' => $notes_cid ? 0 : 1, '$wall' => $notes_cid ? 0 : 1,
'$posttype' => $notes_cid ? Item::PT_PERSONAL_NOTE : Item::PT_ARTICLE, '$posttype' => $notes_cid ? Item::PT_PERSONAL_NOTE : Item::PT_ARTICLE,
'$content' => defaults($x, 'content', ''), '$content' => $x['content'] ?? '',
'$post_id' => defaults($x, 'post_id', ''), '$post_id' => $x['post_id'] ?? '',
'$baseurl' => System::baseUrl(true), '$baseurl' => System::baseUrl(true),
'$defloc' => $x['default_location'], '$defloc' => $x['default_location'],
'$visitor' => $x['visitor'], '$visitor' => $x['visitor'],
@ -1527,9 +1527,9 @@ function get_responses(array $conv_responses, array $response_verbs, array $item
$ret = []; $ret = [];
foreach ($response_verbs as $v) { foreach ($response_verbs as $v) {
$ret[$v] = []; $ret[$v] = [];
$ret[$v]['count'] = defaults($conv_responses[$v], $item['uri'], 0); $ret[$v]['count'] = $conv_responses[$v][$item['uri']] ?? 0;
$ret[$v]['list'] = defaults($conv_responses[$v], $item['uri'] . '-l', []); $ret[$v]['list'] = $conv_responses[$v][$item['uri'] . '-l'] ?? [];
$ret[$v]['self'] = defaults($conv_responses[$v], $item['uri'] . '-self', '0'); $ret[$v]['self'] = $conv_responses[$v][$item['uri'] . '-self'] ?? '0';
if (count($ret[$v]['list']) > MAX_LIKERS) { if (count($ret[$v]['list']) > MAX_LIKERS) {
$ret[$v]['list_part'] = array_slice($ret[$v]['list'], 0, MAX_LIKERS); $ret[$v]['list_part'] = array_slice($ret[$v]['list'], 0, MAX_LIKERS);
array_push($ret[$v]['list_part'], '<a href="#" data-toggle="modal" data-target="#' . $v . 'Modal-' array_push($ret[$v]['list_part'], '<a href="#" data-toggle="modal" data-target="#' . $v . 'Modal-'

View file

@ -46,10 +46,10 @@ function notification($params)
return false; return false;
} }
$params['notify_flags'] = defaults($params, 'notify_flags', $user['notify-flags']); $params['notify_flags'] = ($params['notify_flags'] ?? '') ?: $user['notify-flags'];
$params['language'] = defaults($params, 'language' , $user['language']); $params['language'] = ($params['language'] ?? '') ?: $user['language'];
$params['to_name'] = defaults($params, 'to_name' , $user['username']); $params['to_name'] = ($params['to_name'] ?? '') ?: $user['username'];
$params['to_email'] = defaults($params, 'to_email' , $user['email']); $params['to_email'] = ($params['to_email'] ?? '') ?: $user['email'];
// from here on everything is in the recipients language // from here on everything is in the recipients language
L10n::pushLang($params['language']); L10n::pushLang($params['language']);
@ -142,7 +142,7 @@ function notification($params)
} }
if ($params['type'] == NOTIFY_COMMENT || $params['type'] == NOTIFY_TAGSELF) { if ($params['type'] == NOTIFY_COMMENT || $params['type'] == NOTIFY_TAGSELF) {
$thread = Item::selectFirstThreadForUser($params['uid'], ['ignored'], ['iid' => $parent_id]); $thread = Item::selectFirstThreadForUser($params['uid'], ['ignored'], ['iid' => $parent_id, 'deleted' => false]);
if (DBA::isResult($thread) && $thread['ignored']) { if (DBA::isResult($thread) && $thread['ignored']) {
Logger::log('Thread ' . $parent_id . ' will be ignored', Logger::DEBUG); Logger::log('Thread ' . $parent_id . ' will be ignored', Logger::DEBUG);
L10n::popLang(); L10n::popLang();
@ -161,7 +161,7 @@ function notification($params)
// if it's a post figure out who's post it is. // if it's a post figure out who's post it is.
$item = null; $item = null;
if ($params['otype'] === 'item' && $parent_id) { if ($params['otype'] === 'item' && $parent_id) {
$item = Item::selectFirstForUser($params['uid'], Item::ITEM_FIELDLIST, ['id' => $parent_id]); $item = Item::selectFirstForUser($params['uid'], Item::ITEM_FIELDLIST, ['id' => $parent_id, 'deleted' => false]);
} }
$item_post_type = Item::postType($item); $item_post_type = Item::postType($item);
@ -456,17 +456,17 @@ function notification($params)
if (!isset($params['subject'])) { if (!isset($params['subject'])) {
Logger::warning('subject isn\'t set.', ['type' => $params['type']]); Logger::warning('subject isn\'t set.', ['type' => $params['type']]);
} }
$subject = defaults($params, 'subject', ''); $subject = $params['subject'] ?? '';
if (!isset($params['preamble'])) { if (!isset($params['preamble'])) {
Logger::warning('preamble isn\'t set.', ['type' => $params['type'], 'subject' => $subject]); Logger::warning('preamble isn\'t set.', ['type' => $params['type'], 'subject' => $subject]);
} }
$preamble = defaults($params, 'preamble', ''); $preamble = $params['preamble'] ?? '';
if (!isset($params['body'])) { if (!isset($params['body'])) {
Logger::warning('body isn\'t set.', ['type' => $params['type'], 'subject' => $subject, 'preamble' => $preamble]); Logger::warning('body isn\'t set.', ['type' => $params['type'], 'subject' => $subject, 'preamble' => $preamble]);
} }
$body = defaults($params, 'body', ''); $body = $params['body'] ?? '';
$show_in_notification_page = false; $show_in_notification_page = false;
} }
@ -613,11 +613,11 @@ function notification($params)
$datarray['siteurl'] = $siteurl; $datarray['siteurl'] = $siteurl;
$datarray['type'] = $params['type']; $datarray['type'] = $params['type'];
$datarray['parent'] = $parent_id; $datarray['parent'] = $parent_id;
$datarray['source_name'] = defaults($params, 'source_name', ''); $datarray['source_name'] = $params['source_name'] ?? '';
$datarray['source_link'] = defaults($params, 'source_link', ''); $datarray['source_link'] = $params['source_link'] ?? '';
$datarray['source_photo'] = defaults($params, 'source_photo', ''); $datarray['source_photo'] = $params['source_photo'] ?? '';
$datarray['uid'] = $params['uid']; $datarray['uid'] = $params['uid'];
$datarray['username'] = defaults($params, 'to_name', ''); $datarray['username'] = $params['to_name'] ?? '';
$datarray['hsitelink'] = $hsitelink; $datarray['hsitelink'] = $hsitelink;
$datarray['tsitelink'] = $tsitelink; $datarray['tsitelink'] = $tsitelink;
$datarray['hitemlink'] = '<a href="'.$itemlink.'">'.$itemlink.'</a>'; $datarray['hitemlink'] = '<a href="'.$itemlink.'">'.$itemlink.'</a>';
@ -783,7 +783,7 @@ function check_item_notification($itemid, $uid, $defaulttype = "") {
$fields = ['id', 'mention', 'tag', 'parent', 'title', 'body', $fields = ['id', 'mention', 'tag', 'parent', 'title', 'body',
'author-link', 'author-name', 'author-avatar', 'author-id', 'author-link', 'author-name', 'author-avatar', 'author-id',
'guid', 'parent-uri', 'uri', 'contact-id', 'network']; 'guid', 'parent-uri', 'uri', 'contact-id', 'network'];
$condition = ['id' => $itemid, 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT]]; $condition = ['id' => $itemid, 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT], 'deleted' => false];
$item = Item::selectFirstForUser($uid, $fields, $condition); $item = Item::selectFirstForUser($uid, $fields, $condition);
if (!DBA::isResult($item) || in_array($item['author-id'], $contacts)) { if (!DBA::isResult($item) || in_array($item['author-id'], $contacts)) {
return false; return false;
@ -840,7 +840,7 @@ function check_item_notification($itemid, $uid, $defaulttype = "") {
// Is it a post that the user had started? // Is it a post that the user had started?
$fields = ['ignored', 'mention']; $fields = ['ignored', 'mention'];
$thread = Item::selectFirstThreadForUser($params['uid'], $fields, ['iid' => $item["parent"]]); $thread = Item::selectFirstThreadForUser($params['uid'], $fields, ['iid' => $item["parent"], 'deleted' => false]);
if ($thread['mention'] && !$thread['ignored'] && !isset($params["type"])) { if ($thread['mention'] && !$thread['ignored'] && !isset($params["type"])) {
$params["type"] = NOTIFY_COMMENT; $params["type"] = NOTIFY_COMMENT;
@ -848,7 +848,7 @@ function check_item_notification($itemid, $uid, $defaulttype = "") {
} }
// And now we check for participation of one of our contacts in the thread // And now we check for participation of one of our contacts in the thread
$condition = ['parent' => $item["parent"], 'author-id' => $contacts]; $condition = ['parent' => $item["parent"], 'author-id' => $contacts, 'deleted' => false];
if (!$thread['ignored'] && !isset($params["type"]) && Item::exists($condition)) { if (!$thread['ignored'] && !isset($params["type"]) && Item::exists($condition)) {
$params["type"] = NOTIFY_COMMENT; $params["type"] = NOTIFY_COMMENT;

View file

@ -13,6 +13,7 @@ use Friendica\Core\PConfig;
use Friendica\Core\Protocol; use Friendica\Core\Protocol;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Model\Item; use Friendica\Model\Item;
use Friendica\Protocol\DFRN; use Friendica\Protocol\DFRN;
@ -41,7 +42,7 @@ function add_page_info_data(array $data, $no_photos = false)
$data["type"] = "link"; $data["type"] = "link";
} }
$data["title"] = defaults($data, "title", ""); $data["title"] = $data["title"] ?? '';
if ((($data["type"] != "link") && ($data["type"] != "video") && ($data["type"] != "photo")) || ($data["title"] == $data["url"])) { if ((($data["type"] != "link") && ($data["type"] != "video") && ($data["type"] != "photo")) || ($data["title"] == $data["url"])) {
return ""; return "";
@ -326,7 +327,7 @@ function drop_items(array $items)
{ {
$uid = 0; $uid = 0;
if (!local_user() && !remote_user()) { if (!Session::isAuthenticated()) {
return; return;
} }
@ -362,14 +363,8 @@ function drop_item($id, $return = '')
$contact_id = 0; $contact_id = 0;
// check if logged in user is either the author or owner of this item // check if logged in user is either the author or owner of this item
if (Session::getRemoteContactID($item['uid']) == $item['contact-id']) {
if (!empty($_SESSION['remote'])) { $contact_id = $item['contact-id'];
foreach ($_SESSION['remote'] as $visitor) {
if ($visitor['uid'] == $item['uid'] && $visitor['cid'] == $item['contact-id']) {
$contact_id = $visitor['cid'];
break;
}
}
} }
if ((local_user() == $item['uid']) || $contact_id) { if ((local_user() == $item['uid']) || $contact_id) {

View file

@ -122,7 +122,7 @@ function redir_private_images($a, &$item)
} }
if ((local_user() == $item['uid']) && ($item['private'] == 1) && ($item['contact-id'] != $a->contact['id']) && ($item['network'] == Protocol::DFRN)) { if ((local_user() == $item['uid']) && ($item['private'] == 1) && ($item['contact-id'] != $a->contact['id']) && ($item['network'] == Protocol::DFRN)) {
$img_url = 'redir?f=1&quiet=1&url=' . urlencode($mtch[1]) . '&conurl=' . urlencode($item['author-link']); $img_url = 'redir/' . $item['contact-id'] . '?url=' . urlencode($mtch[1]);
$item['body'] = str_replace($mtch[0], '[img]' . $img_url . '[/img]', $item['body']); $item['body'] = str_replace($mtch[0], '[img]' . $img_url . '[/img]', $item['body']);
} }
} }

View file

@ -13,6 +13,7 @@ if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
require __DIR__ . '/vendor/autoload.php'; require __DIR__ . '/vendor/autoload.php';
$dice = (new Dice())->addRules(include __DIR__ . '/static/dependencies.config.php'); $dice = (new Dice())->addRules(include __DIR__ . '/static/dependencies.config.php');
$dice = $dice->addRule(Friendica\App\Mode::class, ['call' => [['determineRunMode', [false, $_SERVER], Dice::CHAIN_CALL]]]);
\Friendica\BaseObject::setDependencyInjection($dice); \Friendica\BaseObject::setDependencyInjection($dice);

View file

@ -4,27 +4,30 @@
/* Generic exception class /* Generic exception class
*/ */
if (!class_exists('OAuthException', false)) { if (!class_exists('OAuthException', false)) {
class OAuthException extends Exception { class OAuthException extends Exception
// pass { }
}
} }
class OAuthConsumer { class OAuthConsumer
{
public $key; public $key;
public $secret; public $secret;
function __construct($key, $secret, $callback_url=NULL) { function __construct($key, $secret, $callback_url = NULL)
{
$this->key = $key; $this->key = $key;
$this->secret = $secret; $this->secret = $secret;
$this->callback_url = $callback_url; $this->callback_url = $callback_url;
} }
function __toString() { function __toString()
{
return "OAuthConsumer[key=$this->key,secret=$this->secret]"; return "OAuthConsumer[key=$this->key,secret=$this->secret]";
} }
} }
class OAuthToken { class OAuthToken
{
// access tokens and request tokens // access tokens and request tokens
public $key; public $key;
public $secret; public $secret;
@ -37,7 +40,8 @@ class OAuthToken {
* key = the token * key = the token
* secret = the token secret * secret = the token secret
*/ */
function __construct($key, $secret) { function __construct($key, $secret)
{
$this->key = $key; $this->key = $key;
$this->secret = $secret; $this->secret = $secret;
} }
@ -46,14 +50,16 @@ class OAuthToken {
* generates the basic string serialization of a token that a server * generates the basic string serialization of a token that a server
* would respond to request_token and access_token calls with * would respond to request_token and access_token calls with
*/ */
function to_string() { function to_string()
{
return "oauth_token=" . return "oauth_token=" .
OAuthUtil::urlencode_rfc3986($this->key) . OAuthUtil::urlencode_rfc3986($this->key) .
"&oauth_token_secret=" . "&oauth_token_secret=" .
OAuthUtil::urlencode_rfc3986($this->secret); OAuthUtil::urlencode_rfc3986($this->secret);
} }
function __toString() { function __toString()
{
return $this->to_string(); return $this->to_string();
} }
} }
@ -62,7 +68,8 @@ class OAuthToken {
* A class for implementing a Signature Method * A class for implementing a Signature Method
* See section 9 ("Signing Requests") in the spec * See section 9 ("Signing Requests") in the spec
*/ */
abstract class OAuthSignatureMethod { abstract class OAuthSignatureMethod
{
/** /**
* Needs to return the name of the Signature Method (ie HMAC-SHA1) * Needs to return the name of the Signature Method (ie HMAC-SHA1)
* @return string * @return string
@ -89,7 +96,8 @@ abstract class OAuthSignatureMethod {
* @param string $signature * @param string $signature
* @return bool * @return bool
*/ */
public function check_signature($request, $consumer, $token, $signature) { public function check_signature($request, $consumer, $token, $signature)
{
$built = $this->build_signature($request, $consumer, $token); $built = $this->build_signature($request, $consumer, $token);
return ($built == $signature); return ($built == $signature);
} }
@ -102,12 +110,15 @@ abstract class OAuthSignatureMethod {
* character (ASCII code 38) even if empty. * character (ASCII code 38) even if empty.
* - Chapter 9.2 ("HMAC-SHA1") * - Chapter 9.2 ("HMAC-SHA1")
*/ */
class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod { class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod
function get_name() { {
function get_name()
{
return "HMAC-SHA1"; return "HMAC-SHA1";
} }
public function build_signature($request, $consumer, $token) { public function build_signature($request, $consumer, $token)
{
$base_string = $request->get_signature_base_string(); $base_string = $request->get_signature_base_string();
$request->base_string = $base_string; $request->base_string = $base_string;
@ -130,8 +141,10 @@ class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {
* over a secure channel such as HTTPS. It does not use the Signature Base String. * over a secure channel such as HTTPS. It does not use the Signature Base String.
* - Chapter 9.4 ("PLAINTEXT") * - Chapter 9.4 ("PLAINTEXT")
*/ */
class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod { class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod
public function get_name() { {
public function get_name()
{
return "PLAINTEXT"; return "PLAINTEXT";
} }
@ -144,7 +157,8 @@ class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {
* Please note that the second encoding MUST NOT happen in the SignatureMethod, as * Please note that the second encoding MUST NOT happen in the SignatureMethod, as
* OAuthRequest handles this! * OAuthRequest handles this!
*/ */
public function build_signature($request, $consumer, $token) { public function build_signature($request, $consumer, $token)
{
$key_parts = array( $key_parts = array(
$consumer->secret, $consumer->secret,
($token) ? $token->secret : "" ($token) ? $token->secret : ""
@ -166,8 +180,10 @@ class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {
* specification. * specification.
* - Chapter 9.3 ("RSA-SHA1") * - Chapter 9.3 ("RSA-SHA1")
*/ */
abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod { abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod
public function get_name() { {
public function get_name()
{
return "RSA-SHA1"; return "RSA-SHA1";
} }
@ -185,7 +201,8 @@ abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {
// Either way should return a string representation of the certificate // Either way should return a string representation of the certificate
protected abstract function fetch_private_cert(&$request); protected abstract function fetch_private_cert(&$request);
public function build_signature($request, $consumer, $token) { public function build_signature($request, $consumer, $token)
{
$base_string = $request->get_signature_base_string(); $base_string = $request->get_signature_base_string();
$request->base_string = $base_string; $request->base_string = $base_string;
@ -204,7 +221,8 @@ abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {
return base64_encode($signature); return base64_encode($signature);
} }
public function check_signature($request, $consumer, $token, $signature) { public function check_signature($request, $consumer, $token, $signature)
{
$decoded_sig = base64_decode($signature); $decoded_sig = base64_decode($signature);
$base_string = $request->get_signature_base_string(); $base_string = $request->get_signature_base_string();
@ -225,7 +243,8 @@ abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {
} }
} }
class OAuthRequest { class OAuthRequest
{
private $parameters; private $parameters;
private $http_method; private $http_method;
private $http_url; private $http_url;
@ -234,7 +253,8 @@ class OAuthRequest {
public static $version = '1.0'; public static $version = '1.0';
public static $POST_INPUT = 'php://input'; public static $POST_INPUT = 'php://input';
function __construct($http_method, $http_url, $parameters=NULL) { function __construct($http_method, $http_url, $parameters = NULL)
{
@$parameters or $parameters = array(); @$parameters or $parameters = array();
$parameters = array_merge(OAuthUtil::parse_parameters(parse_url($http_url, PHP_URL_QUERY)), $parameters); $parameters = array_merge(OAuthUtil::parse_parameters(parse_url($http_url, PHP_URL_QUERY)), $parameters);
$this->parameters = $parameters; $this->parameters = $parameters;
@ -246,7 +266,8 @@ class OAuthRequest {
/** /**
* attempt to build up a request from what was passed to the server * attempt to build up a request from what was passed to the server
*/ */
public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) { public static function from_request($http_method = NULL, $http_url = NULL, $parameters = NULL)
{
$scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on")
? 'http' ? 'http'
: 'https'; : 'https';
@ -270,9 +291,12 @@ class OAuthRequest {
// It's a POST request of the proper content-type, so parse POST // It's a POST request of the proper content-type, so parse POST
// parameters and add those overriding any duplicates from GET // parameters and add those overriding any duplicates from GET
if ($http_method == "POST" if (
&& @strstr($request_headers["Content-Type"], $http_method == "POST"
"application/x-www-form-urlencoded") && @strstr(
$request_headers["Content-Type"],
"application/x-www-form-urlencoded"
)
) { ) {
$post_data = OAuthUtil::parse_parameters( $post_data = OAuthUtil::parse_parameters(
file_get_contents(self::$POST_INPUT) file_get_contents(self::$POST_INPUT)
@ -288,7 +312,6 @@ class OAuthRequest {
); );
$parameters = array_merge($parameters, $header_parameters); $parameters = array_merge($parameters, $header_parameters);
} }
} }
// fix for friendica redirect system // fix for friendica redirect system
@ -301,12 +324,15 @@ class OAuthRequest {
/** /**
* pretty much a helper function to set up the request * pretty much a helper function to set up the request
*/ */
public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) { public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters = NULL)
{
@$parameters or $parameters = array(); @$parameters or $parameters = array();
$defaults = array("oauth_version" => OAuthRequest::$version, $defaults = array(
"oauth_version" => OAuthRequest::$version,
"oauth_nonce" => OAuthRequest::generate_nonce(), "oauth_nonce" => OAuthRequest::generate_nonce(),
"oauth_timestamp" => OAuthRequest::generate_timestamp(), "oauth_timestamp" => OAuthRequest::generate_timestamp(),
"oauth_consumer_key" => $consumer->key); "oauth_consumer_key" => $consumer->key
);
if ($token) if ($token)
$defaults['oauth_token'] = $token->key; $defaults['oauth_token'] = $token->key;
@ -315,7 +341,8 @@ class OAuthRequest {
return new OAuthRequest($http_method, $http_url, $parameters); return new OAuthRequest($http_method, $http_url, $parameters);
} }
public function set_parameter($name, $value, $allow_duplicates = true) { public function set_parameter($name, $value, $allow_duplicates = true)
{
if ($allow_duplicates && isset($this->parameters[$name])) { if ($allow_duplicates && isset($this->parameters[$name])) {
// We have already added parameter(s) with this name, so add to the list // We have already added parameter(s) with this name, so add to the list
if (is_scalar($this->parameters[$name])) { if (is_scalar($this->parameters[$name])) {
@ -330,15 +357,18 @@ class OAuthRequest {
} }
} }
public function get_parameter($name) { public function get_parameter($name)
{
return isset($this->parameters[$name]) ? $this->parameters[$name] : null; return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
} }
public function get_parameters() { public function get_parameters()
{
return $this->parameters; return $this->parameters;
} }
public function unset_parameter($name) { public function unset_parameter($name)
{
unset($this->parameters[$name]); unset($this->parameters[$name]);
} }
@ -346,7 +376,8 @@ class OAuthRequest {
* The request parameters, sorted and concatenated into a normalized string. * The request parameters, sorted and concatenated into a normalized string.
* @return string * @return string
*/ */
public function get_signable_parameters() { public function get_signable_parameters()
{
// Grab all parameters // Grab all parameters
$params = $this->parameters; $params = $this->parameters;
@ -366,7 +397,8 @@ class OAuthRequest {
* and the parameters (normalized), each urlencoded * and the parameters (normalized), each urlencoded
* and the concated with &. * and the concated with &.
*/ */
public function get_signature_base_string() { public function get_signature_base_string()
{
$parts = array( $parts = array(
$this->get_normalized_http_method(), $this->get_normalized_http_method(),
$this->get_normalized_http_url(), $this->get_normalized_http_url(),
@ -381,7 +413,8 @@ class OAuthRequest {
/** /**
* just uppercases the http method * just uppercases the http method
*/ */
public function get_normalized_http_method() { public function get_normalized_http_method()
{
return strtoupper($this->http_method); return strtoupper($this->http_method);
} }
@ -389,7 +422,8 @@ class OAuthRequest {
* parses the url and rebuilds it to be * parses the url and rebuilds it to be
* scheme://host/path * scheme://host/path
*/ */
public function get_normalized_http_url() { public function get_normalized_http_url()
{
$parts = parse_url($this->http_url); $parts = parse_url($this->http_url);
$port = @$parts['port']; $port = @$parts['port'];
@ -400,7 +434,8 @@ class OAuthRequest {
$port or $port = ($scheme == 'https') ? '443' : '80'; $port or $port = ($scheme == 'https') ? '443' : '80';
if (($scheme == 'https' && $port != '443') if (($scheme == 'https' && $port != '443')
|| ($scheme == 'http' && $port != '80')) { || ($scheme == 'http' && $port != '80')
) {
$host = "$host:$port"; $host = "$host:$port";
} }
return "$scheme://$host$path"; return "$scheme://$host$path";
@ -409,7 +444,8 @@ class OAuthRequest {
/** /**
* builds a url usable for a GET request * builds a url usable for a GET request
*/ */
public function to_url() { public function to_url()
{
$post_data = $this->to_postdata(); $post_data = $this->to_postdata();
$out = $this->get_normalized_http_url(); $out = $this->get_normalized_http_url();
if ($post_data) { if ($post_data) {
@ -421,9 +457,10 @@ class OAuthRequest {
/** /**
* builds the data one would send in a POST request * builds the data one would send in a POST request
*/ */
public function to_postdata($raw = false) { public function to_postdata($raw = false)
{
if ($raw) if ($raw)
return($this->parameters); return $this->parameters;
else else
return OAuthUtil::build_http_query($this->parameters); return OAuthUtil::build_http_query($this->parameters);
} }
@ -431,7 +468,8 @@ class OAuthRequest {
/** /**
* builds the Authorization: header * builds the Authorization: header
*/ */
public function to_header($realm=null) { public function to_header($realm = null)
{
$first = true; $first = true;
if ($realm) { if ($realm) {
$out = 'Authorization: OAuth realm="' . OAuthUtil::urlencode_rfc3986($realm) . '"'; $out = 'Authorization: OAuth realm="' . OAuthUtil::urlencode_rfc3986($realm) . '"';
@ -439,7 +477,6 @@ class OAuthRequest {
} else } else
$out = 'Authorization: OAuth'; $out = 'Authorization: OAuth';
$total = array();
foreach ($this->parameters as $k => $v) { foreach ($this->parameters as $k => $v) {
if (substr($k, 0, 5) != "oauth") continue; if (substr($k, 0, 5) != "oauth") continue;
if (is_array($v)) { if (is_array($v)) {
@ -455,12 +492,14 @@ class OAuthRequest {
return $out; return $out;
} }
public function __toString() { public function __toString()
{
return $this->to_url(); return $this->to_url();
} }
public function sign_request($signature_method, $consumer, $token) { public function sign_request($signature_method, $consumer, $token)
{
$this->set_parameter( $this->set_parameter(
"oauth_signature_method", "oauth_signature_method",
$signature_method->get_name(), $signature_method->get_name(),
@ -470,7 +509,8 @@ class OAuthRequest {
$this->set_parameter("oauth_signature", $signature, false); $this->set_parameter("oauth_signature", $signature, false);
} }
public function build_signature($signature_method, $consumer, $token) { public function build_signature($signature_method, $consumer, $token)
{
$signature = $signature_method->build_signature($this, $consumer, $token); $signature = $signature_method->build_signature($this, $consumer, $token);
return $signature; return $signature;
} }
@ -478,33 +518,35 @@ class OAuthRequest {
/** /**
* util function: current timestamp * util function: current timestamp
*/ */
private static function generate_timestamp() { private static function generate_timestamp()
{
return time(); return time();
} }
/** /**
* util function: current nonce * util function: current nonce
*/ */
private static function generate_nonce() { private static function generate_nonce()
$mt = microtime(); {
$rand = mt_rand(); return Friendica\Util\Strings::getRandomHex(32);
return md5($mt . $rand); // md5s look nicer than numbers
} }
} }
class OAuthServer { class OAuthServer
{
protected $timestamp_threshold = 300; // in seconds, five minutes protected $timestamp_threshold = 300; // in seconds, five minutes
protected $version = '1.0'; // hi blaine protected $version = '1.0'; // hi blaine
protected $signature_methods = array(); protected $signature_methods = array();
protected $data_store; protected $data_store;
function __construct($data_store) { function __construct($data_store)
{
$this->data_store = $data_store; $this->data_store = $data_store;
} }
public function add_signature_method($signature_method) { public function add_signature_method($signature_method)
{
$this->signature_methods[$signature_method->get_name()] = $this->signature_methods[$signature_method->get_name()] =
$signature_method; $signature_method;
} }
@ -515,7 +557,8 @@ class OAuthServer {
* process a request_token request * process a request_token request
* returns the request token on success * returns the request token on success
*/ */
public function fetch_request_token(&$request) { public function fetch_request_token(&$request)
{
$this->get_version($request); $this->get_version($request);
$consumer = $this->get_consumer($request); $consumer = $this->get_consumer($request);
@ -536,7 +579,8 @@ class OAuthServer {
* process an access_token request * process an access_token request
* returns the access token on success * returns the access token on success
*/ */
public function fetch_access_token(&$request) { public function fetch_access_token(&$request)
{
$this->get_version($request); $this->get_version($request);
$consumer = $this->get_consumer($request); $consumer = $this->get_consumer($request);
@ -556,19 +600,21 @@ class OAuthServer {
/** /**
* verify an api call, checks all the parameters * verify an api call, checks all the parameters
*/ */
public function verify_request(&$request) { public function verify_request(&$request)
{
$this->get_version($request); $this->get_version($request);
$consumer = $this->get_consumer($request); $consumer = $this->get_consumer($request);
$token = $this->get_token($request, $consumer, "access"); $token = $this->get_token($request, $consumer, "access");
$this->check_signature($request, $consumer, $token); $this->check_signature($request, $consumer, $token);
return array($consumer, $token); return [$consumer, $token];
} }
// Internals from here // Internals from here
/** /**
* version 1 * version 1
*/ */
private function get_version(&$request) { private function get_version(&$request)
{
$version = $request->get_parameter("oauth_version"); $version = $request->get_parameter("oauth_version");
if (!$version) { if (!$version) {
// Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present. // Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present.
@ -584,7 +630,8 @@ class OAuthServer {
/** /**
* figure out the signature with some defaults * figure out the signature with some defaults
*/ */
private function get_signature_method(&$request) { private function get_signature_method(&$request)
{
$signature_method = $signature_method =
@$request->get_parameter("oauth_signature_method"); @$request->get_parameter("oauth_signature_method");
@ -594,8 +641,10 @@ class OAuthServer {
throw new OAuthException('No signature method parameter. This parameter is required'); throw new OAuthException('No signature method parameter. This parameter is required');
} }
if (!in_array($signature_method, if (!in_array(
array_keys($this->signature_methods))) { $signature_method,
array_keys($this->signature_methods)
)) {
throw new OAuthException( throw new OAuthException(
"Signature method '$signature_method' not supported " . "Signature method '$signature_method' not supported " .
"try one of the following: " . "try one of the following: " .
@ -608,7 +657,8 @@ class OAuthServer {
/** /**
* try to find the consumer for the provided request's consumer key * try to find the consumer for the provided request's consumer key
*/ */
private function get_consumer(&$request) { private function get_consumer(&$request)
{
$consumer_key = @$request->get_parameter("oauth_consumer_key"); $consumer_key = @$request->get_parameter("oauth_consumer_key");
if (!$consumer_key) { if (!$consumer_key) {
throw new OAuthException("Invalid consumer key"); throw new OAuthException("Invalid consumer key");
@ -625,10 +675,13 @@ class OAuthServer {
/** /**
* try to find the token for the provided request's token key * try to find the token for the provided request's token key
*/ */
private function get_token(&$request, $consumer, $token_type="access") { private function get_token(&$request, $consumer, $token_type = "access")
{
$token_field = @$request->get_parameter('oauth_token'); $token_field = @$request->get_parameter('oauth_token');
$token = $this->data_store->lookup_token( $token = $this->data_store->lookup_token(
$consumer, $token_type, $token_field $consumer,
$token_type,
$token_field
); );
if (!$token) { if (!$token) {
throw new OAuthException("Invalid $token_type token: $token_field"); throw new OAuthException("Invalid $token_type token: $token_field");
@ -640,7 +693,8 @@ class OAuthServer {
* all-in-one function to check the signature on a request * all-in-one function to check the signature on a request
* should guess the signature method appropriately * should guess the signature method appropriately
*/ */
private function check_signature(&$request, $consumer, $token) { private function check_signature(&$request, $consumer, $token)
{
// this should probably be in a different method // this should probably be in a different method
$timestamp = @$request->get_parameter('oauth_timestamp'); $timestamp = @$request->get_parameter('oauth_timestamp');
$nonce = @$request->get_parameter('oauth_nonce'); $nonce = @$request->get_parameter('oauth_nonce');
@ -667,7 +721,8 @@ class OAuthServer {
/** /**
* check that the timestamp is new enough * check that the timestamp is new enough
*/ */
private function check_timestamp($timestamp) { private function check_timestamp($timestamp)
{
if (!$timestamp) if (!$timestamp)
throw new OAuthException( throw new OAuthException(
'Missing timestamp parameter. The parameter is required' 'Missing timestamp parameter. The parameter is required'
@ -685,7 +740,8 @@ class OAuthServer {
/** /**
* check that the nonce is not repeated * check that the nonce is not repeated
*/ */
private function check_nonce($consumer, $token, $nonce, $timestamp) { private function check_nonce($consumer, $token, $nonce, $timestamp)
{
if (!$nonce) if (!$nonce)
throw new OAuthException( throw new OAuthException(
'Missing nonce parameter. The parameter is required' 'Missing nonce parameter. The parameter is required'
@ -702,39 +758,45 @@ class OAuthServer {
throw new OAuthException("Nonce already used: $nonce"); throw new OAuthException("Nonce already used: $nonce");
} }
} }
} }
class OAuthDataStore { class OAuthDataStore
function lookup_consumer($consumer_key) { {
function lookup_consumer($consumer_key)
{
// implement me // implement me
} }
function lookup_token($consumer, $token_type, $token) { function lookup_token($consumer, $token_type, $token)
{
// implement me // implement me
} }
function lookup_nonce($consumer, $token, $nonce, $timestamp) { function lookup_nonce($consumer, $token, $nonce, $timestamp)
{
// implement me // implement me
} }
function new_request_token($consumer, $callback = null) { function new_request_token($consumer, $callback = null)
{
// return a new token attached to this consumer // return a new token attached to this consumer
} }
function new_access_token($token, $consumer, $verifier = null) { function new_access_token($token, $consumer, $verifier = null)
{
// return a new access token attached to this consumer // return a new access token attached to this consumer
// for the user associated with this token if the request token // for the user associated with this token if the request token
// is authorized // is authorized
// should also invalidate the request token // should also invalidate the request token
} }
} }
class OAuthUtil { class OAuthUtil
public static function urlencode_rfc3986($input) { {
public static function urlencode_rfc3986($input)
{
if (is_array($input)) { if (is_array($input)) {
return array_map(array('OAuthUtil', 'urlencode_rfc3986'), $input); return array_map(['OAuthUtil', 'urlencode_rfc3986'], $input);
} else if (is_scalar($input)) { } else if (is_scalar($input)) {
return str_replace( return str_replace(
'+', '+',
@ -750,17 +812,19 @@ class OAuthUtil {
// This decode function isn't taking into consideration the above // This decode function isn't taking into consideration the above
// modifications to the encoding process. However, this method doesn't // modifications to the encoding process. However, this method doesn't
// seem to be used anywhere so leaving it as is. // seem to be used anywhere so leaving it as is.
public static function urldecode_rfc3986($string) { public static function urldecode_rfc3986($string)
{
return urldecode($string); return urldecode($string);
} }
// Utility function for turning the Authorization: header into // Utility function for turning the Authorization: header into
// parameters, has to do some unescaping // parameters, has to do some unescaping
// Can filter out any non-oauth parameters if needed (default behaviour) // Can filter out any non-oauth parameters if needed (default behaviour)
public static function split_header($header, $only_allow_oauth_parameters = true) { public static function split_header($header, $only_allow_oauth_parameters = true)
{
$pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/'; $pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/';
$offset = 0; $offset = 0;
$params = array(); $params = [];
while (preg_match($pattern, $header, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) { while (preg_match($pattern, $header, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) {
$match = $matches[0]; $match = $matches[0];
$header_name = $matches[2][0]; $header_name = $matches[2][0];
@ -779,7 +843,8 @@ class OAuthUtil {
} }
// helper to try to sort out headers for people who aren't running apache // helper to try to sort out headers for people who aren't running apache
public static function get_headers() { public static function get_headers()
{
if (function_exists('apache_request_headers')) { if (function_exists('apache_request_headers')) {
// we need this to get the actual Authorization: header // we need this to get the actual Authorization: header
// because apache tends to tell us it doesn't exist // because apache tends to tell us it doesn't exist
@ -789,8 +854,8 @@ class OAuthUtil {
// we always want the keys to be Cased-Like-This and arh() // we always want the keys to be Cased-Like-This and arh()
// returns the headers in the same case as they are in the // returns the headers in the same case as they are in the
// request // request
$out = array(); $out = [];
foreach( $headers AS $key => $value ) { foreach ($headers as $key => $value) {
$key = str_replace( $key = str_replace(
" ", " ",
"-", "-",
@ -801,7 +866,7 @@ class OAuthUtil {
} else { } else {
// otherwise we don't have apache and are just going to have to hope // otherwise we don't have apache and are just going to have to hope
// that $_SERVER actually contains what we need // that $_SERVER actually contains what we need
$out = array(); $out = [];
if (isset($_SERVER['CONTENT_TYPE'])) if (isset($_SERVER['CONTENT_TYPE']))
$out['Content-Type'] = $_SERVER['CONTENT_TYPE']; $out['Content-Type'] = $_SERVER['CONTENT_TYPE'];
if (isset($_ENV['CONTENT_TYPE'])) if (isset($_ENV['CONTENT_TYPE']))
@ -827,12 +892,13 @@ class OAuthUtil {
// This function takes a input like a=b&a=c&d=e and returns the parsed // This function takes a input like a=b&a=c&d=e and returns the parsed
// parameters like this // parameters like this
// array('a' => array('b','c'), 'd' => 'e') // array('a' => array('b','c'), 'd' => 'e')
public static function parse_parameters( $input ) { public static function parse_parameters($input)
{
if (!isset($input) || !$input) return array(); if (!isset($input) || !$input) return array();
$pairs = explode('&', $input); $pairs = explode('&', $input);
$parsed_parameters = array(); $parsed_parameters = [];
foreach ($pairs as $pair) { foreach ($pairs as $pair) {
$split = explode('=', $pair, 2); $split = explode('=', $pair, 2);
$parameter = OAuthUtil::urldecode_rfc3986($split[0]); $parameter = OAuthUtil::urldecode_rfc3986($split[0]);
@ -845,7 +911,7 @@ class OAuthUtil {
if (is_scalar($parsed_parameters[$parameter])) { if (is_scalar($parsed_parameters[$parameter])) {
// This is the first duplicate, so transform scalar (string) into an array // This is the first duplicate, so transform scalar (string) into an array
// so we can add the duplicates // so we can add the duplicates
$parsed_parameters[$parameter] = array($parsed_parameters[$parameter]); $parsed_parameters[$parameter] = [$parsed_parameters[$parameter]];
} }
$parsed_parameters[$parameter][] = $value; $parsed_parameters[$parameter][] = $value;
@ -856,7 +922,8 @@ class OAuthUtil {
return $parsed_parameters; return $parsed_parameters;
} }
public static function build_http_query($params) { public static function build_http_query($params)
{
if (!$params) return ''; if (!$params) return '';
// Urlencode both keys and values // Urlencode both keys and values
@ -868,7 +935,7 @@ class OAuthUtil {
// Ref: Spec: 9.1.1 (1) // Ref: Spec: 9.1.1 (1)
uksort($params, 'strcmp'); uksort($params, 'strcmp');
$pairs = array(); $pairs = [];
foreach ($params as $parameter => $value) { foreach ($params as $parameter => $value) {
if (is_array($value)) { if (is_array($value)) {
// If two or more parameters share the same name, they are sorted by their value // If two or more parameters share the same name, they are sorted by their value
@ -886,5 +953,3 @@ class OAuthUtil {
return implode('&', $pairs); return implode('&', $pairs);
} }
} }
?>

View file

@ -1,316 +0,0 @@
<?php
/* ACL selector json backend */
use Friendica\App;
use Friendica\Content\Widget;
use Friendica\Core\ACL;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Protocol;
use Friendica\Database\DBA;
use Friendica\Model\Contact;
use Friendica\Model\Item;
use Friendica\Util\Proxy as ProxyUtils;
use Friendica\Util\Strings;
function acl_content(App $a)
{
if (!local_user()) {
return '';
}
$start = defaults($_REQUEST, 'start' , 0);
$count = defaults($_REQUEST, 'count' , 100);
$search = defaults($_REQUEST, 'search' , '');
$type = defaults($_REQUEST, 'type' , '');
$conv_id = defaults($_REQUEST, 'conversation', null);
// For use with jquery.textcomplete for private mail completion
if (!empty($_REQUEST['query'])) {
if (!$type) {
$type = 'm';
}
$search = $_REQUEST['query'];
}
Logger::info('ACL {action} - {subaction}', ['module' => 'acl', 'action' => 'content', 'subaction' => 'search', 'search' => $search, 'type' => $type, 'conversation' => $conv_id]);
if ($search != '') {
$sql_extra = "AND `name` LIKE '%%" . DBA::escape($search) . "%%'";
$sql_extra2 = "AND (`attag` LIKE '%%" . DBA::escape($search) . "%%' OR `name` LIKE '%%" . DBA::escape($search) . "%%' OR `nick` LIKE '%%" . DBA::escape($search) . "%%')";
} else {
/// @TODO Avoid these needless else blocks by putting variable-initialization atop of if()
$sql_extra = $sql_extra2 = '';
}
// count groups and contacts
$group_count = 0;
if ($type == '' || $type == 'g') {
$r = q("SELECT COUNT(*) AS g FROM `group` WHERE NOT `deleted` AND `uid` = %d $sql_extra",
intval(local_user())
);
$group_count = (int) $r[0]['g'];
}
$sql_extra2 .= ' ' . Widget::unavailableNetworks();
$contact_count = 0;
if ($type == '' || $type == 'c') {
// autocomplete for editor mentions
$r = q("SELECT COUNT(*) AS c FROM `contact`
WHERE `uid` = %d AND NOT `self` AND NOT `deleted`
AND NOT `blocked` AND NOT `pending` AND NOT `archive`
AND `notify` != '' $sql_extra2",
intval(local_user())
);
$contact_count = (int) $r[0]['c'];
} elseif ($type == 'f') {
// autocomplete for editor mentions of forums
$r = q("SELECT COUNT(*) AS c FROM `contact`
WHERE `uid` = %d AND NOT `self` AND NOT `deleted`
AND NOT `blocked` AND NOT `pending` AND NOT `archive`
AND (`forum` OR `prv`)
AND `notify` != '' $sql_extra2",
intval(local_user())
);
$contact_count = (int) $r[0]['c'];
} elseif ($type == 'm') {
// autocomplete for Private Messages
$r = q("SELECT COUNT(*) AS c FROM `contact`
WHERE `uid` = %d AND NOT `self` AND NOT `deleted`
AND NOT `blocked` AND NOT `pending` AND NOT `archive`
AND `network` IN ('%s', '%s', '%s') $sql_extra2",
intval(local_user()),
DBA::escape(Protocol::ACTIVITYPUB),
DBA::escape(Protocol::DFRN),
DBA::escape(Protocol::DIASPORA)
);
$contact_count = (int) $r[0]['c'];
} elseif ($type == 'a') {
// autocomplete for Contacts
$r = q("SELECT COUNT(*) AS c FROM `contact`
WHERE `uid` = %d AND NOT `self`
AND NOT `pending` AND NOT `deleted` $sql_extra2",
intval(local_user())
);
$contact_count = (int) $r[0]['c'];
}
$tot = $group_count + $contact_count;
$groups = [];
$contacts = [];
if ($type == '' || $type == 'g') {
/// @todo We should cache this query.
// This can be done when we can delete cache entries via wildcard
$r = q("SELECT `group`.`id`, `group`.`name`, GROUP_CONCAT(DISTINCT `group_member`.`contact-id` SEPARATOR ',') AS uids
FROM `group`
INNER JOIN `group_member` ON `group_member`.`gid`=`group`.`id`
WHERE NOT `group`.`deleted` AND `group`.`uid` = %d
$sql_extra
GROUP BY `group`.`name`, `group`.`id`
ORDER BY `group`.`name`
LIMIT %d,%d",
intval(local_user()),
intval($start),
intval($count)
);
foreach ($r as $g) {
$groups[] = [
'type' => 'g',
'photo' => 'images/twopeople.png',
'name' => htmlspecialchars($g['name']),
'id' => intval($g['id']),
'uids' => array_map('intval', explode(',', $g['uids'])),
'link' => '',
'forum' => '0'
];
}
if ((count($groups) > 0) && ($search == '')) {
$groups[] = ['separator' => true];
}
}
$r = [];
if ($type == '') {
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv`, (`prv` OR `forum`) AS `frm` FROM `contact`
WHERE `uid` = %d AND NOT `self` AND NOT `deleted` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
AND NOT (`network` IN ('%s', '%s'))
$sql_extra2
ORDER BY `name` ASC ",
intval(local_user()),
DBA::escape(Protocol::OSTATUS),
DBA::escape(Protocol::STATUSNET)
);
} elseif ($type == 'c') {
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
WHERE `uid` = %d AND NOT `self` AND NOT `deleted` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
AND NOT (`network` IN ('%s'))
$sql_extra2
ORDER BY `name` ASC ",
intval(local_user()),
DBA::escape(Protocol::STATUSNET)
);
} elseif ($type == 'f') {
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
WHERE `uid` = %d AND NOT `self` AND NOT `deleted` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
AND NOT (`network` IN ('%s'))
AND (`forum` OR `prv`)
$sql_extra2
ORDER BY `name` ASC ",
intval(local_user()),
DBA::escape(Protocol::STATUSNET)
);
} elseif ($type == 'm') {
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr` FROM `contact`
WHERE `uid` = %d AND NOT `self` AND NOT `deleted` AND NOT `blocked` AND NOT `pending` AND NOT `archive`
AND `network` IN ('%s', '%s', '%s')
$sql_extra2
ORDER BY `name` ASC ",
intval(local_user()),
DBA::escape(Protocol::ACTIVITYPUB),
DBA::escape(Protocol::DFRN),
DBA::escape(Protocol::DIASPORA)
);
} elseif ($type == 'a') {
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
WHERE `uid` = %d AND NOT `deleted` AND NOT `pending` AND NOT `archive`
$sql_extra2
ORDER BY `name` ASC ",
intval(local_user())
);
} elseif ($type == 'x') {
// autocomplete for global contact search (e.g. navbar search)
$search = Strings::escapeTags(trim($_REQUEST['search']));
$mode = $_REQUEST['smode'];
$r = ACL::contactAutocomplete($search, $mode);
$contacts = [];
foreach ($r as $g) {
$contacts[] = [
'photo' => ProxyUtils::proxifyUrl($g['photo'], false, ProxyUtils::SIZE_MICRO),
'name' => htmlspecialchars($g['name']),
'nick' => defaults($g, 'addr', $g['url']),
'network' => $g['network'],
'link' => $g['url'],
'forum' => !empty($g['community']) ? 1 : 0,
];
}
$o = [
'start' => $start,
'count' => $count,
'items' => $contacts,
];
echo json_encode($o);
exit;
}
if (DBA::isResult($r)) {
$forums = [];
foreach ($r as $g) {
$entry = [
'type' => 'c',
'photo' => ProxyUtils::proxifyUrl($g['micro'], false, ProxyUtils::SIZE_MICRO),
'name' => htmlspecialchars($g['name']),
'id' => intval($g['id']),
'network' => $g['network'],
'link' => $g['url'],
'nick' => htmlentities(defaults($g, 'attag', $g['nick'])),
'addr' => htmlentities(defaults($g, 'addr', $g['url'])),
'forum' => !empty($g['forum']) || !empty($g['prv']) ? 1 : 0,
];
if ($entry['forum']) {
$forums[] = $entry;
} else {
$contacts[] = $entry;
}
}
if (count($forums) > 0) {
if ($search == '') {
$forums[] = ['separator' => true];
}
$contacts = array_merge($forums, $contacts);
}
}
$items = array_merge($groups, $contacts);
if ($conv_id) {
// In multi threaded posts the conv_id is not the parent of the whole thread
$parent_item = Item::selectFirst(['parent'], ['id' => $conv_id]);
if (DBA::isResult($parent_item)) {
$conv_id = $parent_item['parent'];
}
/*
* if $conv_id is set, get unknown contacts in thread
* but first get known contacts url to filter them out
*/
$known_contacts = array_map(function ($i) {
return $i['link'];
}, $contacts);
$unknown_contacts = [];
$condition = ["`parent` = ?", $conv_id];
$params = ['order' => ['author-name' => true]];
$authors = Item::selectForUser(local_user(), ['author-link'], $condition, $params);
$item_authors = [];
while ($author = Item::fetch($authors)) {
$item_authors[$author['author-link']] = $author['author-link'];
}
DBA::close($authors);
foreach ($item_authors as $author) {
if (in_array($author, $known_contacts)) {
continue;
}
$contact = Contact::getDetailsByURL($author);
if (count($contact) > 0) {
$unknown_contacts[] = [
'type' => 'c',
'photo' => ProxyUtils::proxifyUrl($contact['micro'], false, ProxyUtils::SIZE_MICRO),
'name' => htmlspecialchars($contact['name']),
'id' => intval($contact['cid']),
'network' => $contact['network'],
'link' => $contact['url'],
'nick' => htmlentities(defaults($contact, 'nick', $contact['addr'])),
'addr' => htmlentities(defaults($contact, 'addr', $contact['url'])),
'forum' => $contact['forum']
];
}
}
$items = array_merge($items, $unknown_contacts);
$tot += count($unknown_contacts);
}
$results = [
'tot' => $tot,
'start' => $start,
'count' => $count,
'groups' => $groups,
'contacts' => $contacts,
'items' => $items,
'type' => $type,
'search' => $search,
];
Hook::callAll('acl_lookup_end', $results);
$o = [
'tot' => $results['tot'],
'start' => $results['start'],
'count' => $results['count'],
'items' => $results['items'],
];
echo json_encode($o);
exit;
}

View file

@ -2,6 +2,7 @@
/** /**
* @file mod/api.php * @file mod/api.php
*/ */
use Friendica\App; use Friendica\App;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\L10n; use Friendica\Core\L10n;
@ -9,7 +10,7 @@ use Friendica\Core\Renderer;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Module\Login; use Friendica\Module\Login;
require_once 'include/api.php'; require_once __DIR__ . '/../include/api.php';
function oauth_get_client(OAuthRequest $request) function oauth_get_client(OAuthRequest $request)
{ {

View file

@ -14,6 +14,7 @@ use Friendica\Core\Config;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Model\Event; use Friendica\Model\Event;
@ -26,11 +27,7 @@ use Friendica\Util\Temporal;
function cal_init(App $a) function cal_init(App $a)
{ {
if ($a->argc > 1) { if (Config::get('system', 'block_public') && !Session::isAuthenticated()) {
DFRN::autoRedir($a, $a->argv[1]);
}
if (Config::get('system', 'block_public') && !local_user() && !remote_user()) {
throw new \Friendica\Network\HTTPException\ForbiddenException(L10n::t('Access denied.')); throw new \Friendica\Network\HTTPException\ForbiddenException(L10n::t('Access denied.'));
} }
@ -113,18 +110,11 @@ function cal_content(App $a)
$owner_uid = intval($a->data['user']['uid']); $owner_uid = intval($a->data['user']['uid']);
$nick = $a->data['user']['nickname']; $nick = $a->data['user']['nickname'];
if (!empty($_SESSION['remote']) && is_array($_SESSION['remote'])) { if (!empty(Session::getRemoteContactID($a->profile['profile_uid']))) {
foreach ($_SESSION['remote'] as $v) { $contact_id = Session::getRemoteContactID($a->profile['profile_uid']);
if ($v['uid'] == $a->profile['profile_uid']) {
$contact_id = $v['cid'];
break;
}
}
} }
$groups = [];
if ($contact_id) { if ($contact_id) {
$groups = Group::getIdsByContactId($contact_id);
$r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
intval($contact_id), intval($contact_id),
intval($a->profile['profile_uid']) intval($a->profile['profile_uid'])
@ -142,7 +132,7 @@ function cal_content(App $a)
} }
// get the permissions // get the permissions
$sql_perms = Item::getPermissionsSQLByUserId($owner_uid, $remote_contact, $groups); $sql_perms = Item::getPermissionsSQLByUserId($owner_uid);
// we only want to have the events of the profile owner // we only want to have the events of the profile owner
$sql_extra = " AND `event`.`cid` = 0 " . $sql_perms; $sql_extra = " AND `event`.`cid` = 0 " . $sql_perms;
@ -210,7 +200,7 @@ function cal_content(App $a)
// put the event parametes in an array so we can better transmit them // put the event parametes in an array so we can better transmit them
$event_params = [ $event_params = [
'event_id' => intval(defaults($_GET, 'id', 0)), 'event_id' => intval($_GET['id'] ?? 0),
'start' => $start, 'start' => $start,
'finish' => $finish, 'finish' => $finish,
'adjust_start' => $adjust_start, 'adjust_start' => $adjust_start,

View file

@ -118,7 +118,7 @@ function common_content(App $a)
$entry = [ $entry = [
'url' => Model\Contact::magicLink($common_friend['url']), 'url' => Model\Contact::magicLink($common_friend['url']),
'itemurl' => defaults($contact_details, 'addr', $common_friend['url']), 'itemurl' => ($contact_details['addr'] ?? '') ?: $common_friend['url'],
'name' => $contact_details['name'], 'name' => $contact_details['name'],
'thumb' => ProxyUtils::proxifyUrl($contact_details['thumb'], false, ProxyUtils::SIZE_THUMB), 'thumb' => ProxyUtils::proxifyUrl($contact_details['thumb'], false, ProxyUtils::SIZE_THUMB),
'img_hover' => $contact_details['name'], 'img_hover' => $contact_details['name'],

View file

@ -17,19 +17,11 @@ use Friendica\Database\DBA;
use Friendica\Model\Item; use Friendica\Model\Item;
use Friendica\Model\User; use Friendica\Model\User;
function community_init(App $a)
{
if (!local_user()) {
unset($_SESSION['theme']);
unset($_SESSION['mobile-theme']);
}
}
function community_content(App $a, $update = 0) function community_content(App $a, $update = 0)
{ {
$o = ''; $o = '';
if (Config::get('system', 'block_public') && !local_user() && !remote_user()) { if (Config::get('system', 'block_public') && !Session::isAuthenticated()) {
notice(L10n::t('Public access denied.') . EOL); notice(L10n::t('Public access denied.') . EOL);
return; return;
} }
@ -227,6 +219,7 @@ function community_getitems($start, $itemspage, $content, $accounttype)
$values = [$start, $itemspage]; $values = [$start, $itemspage];
} }
/// @todo Use "unsearchable" here as well (instead of "hidewall")
$r = DBA::p("SELECT `item`.`uri`, `author`.`url` AS `author-link` FROM `thread` $r = DBA::p("SELECT `item`.`uri`, `author`.`url` AS `author-link` FROM `thread`
STRAIGHT_JOIN `user` ON `user`.`uid` = `thread`.`uid` AND NOT `user`.`hidewall` STRAIGHT_JOIN `user` ON `user`.`uid` = `thread`.`uid` AND NOT `user`.`hidewall`
STRAIGHT_JOIN `item` ON `item`.`id` = `thread`.`iid` STRAIGHT_JOIN `item` ON `item`.`id` = `thread`.`iid`
@ -237,9 +230,9 @@ function community_getitems($start, $itemspage, $content, $accounttype)
return DBA::toArray($r); return DBA::toArray($r);
} elseif ($content == 'global') { } elseif ($content == 'global') {
if (!is_null($accounttype)) { if (!is_null($accounttype)) {
$condition = ["`uid` = ? AND `owner`.`contact-type` = ?", 0, $accounttype]; $condition = ["`uid` = ? AND NOT `author`.`unsearchable` AND NOT `owner`.`unsearchable` AND `owner`.`contact-type` = ?", 0, $accounttype];
} else { } else {
$condition = ['uid' => 0]; $condition = ["`uid` = ? AND NOT `author`.`unsearchable` AND NOT `owner`.`unsearchable`", 0];
} }
$r = Item::selectThreadForUser(0, ['uri'], $condition, ['order' => ['commented' => true], 'limit' => [$start, $itemspage]]); $r = Item::selectThreadForUser(0, ['uri'], $condition, ['order' => ['commented' => true], 'limit' => [$start, $itemspage]]);

View file

@ -38,17 +38,17 @@ function crepair_post(App $a)
return; return;
} }
$name = defaults($_POST, 'name' , $contact['name']); $name = ($_POST['name'] ?? '') ?: $contact['name'];
$nick = defaults($_POST, 'nick' , ''); $nick = $_POST['nick'] ?? '';
$url = defaults($_POST, 'url' , ''); $url = $_POST['url'] ?? '';
$alias = defaults($_POST, 'alias' , ''); $alias = $_POST['alias'] ?? '';
$request = defaults($_POST, 'request' , ''); $request = $_POST['request'] ?? '';
$confirm = defaults($_POST, 'confirm' , ''); $confirm = $_POST['confirm'] ?? '';
$notify = defaults($_POST, 'notify' , ''); $notify = $_POST['notify'] ?? '';
$poll = defaults($_POST, 'poll' , ''); $poll = $_POST['poll'] ?? '';
$attag = defaults($_POST, 'attag' , ''); $attag = $_POST['attag'] ?? '';
$photo = defaults($_POST, 'photo' , ''); $photo = $_POST['photo'] ?? '';
$remote_self = defaults($_POST, 'remote_self', false); $remote_self = $_POST['remote_self'] ?? false;
$nurl = Strings::normaliseLink($url); $nurl = Strings::normaliseLink($url);
$r = DBA::update( $r = DBA::update(

View file

@ -1,191 +0,0 @@
<?php
/**
* @file mod/delegate.php
*/
use Friendica\App;
use Friendica\BaseModule;
use Friendica\Core\L10n;
use Friendica\Core\Protocol;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Database\DBA;
use Friendica\Model\User;
use Friendica\Util\Strings;
require_once 'mod/settings.php';
function delegate_init(App $a)
{
settings_init($a);
}
function delegate_post(App $a)
{
if (!local_user()) {
return;
}
if (count($a->user) && !empty($a->user['uid']) && $a->user['uid'] != local_user()) {
notice(L10n::t('Permission denied.') . EOL);
return;
}
BaseModule::checkFormSecurityTokenRedirectOnError('/delegate', 'delegate');
$parent_uid = defaults($_POST, 'parent_user', 0);
$parent_password = defaults($_POST, 'parent_password', '');
if ($parent_uid != 0) {
$user = DBA::selectFirst('user', ['nickname'], ['uid' => $parent_uid]);
if (!DBA::isResult($user)) {
notice(L10n::t('Parent user not found.') . EOL);
return;
}
$success = User::authenticate($user['nickname'], trim($parent_password));
if (!$success) {
notice(L10n::t('Permission denied.') . EOL);
return;
}
}
DBA::update('user', ['parent-uid' => $parent_uid], ['uid' => local_user()]);
}
function delegate_content(App $a)
{
if (!local_user()) {
notice(L10n::t('Permission denied.') . EOL);
return;
}
if ($a->argc > 2 && $a->argv[1] === 'add' && intval($a->argv[2])) {
// delegated admins can view but not change delegation permissions
if (!empty($_SESSION['submanage'])) {
$a->internalRedirect('delegate');
}
$user_id = $a->argv[2];
$user = DBA::selectFirst('user', ['nickname'], ['uid' => $user_id]);
if (DBA::isResult($user)) {
$condition = [
'uid' => local_user(),
'nurl' => Strings::normaliseLink(System::baseUrl() . '/profile/' . $user['nickname'])
];
if (DBA::exists('contact', $condition)) {
DBA::insert('manage', ['uid' => $user_id, 'mid' => local_user()]);
}
}
$a->internalRedirect('delegate');
}
if ($a->argc > 2 && $a->argv[1] === 'remove' && intval($a->argv[2])) {
// delegated admins can view but not change delegation permissions
if (!empty($_SESSION['submanage'])) {
$a->internalRedirect('delegate');
}
DBA::delete('manage', ['uid' => $a->argv[2], 'mid' => local_user()]);
$a->internalRedirect('delegate');
}
// find everybody that currently has delegated management to this account/page
$delegates = [];
$r = q("SELECT * FROM `user` WHERE `uid` IN (SELECT `uid` FROM `manage` WHERE `mid` = %d)",
intval(local_user())
);
if (DBA::isResult($r)) {
$delegates = $r;
}
$uids = [];
foreach ($delegates as $rr) {
$uids[] = $rr['uid'];
}
// find every contact who might be a candidate for delegation
$potentials = [];
$r = q("SELECT `nurl`
FROM `contact`
WHERE `self` = 0
AND SUBSTRING_INDEX(`nurl`, '/', 3) = '%s'
AND `uid` = %d
AND `network` = '%s' ",
DBA::escape(Strings::normaliseLink(System::baseUrl())),
intval(local_user()),
DBA::escape(Protocol::DFRN)
);
if (DBA::isResult($r)) {
$nicknames = [];
foreach ($r as $rr) {
$nicknames[] = "'" . DBA::escape(basename($rr['nurl'])) . "'";
}
$nicks = implode(',', $nicknames);
// get user records for all potential page delegates who are not already delegates or managers
$r = q("SELECT `uid`, `username`, `nickname` FROM `user` WHERE `nickname` IN ($nicks)");
if (DBA::isResult($r)) {
foreach ($r as $rr) {
if (!in_array($rr['uid'], $uids)) {
$potentials[] = $rr;
}
}
}
}
settings_init($a);
$user = DBA::selectFirst('user', ['parent-uid', 'email'], ['uid' => local_user()]);
$parent_user = null;
if (DBA::isResult($user)) {
if (!DBA::exists('user', ['parent-uid' => local_user()])) {
$parent_uid = $user['parent-uid'];
$parents = [0 => L10n::t('No parent user')];
$fields = ['uid', 'username', 'nickname'];
$condition = ['email' => $user['email'], 'verified' => true, 'blocked' => false, 'parent-uid' => 0];
$parent_users = DBA::select('user', $fields, $condition);
while ($parent = DBA::fetch($parent_users)) {
if ($parent['uid'] != local_user()) {
$parents[$parent['uid']] = sprintf('%s (%s)', $parent['username'], $parent['nickname']);
}
}
$parent_user = ['parent_user', '', $parent_uid, '', $parents];
}
}
if (!is_null($parent_user)) {
$parent_password = ['parent_password', L10n::t('Parent Password:'), '', L10n::t('Please enter the password of the parent account to legitimize your request.')];
} else {
$parent_password = '';
}
$o = Renderer::replaceMacros(Renderer::getMarkupTemplate('delegate.tpl'), [
'$form_security_token' => BaseModule::getFormSecurityToken('delegate'),
'$parent_header' => L10n::t('Parent User'),
'$parent_user' => $parent_user,
'$parent_password' => $parent_password,
'$parent_desc' => L10n::t('Parent users have total control about this account, including the account settings. Please double check whom you give this access.'),
'$submit' => L10n::t('Save Settings'),
'$header' => L10n::t('Delegate Page Management'),
'$delegates_header' => L10n::t('Delegates'),
'$base' => System::baseUrl(),
'$desc' => L10n::t('Delegates are able to manage all aspects of this account/page except for basic account settings. Please do not delegate your personal account to anybody that you do not trust completely.'),
'$head_delegates' => L10n::t('Existing Page Delegates'),
'$delegates' => $delegates,
'$head_potentials' => L10n::t('Potential Delegates'),
'$potentials' => $potentials,
'$remove' => L10n::t('Remove'),
'$add' => L10n::t('Add'),
'$none' => L10n::t('No entries.')
]);
return $o;
}

View file

@ -59,7 +59,7 @@ function dfrn_confirm_post(App $a, $handsfree = null)
* since we are operating on behalf of our registered user to approve a friendship. * since we are operating on behalf of our registered user to approve a friendship.
*/ */
if (empty($_POST['source_url'])) { if (empty($_POST['source_url'])) {
$uid = defaults($handsfree, 'uid', local_user()); $uid = ($handsfree['uid'] ?? 0) ?: local_user();
if (!$uid) { if (!$uid) {
notice(L10n::t('Permission denied.') . EOL); notice(L10n::t('Permission denied.') . EOL);
return; return;
@ -78,13 +78,13 @@ function dfrn_confirm_post(App $a, $handsfree = null)
$intro_id = $handsfree['intro_id']; $intro_id = $handsfree['intro_id'];
$duplex = $handsfree['duplex']; $duplex = $handsfree['duplex'];
$cid = 0; $cid = 0;
$hidden = intval(defaults($handsfree, 'hidden' , 0)); $hidden = intval($handsfree['hidden'] ?? 0);
} else { } else {
$dfrn_id = Strings::escapeTags(trim(defaults($_POST, 'dfrn_id' , ''))); $dfrn_id = Strings::escapeTags(trim($_POST['dfrn_id'] ?? ''));
$intro_id = intval(defaults($_POST, 'intro_id' , 0)); $intro_id = intval($_POST['intro_id'] ?? 0);
$duplex = intval(defaults($_POST, 'duplex' , 0)); $duplex = intval($_POST['duplex'] ?? 0);
$cid = intval(defaults($_POST, 'contact_id', 0)); $cid = intval($_POST['contact_id'] ?? 0);
$hidden = intval(defaults($_POST, 'hidden' , 0)); $hidden = intval($_POST['hidden'] ?? 0);
} }
/* /*
@ -347,12 +347,12 @@ function dfrn_confirm_post(App $a, $handsfree = null)
*/ */
if (!empty($_POST['source_url'])) { if (!empty($_POST['source_url'])) {
// We are processing an external confirmation to an introduction created by our user. // We are processing an external confirmation to an introduction created by our user.
$public_key = defaults($_POST, 'public_key', ''); $public_key = $_POST['public_key'] ?? '';
$dfrn_id = hex2bin(defaults($_POST, 'dfrn_id' , '')); $dfrn_id = hex2bin($_POST['dfrn_id'] ?? '');
$source_url = hex2bin(defaults($_POST, 'source_url', '')); $source_url = hex2bin($_POST['source_url'] ?? '');
$aes_key = defaults($_POST, 'aes_key' , ''); $aes_key = $_POST['aes_key'] ?? '';
$duplex = intval(defaults($_POST, 'duplex' , 0)); $duplex = intval($_POST['duplex'] ?? 0);
$page = intval(defaults($_POST, 'page' , 0)); $page = intval($_POST['page'] ?? 0);
$forum = (($page == 1) ? 1 : 0); $forum = (($page == 1) ? 1 : 0);
$prv = (($page == 2) ? 1 : 0); $prv = (($page == 2) ? 1 : 0);

View file

@ -26,7 +26,7 @@ function dfrn_notify_post(App $a) {
if (empty($_POST) || !empty($postdata)) { if (empty($_POST) || !empty($postdata)) {
$data = json_decode($postdata); $data = json_decode($postdata);
if (is_object($data)) { if (is_object($data)) {
$nick = defaults($a->argv, 1, ''); $nick = $a->argv[1] ?? '';
$user = DBA::selectFirst('user', [], ['nickname' => $nick, 'account_expired' => false, 'account_removed' => false]); $user = DBA::selectFirst('user', [], ['nickname' => $nick, 'account_expired' => false, 'account_removed' => false]);
if (!DBA::isResult($user)) { if (!DBA::isResult($user)) {
@ -42,8 +42,8 @@ function dfrn_notify_post(App $a) {
$dfrn_id = (!empty($_POST['dfrn_id']) ? Strings::escapeTags(trim($_POST['dfrn_id'])) : ''); $dfrn_id = (!empty($_POST['dfrn_id']) ? Strings::escapeTags(trim($_POST['dfrn_id'])) : '');
$dfrn_version = (!empty($_POST['dfrn_version']) ? (float) $_POST['dfrn_version'] : 2.0); $dfrn_version = (!empty($_POST['dfrn_version']) ? (float) $_POST['dfrn_version'] : 2.0);
$challenge = (!empty($_POST['challenge']) ? Strings::escapeTags(trim($_POST['challenge'])) : ''); $challenge = (!empty($_POST['challenge']) ? Strings::escapeTags(trim($_POST['challenge'])) : '');
$data = defaults($_POST, 'data', ''); $data = $_POST['data'] ?? '';
$key = defaults($_POST, 'key', ''); $key = $_POST['key'] ?? '';
$rino_remote = (!empty($_POST['rino']) ? intval($_POST['rino']) : 0); $rino_remote = (!empty($_POST['rino']) ? intval($_POST['rino']) : 0);
$dissolve = (!empty($_POST['dissolve']) ? intval($_POST['dissolve']) : 0); $dissolve = (!empty($_POST['dissolve']) ? intval($_POST['dissolve']) : 0);
$perm = (!empty($_POST['perm']) ? Strings::escapeTags(trim($_POST['perm'])) : 'r'); $perm = (!empty($_POST['perm']) ? Strings::escapeTags(trim($_POST['perm'])) : 'r');

View file

@ -9,6 +9,7 @@ use Friendica\Core\Config;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Core\Logger; use Friendica\Core\Logger;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Module\Login; use Friendica\Module\Login;
use Friendica\Protocol\DFRN; use Friendica\Protocol\DFRN;
@ -21,17 +22,17 @@ function dfrn_poll_init(App $a)
{ {
Login::sessionAuth(); Login::sessionAuth();
$dfrn_id = defaults($_GET, 'dfrn_id' , ''); $dfrn_id = $_GET['dfrn_id'] ?? '';
$type = defaults($_GET, 'type' , 'data'); $type = ($_GET['type'] ?? '') ?: 'data';
$last_update = defaults($_GET, 'last_update' , ''); $last_update = $_GET['last_update'] ?? '';
$destination_url = defaults($_GET, 'destination_url', ''); $destination_url = $_GET['destination_url'] ?? '';
$challenge = defaults($_GET, 'challenge' , ''); $challenge = $_GET['challenge'] ?? '';
$sec = defaults($_GET, 'sec' , ''); $sec = $_GET['sec'] ?? '';
$dfrn_version = (float) defaults($_GET, 'dfrn_version' , 2.0); $dfrn_version = floatval(($_GET['dfrn_version'] ?? 0.0) ?: 2.0);
$quiet = !empty($_GET['quiet']); $quiet = !empty($_GET['quiet']);
// Possibly it is an OStatus compatible server that requests a user feed // Possibly it is an OStatus compatible server that requests a user feed
$user_agent = defaults($_SERVER, 'HTTP_USER_AGENT', ''); $user_agent = $_SERVER['HTTP_USER_AGENT'] ?? '';
if (($a->argc > 1) && ($dfrn_id == '') && !strstr($user_agent, 'Friendica')) { if (($a->argc > 1) && ($dfrn_id == '') && !strstr($user_agent, 'Friendica')) {
$nickname = $a->argv[1]; $nickname = $a->argv[1];
header("Content-type: application/atom+xml"); header("Content-type: application/atom+xml");
@ -49,7 +50,7 @@ function dfrn_poll_init(App $a)
$hidewall = false; $hidewall = false;
if (($dfrn_id === '') && empty($_POST['dfrn_id'])) { if (($dfrn_id === '') && empty($_POST['dfrn_id'])) {
if (Config::get('system', 'block_public') && !local_user() && !remote_user()) { if (Config::get('system', 'block_public') && !Session::isAuthenticated()) {
throw new \Friendica\Network\HTTPException\ForbiddenException(); throw new \Friendica\Network\HTTPException\ForbiddenException();
} }
@ -110,17 +111,14 @@ function dfrn_poll_init(App $a)
if ((int)$xml->status === 1) { if ((int)$xml->status === 1) {
$_SESSION['authenticated'] = 1; $_SESSION['authenticated'] = 1;
if (empty($_SESSION['remote'])) {
$_SESSION['remote'] = [];
}
$_SESSION['remote'][] = ['cid' => $r[0]['id'], 'uid' => $r[0]['uid'], 'url' => $r[0]['url']];
$_SESSION['visitor_id'] = $r[0]['id']; $_SESSION['visitor_id'] = $r[0]['id'];
$_SESSION['visitor_home'] = $r[0]['url']; $_SESSION['visitor_home'] = $r[0]['url'];
$_SESSION['visitor_handle'] = $r[0]['addr']; $_SESSION['visitor_handle'] = $r[0]['addr'];
$_SESSION['visitor_visiting'] = $r[0]['uid']; $_SESSION['visitor_visiting'] = $r[0]['uid'];
$_SESSION['my_url'] = $r[0]['url']; $_SESSION['my_url'] = $r[0]['url'];
Session::setVisitorsContacts();
if (!$quiet) { if (!$quiet) {
info(L10n::t('%1$s welcomes %2$s', $r[0]['username'], $r[0]['name']) . EOL); info(L10n::t('%1$s welcomes %2$s', $r[0]['username'], $r[0]['name']) . EOL);
} }
@ -227,13 +225,13 @@ function dfrn_poll_init(App $a)
function dfrn_poll_post(App $a) function dfrn_poll_post(App $a)
{ {
$dfrn_id = defaults($_POST, 'dfrn_id' , ''); $dfrn_id = $_POST['dfrn_id'] ?? '';
$challenge = defaults($_POST, 'challenge', ''); $challenge = $_POST['challenge'] ?? '';
$url = defaults($_POST, 'url' , ''); $url = $_POST['url'] ?? '';
$sec = defaults($_POST, 'sec' , ''); $sec = $_POST['sec'] ?? '';
$ptype = defaults($_POST, 'type' , ''); $ptype = $_POST['type'] ?? '';
$perm = defaults($_POST, 'perm' , 'r'); $perm = ($_POST['perm'] ?? '') ?: 'r';
$dfrn_version = !empty($_POST['dfrn_version']) ? (float) $_POST['dfrn_version'] : 2.0; $dfrn_version = floatval(($_GET['dfrn_version'] ?? 0.0) ?: 2.0);
if ($ptype === 'profile-check') { if ($ptype === 'profile-check') {
if (strlen($challenge) && strlen($sec)) { if (strlen($challenge) && strlen($sec)) {
@ -393,12 +391,12 @@ function dfrn_poll_post(App $a)
function dfrn_poll_content(App $a) function dfrn_poll_content(App $a)
{ {
$dfrn_id = defaults($_GET, 'dfrn_id' , ''); $dfrn_id = $_GET['dfrn_id'] ?? '';
$type = defaults($_GET, 'type' , 'data'); $type = ($_GET['type'] ?? '') ?: 'data';
$last_update = defaults($_GET, 'last_update' , ''); $last_update = $_GET['last_update'] ?? '';
$destination_url = defaults($_GET, 'destination_url', ''); $destination_url = $_GET['destination_url'] ?? '';
$sec = defaults($_GET, 'sec' , ''); $sec = $_GET['sec'] ?? '';
$dfrn_version = !empty($_GET['dfrn_version']) ? (float) $_GET['dfrn_version'] : 2.0; $dfrn_version = floatval(($_GET['dfrn_version'] ?? 0.0) ?: 2.0);
$quiet = !empty($_GET['quiet']); $quiet = !empty($_GET['quiet']);
$direction = -1; $direction = -1;
@ -517,15 +515,13 @@ function dfrn_poll_content(App $a)
if (((int) $xml->status == 0) && ($xml->challenge == $hash) && ($xml->sec == $sec)) { if (((int) $xml->status == 0) && ($xml->challenge == $hash) && ($xml->sec == $sec)) {
$_SESSION['authenticated'] = 1; $_SESSION['authenticated'] = 1;
if (empty($_SESSION['remote'])) {
$_SESSION['remote'] = [];
}
$_SESSION['remote'][] = ['cid' => $r[0]['id'], 'uid' => $r[0]['uid'], 'url' => $r[0]['url']];
$_SESSION['visitor_id'] = $r[0]['id']; $_SESSION['visitor_id'] = $r[0]['id'];
$_SESSION['visitor_home'] = $r[0]['url']; $_SESSION['visitor_home'] = $r[0]['url'];
$_SESSION['visitor_visiting'] = $r[0]['uid']; $_SESSION['visitor_visiting'] = $r[0]['uid'];
$_SESSION['my_url'] = $r[0]['url']; $_SESSION['my_url'] = $r[0]['url'];
Session::setVisitorsContacts();
if (!$quiet) { if (!$quiet) {
info(L10n::t('%1$s welcomes %2$s', $r[0]['username'], $r[0]['name']) . EOL); info(L10n::t('%1$s welcomes %2$s', $r[0]['username'], $r[0]['name']) . EOL);
} }

View file

@ -19,6 +19,7 @@ use Friendica\Core\Logger;
use Friendica\Core\Protocol; use Friendica\Core\Protocol;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Model\Group; use Friendica\Model\Group;
@ -79,7 +80,7 @@ function dfrn_request_post(App $a)
if (local_user() && ($a->user['nickname'] == $a->argv[1]) && !empty($_POST['dfrn_url'])) { if (local_user() && ($a->user['nickname'] == $a->argv[1]) && !empty($_POST['dfrn_url'])) {
$dfrn_url = Strings::escapeTags(trim($_POST['dfrn_url'])); $dfrn_url = Strings::escapeTags(trim($_POST['dfrn_url']));
$aes_allow = !empty($_POST['aes_allow']); $aes_allow = !empty($_POST['aes_allow']);
$confirm_key = defaults($_POST, 'confirm_key', ""); $confirm_key = $_POST['confirm_key'] ?? '';
$hidden = (!empty($_POST['hidden-contact']) ? intval($_POST['hidden-contact']) : 0); $hidden = (!empty($_POST['hidden-contact']) ? intval($_POST['hidden-contact']) : 0);
$contact_record = null; $contact_record = null;
$blocked = 1; $blocked = 1;
@ -168,7 +169,7 @@ function dfrn_request_post(App $a)
$r = q("SELECT `id`, `network` FROM `contact` WHERE `uid` = %d AND `url` = '%s' AND `site-pubkey` = '%s' LIMIT 1", $r = q("SELECT `id`, `network` FROM `contact` WHERE `uid` = %d AND `url` = '%s' AND `site-pubkey` = '%s' LIMIT 1",
intval(local_user()), intval(local_user()),
DBA::escape($dfrn_url), DBA::escape($dfrn_url),
defaults($parms, 'key', '') // Potentially missing $parms['key'] ?? '' // Potentially missing
); );
if (DBA::isResult($r)) { if (DBA::isResult($r)) {
Group::addMember(User::getDefaultGroup(local_user(), $r[0]["network"]), $r[0]['id']); Group::addMember(User::getDefaultGroup(local_user(), $r[0]["network"]), $r[0]['id']);
@ -422,7 +423,7 @@ function dfrn_request_post(App $a)
intval($uid), intval($uid),
intval($contact_record['id']), intval($contact_record['id']),
intval(!empty($_POST['knowyou'])), intval(!empty($_POST['knowyou'])),
DBA::escape(Strings::escapeTags(trim(defaults($_POST, 'dfrn-request-message', '')))), DBA::escape(Strings::escapeTags(trim($_POST['dfrn-request-message'] ?? ''))),
DBA::escape($hash), DBA::escape($hash),
DBA::escape(DateTimeFormat::utcNow()) DBA::escape(DateTimeFormat::utcNow())
); );
@ -498,7 +499,7 @@ function dfrn_request_content(App $a)
$dfrn_url = Strings::escapeTags(trim(hex2bin($_GET['dfrn_url']))); $dfrn_url = Strings::escapeTags(trim(hex2bin($_GET['dfrn_url'])));
$aes_allow = !empty($_GET['aes_allow']); $aes_allow = !empty($_GET['aes_allow']);
$confirm_key = defaults($_GET, 'confirm_key', ""); $confirm_key = $_GET['confirm_key'] ?? '';
// Checking fastlane for validity // Checking fastlane for validity
if (!empty($_SESSION['fastlane']) && (Strings::normaliseLink($_SESSION["fastlane"]) == Strings::normaliseLink($dfrn_url))) { if (!empty($_SESSION['fastlane']) && (Strings::normaliseLink($_SESSION["fastlane"]) == Strings::normaliseLink($dfrn_url))) {
@ -592,7 +593,7 @@ function dfrn_request_content(App $a)
exit(); exit();
} else { } else {
// Normal web request. Display our user's introduction form. // Normal web request. Display our user's introduction form.
if ((Config::get('system', 'block_public')) && (!local_user()) && (!remote_user())) { if (Config::get('system', 'block_public') && !Session::isAuthenticated()) {
if (!Config::get('system', 'local_block')) { if (!Config::get('system', 'local_block')) {
notice(L10n::t('Public access denied.') . EOL); notice(L10n::t('Public access denied.') . EOL);
return; return;

View file

@ -14,6 +14,7 @@ use Friendica\Core\Logger;
use Friendica\Core\Protocol; use Friendica\Core\Protocol;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Model\Group; use Friendica\Model\Group;
@ -31,7 +32,7 @@ function display_init(App $a)
Objects::rawContent(); Objects::rawContent();
} }
if (Config::get('system', 'block_public') && !local_user() && !remote_user()) { if (Config::get('system', 'block_public') && !Session::isAuthenticated()) {
return; return;
} }
@ -52,9 +53,11 @@ function display_init(App $a)
if (DBA::isResult($item)) { if (DBA::isResult($item)) {
$nick = $a->user["nickname"]; $nick = $a->user["nickname"];
} }
}
// Is this item private but could be visible to the remove visitor? // Is this item private but could be visible to the remove visitor?
} elseif (remote_user()) { if (!DBA::isResult($item) && remote_user()) {
$item = Item::selectFirst($fields, ['guid' => $a->argv[1], 'private' => 1]); $item = Item::selectFirst($fields, ['guid' => $a->argv[1], 'private' => 1, 'origin' => true]);
if (DBA::isResult($item)) { if (DBA::isResult($item)) {
if (!Contact::isFollower(remote_user(), $item['uid'])) { if (!Contact::isFollower(remote_user(), $item['uid'])) {
$item = null; $item = null;
@ -84,10 +87,6 @@ function display_init(App $a)
displayShowFeed($item['id'], $a->argc > 3 && $a->argv[3] == 'conversation.atom'); displayShowFeed($item['id'], $a->argc > 3 && $a->argv[3] == 'conversation.atom');
} }
if ($a->argc >= 3 && $nick == 'feed-item') {
displayShowFeed($item['id'], $a->argc > 3 && $a->argv[3] == 'conversation.atom');
}
if (!empty($_SERVER['HTTP_ACCEPT']) && strstr($_SERVER['HTTP_ACCEPT'], 'application/atom+xml')) { if (!empty($_SERVER['HTTP_ACCEPT']) && strstr($_SERVER['HTTP_ACCEPT'], 'application/atom+xml')) {
Logger::log('Directly serving XML for id '.$item["id"], Logger::DEBUG); Logger::log('Directly serving XML for id '.$item["id"], Logger::DEBUG);
displayShowFeed($item["id"], false); displayShowFeed($item["id"], false);
@ -102,7 +101,7 @@ function display_init(App $a)
if (strstr(Strings::normaliseLink($profiledata["url"]), Strings::normaliseLink(System::baseUrl()))) { if (strstr(Strings::normaliseLink($profiledata["url"]), Strings::normaliseLink(System::baseUrl()))) {
$nickname = str_replace(Strings::normaliseLink(System::baseUrl())."/profile/", "", Strings::normaliseLink($profiledata["url"])); $nickname = str_replace(Strings::normaliseLink(System::baseUrl())."/profile/", "", Strings::normaliseLink($profiledata["url"]));
if (($nickname != $a->user["nickname"])) { if ($nickname != $a->user["nickname"]) {
$profile = DBA::fetchFirst("SELECT `profile`.`uid` AS `profile_uid`, `profile`.* , `contact`.`avatar-date` AS picdate, `user`.* FROM `profile` $profile = DBA::fetchFirst("SELECT `profile`.`uid` AS `profile_uid`, `profile`.* , `contact`.`avatar-date` AS picdate, `user`.* FROM `profile`
INNER JOIN `contact` on `contact`.`uid` = `profile`.`uid` INNER JOIN `user` ON `profile`.`uid` = `user`.`uid` INNER JOIN `contact` on `contact`.`uid` = `profile`.`uid` INNER JOIN `user` ON `profile`.`uid` = `user`.`uid`
WHERE `user`.`nickname` = ? AND `profile`.`is-default` AND `contact`.`self` LIMIT 1", WHERE `user`.`nickname` = ? AND `profile`.`is-default` AND `contact`.`self` LIMIT 1",
@ -188,14 +187,16 @@ function display_fetchauthor($a, $item)
$profiledata = Contact::getDetailsByURL($profiledata["url"], local_user(), $profiledata); $profiledata = Contact::getDetailsByURL($profiledata["url"], local_user(), $profiledata);
if (!empty($profiledata["photo"])) {
$profiledata["photo"] = System::removedBaseUrl($profiledata["photo"]); $profiledata["photo"] = System::removedBaseUrl($profiledata["photo"]);
}
return $profiledata; return $profiledata;
} }
function display_content(App $a, $update = false, $update_uid = 0) function display_content(App $a, $update = false, $update_uid = 0)
{ {
if (Config::get('system','block_public') && !local_user() && !remote_user()) { if (Config::get('system','block_public') && !Session::isAuthenticated()) {
throw new HTTPException\ForbiddenException(L10n::t('Public access denied.')); throw new HTTPException\ForbiddenException(L10n::t('Public access denied.'));
} }
@ -227,8 +228,10 @@ function display_content(App $a, $update = false, $update_uid = 0)
$item_parent = $item["parent"]; $item_parent = $item["parent"];
$item_parent_uri = $item['parent-uri']; $item_parent_uri = $item['parent-uri'];
} }
} elseif (remote_user()) { }
$item = Item::selectFirst($fields, ['guid' => $a->argv[1], 'private' => 1]);
if (($item_parent == 0) && remote_user()) {
$item = Item::selectFirst($fields, ['guid' => $a->argv[1], 'private' => 1, 'origin' => true]);
if (DBA::isResult($item) && Contact::isFollower(remote_user(), $item['uid'])) { if (DBA::isResult($item) && Contact::isFollower(remote_user(), $item['uid'])) {
$item_id = $item["id"]; $item_id = $item["id"];
$item_parent = $item["parent"]; $item_parent = $item["parent"];
@ -267,34 +270,26 @@ function display_content(App $a, $update = false, $update_uid = 0)
['$alternate' => $alternate, ['$alternate' => $alternate,
'$conversation' => $conversation]); '$conversation' => $conversation]);
$groups = [];
$remote_cid = null;
$is_remote_contact = false; $is_remote_contact = false;
$item_uid = local_user(); $item_uid = local_user();
if (isset($item_parent_uri)) { if (isset($item_parent_uri)) {
$parent = Item::selectFirst(['uid'], ['uri' => $item_parent_uri, 'wall' => true]); $parent = Item::selectFirst(['uid'], ['uri' => $item_parent_uri, 'wall' => true]);
if (DBA::isResult($parent)) { if (DBA::isResult($parent)) {
$a->profile['uid'] = defaults($a->profile, 'uid', $parent['uid']); $a->profile['uid'] = ($a->profile['uid'] ?? 0) ?: $parent['uid'];
$a->profile['profile_uid'] = defaults($a->profile, 'profile_uid', $parent['uid']); $a->profile['profile_uid'] = ($a->profile['profile_uid'] ?? 0) ?: $parent['uid'];
$is_remote_contact = Contact::isFollower(remote_user(), $a->profile['profile_uid']); $is_remote_contact = Session::getRemoteContactID($a->profile['profile_uid']);
if ($is_remote_contact) { if ($is_remote_contact) {
$cdata = Contact::getPublicAndUserContacID(remote_user(), $a->profile['profile_uid']);
if (!empty($cdata['user'])) {
$groups = Group::getIdsByContactId($cdata['user']);
$remote_cid = $cdata['user'];
$item_uid = $parent['uid']; $item_uid = $parent['uid'];
} }
} }
} }
}
$page_contact = DBA::selectFirst('contact', [], ['self' => true, 'uid' => $a->profile['uid']]); $page_contact = DBA::selectFirst('contact', [], ['self' => true, 'uid' => $a->profile['uid']]);
if (DBA::isResult($page_contact)) { if (DBA::isResult($page_contact)) {
$a->page_contact = $page_contact; $a->page_contact = $page_contact;
} }
$is_owner = (local_user() && (in_array($a->profile['profile_uid'], [local_user(), 0])) ? true : false); $is_owner = (local_user() && (in_array($a->profile['profile_uid'], [local_user(), 0])) ? true : false);
if (!empty($a->profile['hidewall']) && !$is_owner && !$is_remote_contact) { if (!empty($a->profile['hidewall']) && !$is_owner && !$is_remote_contact) {
@ -316,7 +311,7 @@ function display_content(App $a, $update = false, $update_uid = 0)
]; ];
$o .= status_editor($a, $x, 0, true); $o .= status_editor($a, $x, 0, true);
} }
$sql_extra = Item::getPermissionsSQLByUserId($a->profile['profile_uid'], $is_remote_contact, $groups, $remote_cid); $sql_extra = Item::getPermissionsSQLByUserId($a->profile['profile_uid']);
if (local_user() && (local_user() == $a->profile['profile_uid'])) { if (local_user() && (local_user() == $a->profile['profile_uid'])) {
$condition = ['parent-uri' => $item_parent_uri, 'uid' => local_user(), 'unseen' => true]; $condition = ['parent-uri' => $item_parent_uri, 'uid' => local_user(), 'unseen' => true];
@ -330,8 +325,8 @@ function display_content(App $a, $update = false, $update_uid = 0)
} }
$condition = ["`id` = ? AND `item`.`uid` IN (0, ?) " . $sql_extra, $item_id, $item_uid]; $condition = ["`id` = ? AND `item`.`uid` IN (0, ?) " . $sql_extra, $item_id, $item_uid];
$fields = ['parent-uri', 'body', 'title', 'author-name', 'author-avatar', 'plink']; $fields = ['parent-uri', 'body', 'title', 'author-name', 'author-avatar', 'plink', 'author-id', 'owner-id', 'contact-id'];
$item = Item::selectFirstForUser(local_user(), $fields, $condition); $item = Item::selectFirstForUser($a->profile['profile_uid'], $fields, $condition);
if (!DBA::isResult($item)) { if (!DBA::isResult($item)) {
throw new HTTPException\NotFoundException(L10n::t('The requested item doesn\'t exist or has been deleted.')); throw new HTTPException\NotFoundException(L10n::t('The requested item doesn\'t exist or has been deleted.'));
@ -370,7 +365,10 @@ function display_content(App $a, $update = false, $update_uid = 0)
$title = htmlspecialchars($title, ENT_COMPAT, 'UTF-8', true); // allow double encoding here $title = htmlspecialchars($title, ENT_COMPAT, 'UTF-8', true); // allow double encoding here
$author_name = htmlspecialchars($author_name, ENT_COMPAT, 'UTF-8', true); // allow double encoding here $author_name = htmlspecialchars($author_name, ENT_COMPAT, 'UTF-8', true); // allow double encoding here
//<meta name="keywords" content=""> if (DBA::exists('contact', ['unsearchable' => true, 'id' => [$item['contact-id'], $item['author-id'], $item['owner-id']]])) {
$a->page['htmlhead'] .= '<meta content="noindex, noarchive" name="robots" />' . "\n";
}
$a->page['htmlhead'] .= '<meta name="author" content="'.$author_name.'" />'."\n"; $a->page['htmlhead'] .= '<meta name="author" content="'.$author_name.'" />'."\n";
$a->page['htmlhead'] .= '<meta name="title" content="'.$title.'" />'."\n"; $a->page['htmlhead'] .= '<meta name="title" content="'.$title.'" />'."\n";
$a->page['htmlhead'] .= '<meta name="fulltitle" content="'.$title.'" />'."\n"; $a->page['htmlhead'] .= '<meta name="fulltitle" content="'.$title.'" />'."\n";

View file

@ -59,11 +59,11 @@ function events_post(App $a)
$cid = !empty($_POST['cid']) ? intval($_POST['cid']) : 0; $cid = !empty($_POST['cid']) ? intval($_POST['cid']) : 0;
$uid = local_user(); $uid = local_user();
$start_text = Strings::escapeHtml(defaults($_REQUEST, 'start_text', '')); $start_text = Strings::escapeHtml($_REQUEST['start_text'] ?? '');
$finish_text = Strings::escapeHtml(defaults($_REQUEST, 'finish_text', '')); $finish_text = Strings::escapeHtml($_REQUEST['finish_text'] ?? '');
$adjust = intval(defaults($_POST, 'adjust', 0)); $adjust = intval($_POST['adjust'] ?? 0);
$nofinish = intval(defaults($_POST, 'nofinish', 0)); $nofinish = intval($_POST['nofinish'] ?? 0);
// The default setting for the `private` field in event_store() is false, so mirror that // The default setting for the `private` field in event_store() is false, so mirror that
$private_event = false; $private_event = false;
@ -96,9 +96,9 @@ function events_post(App $a)
// and we'll waste a bunch of time responding to it. Time that // and we'll waste a bunch of time responding to it. Time that
// could've been spent doing something else. // could've been spent doing something else.
$summary = trim(defaults($_POST, 'summary' , '')); $summary = trim($_POST['summary'] ?? '');
$desc = trim(defaults($_POST, 'desc' , '')); $desc = trim($_POST['desc'] ?? '');
$location = trim(defaults($_POST, 'location', '')); $location = trim($_POST['location'] ?? '');
$type = 'event'; $type = 'event';
$params = [ $params = [
@ -132,7 +132,7 @@ function events_post(App $a)
$a->internalRedirect($onerror_path); $a->internalRedirect($onerror_path);
} }
$share = intval(defaults($_POST, 'share', 0)); $share = intval($_POST['share'] ?? 0);
$c = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `self` LIMIT 1", $c = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `self` LIMIT 1",
intval(local_user()) intval(local_user())
@ -146,10 +146,10 @@ function events_post(App $a)
if ($share) { if ($share) {
$str_group_allow = perms2str(defaults($_POST, 'group_allow' , '')); $str_group_allow = perms2str($_POST['group_allow'] ?? '');
$str_contact_allow = perms2str(defaults($_POST, 'contact_allow', '')); $str_contact_allow = perms2str($_POST['contact_allow'] ?? '');
$str_group_deny = perms2str(defaults($_POST, 'group_deny' , '')); $str_group_deny = perms2str($_POST['group_deny'] ?? '');
$str_contact_deny = perms2str(defaults($_POST, 'contact_deny' , '')); $str_contact_deny = perms2str($_POST['contact_deny'] ?? '');
// Undo the pseudo-contact of self, since there are real contacts now // Undo the pseudo-contact of self, since there are real contacts now
if (strpos($str_contact_allow, '<' . $self . '>') !== false) { if (strpos($str_contact_allow, '<' . $self . '>') !== false) {
@ -321,7 +321,7 @@ function events_content(App $a)
// put the event parametes in an array so we can better transmit them // put the event parametes in an array so we can better transmit them
$event_params = [ $event_params = [
'event_id' => intval(defaults($_GET, 'id', 0)), 'event_id' => intval($_GET['id'] ?? 0),
'start' => $start, 'start' => $start,
'finish' => $finish, 'finish' => $finish,
'adjust_start' => $adjust_start, 'adjust_start' => $adjust_start,

View file

@ -29,7 +29,7 @@ function fbrowser_content(App $a)
} }
// Needed to match the correct template in a module that uses a different theme than the user/site/default // Needed to match the correct template in a module that uses a different theme than the user/site/default
$theme = Strings::sanitizeFilePathItem(defaults($_GET, 'theme', null)); $theme = Strings::sanitizeFilePathItem($_GET['theme'] ?? null);
if ($theme && is_file("view/theme/$theme/config.php")) { if ($theme && is_file("view/theme/$theme/config.php")) {
$a->setCurrentTheme($theme); $a->setCurrentTheme($theme);
} }

View file

@ -62,7 +62,7 @@ function follow_content(App $a)
$uid = local_user(); $uid = local_user();
// Issue 4815: Silently removing a prefixing @ // Issue 4815: Silently removing a prefixing @
$url = ltrim(Strings::escapeTags(trim(defaults($_REQUEST, 'url', ''))), '@!'); $url = ltrim(Strings::escapeTags(trim($_REQUEST['url'] ?? '')), '@!');
// Issue 6874: Allow remote following from Peertube // Issue 6874: Allow remote following from Peertube
if (strpos($url, 'acct:') === 0) { if (strpos($url, 'acct:') === 0) {

View file

@ -45,7 +45,7 @@ function fsuggest_post(App $a)
return; return;
} }
$note = Strings::escapeHtml(trim(defaults($_POST, 'note', ''))); $note = Strings::escapeHtml(trim($_POST['note'] ?? ''));
$fields = ['uid' => local_user(),'cid' => $contact_id, 'name' => $contact['name'], $fields = ['uid' => local_user(),'cid' => $contact_id, 'name' => $contact['name'],
'url' => $contact['url'], 'request' => $contact['request'], 'url' => $contact['url'], 'request' => $contact['request'],

View file

@ -6,13 +6,14 @@ use Friendica\App;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Model\Profile; use Friendica\Model\Profile;
use Friendica\Model\User; use Friendica\Model\User;
function hcard_init(App $a) function hcard_init(App $a)
{ {
$blocked = Config::get('system', 'block_public') && !local_user() && !remote_user(); $blocked = Config::get('system', 'block_public') && !Session::isAuthenticated();
if ($a->argc > 1) { if ($a->argc > 1) {
$which = $a->argv[1]; $which = $a->argv[1];
@ -40,7 +41,7 @@ function hcard_init(App $a)
} }
if (!$blocked) { if (!$blocked) {
$keywords = defaults($a->profile, 'pub_keywords', ''); $keywords = $a->profile['pub_keywords'] ?? '';
$keywords = str_replace([',',' ',',,'], [' ',',',','], $keywords); $keywords = str_replace([',',' ',',,'], [' ',',',','], $keywords);
if (strlen($keywords)) { if (strlen($keywords)) {
$a->page['htmlhead'] .= '<meta name="keywords" content="' . $keywords . '" />' . "\r\n"; $a->page['htmlhead'] .= '<meta name="keywords" content="' . $keywords . '" />' . "\r\n";

View file

@ -26,8 +26,8 @@ function hovercard_init(App $a)
function hovercard_content() function hovercard_content()
{ {
$profileurl = defaults($_REQUEST, 'profileurl', ''); $profileurl = $_REQUEST['profileurl'] ?? '';
$datatype = defaults($_REQUEST, 'datatype' , 'json'); $datatype = ($_REQUEST['datatype'] ?? '') ?: 'json';
// Get out if the system doesn't have public access allowed // Get out if the system doesn't have public access allowed
if (intval(Config::get('system', 'block_public'))) { if (intval(Config::get('system', 'block_public'))) {
@ -50,7 +50,7 @@ function hovercard_content()
if (strpos($profileurl, 'redir/') === 0) { if (strpos($profileurl, 'redir/') === 0) {
$cid = intval(substr($profileurl, 6)); $cid = intval(substr($profileurl, 6));
$remote_contact = DBA::selectFirst('contact', ['nurl'], ['id' => $cid]); $remote_contact = DBA::selectFirst('contact', ['nurl'], ['id' => $cid]);
$profileurl = defaults($remote_contact, 'nurl', ''); $profileurl = $remote_contact['nurl'] ?? '';
} }
$contact = []; $contact = [];
@ -97,7 +97,7 @@ function hovercard_content()
$profile = [ $profile = [
'name' => $contact['name'], 'name' => $contact['name'],
'nick' => $contact['nick'], 'nick' => $contact['nick'],
'addr' => defaults($contact, 'addr', $contact['url']), 'addr' => ($contact['addr'] ?? '') ?: $contact['url'],
'thumb' => ProxyUtils::proxifyUrl($contact['thumb'], false, ProxyUtils::SIZE_THUMB), 'thumb' => ProxyUtils::proxifyUrl($contact['thumb'], false, ProxyUtils::SIZE_THUMB),
'url' => Contact::magicLink($contact['url']), 'url' => Contact::magicLink($contact['url']),
'nurl' => $contact['nurl'], // We additionally store the nurl as identifier 'nurl' => $contact['nurl'], // We additionally store the nurl as identifier

View file

@ -33,7 +33,7 @@ function ignored_init(App $a)
} }
// See if we've been passed a return path to redirect to // See if we've been passed a return path to redirect to
$return_path = defaults($_REQUEST, 'return', ''); $return_path = $_REQUEST['return'] ?? '';
if ($return_path) { if ($return_path) {
$rand = '_=' . time(); $rand = '_=' . time();
if (strpos($return_path, '?')) { if (strpos($return_path, '?')) {

View file

@ -25,6 +25,7 @@ use Friendica\Core\L10n;
use Friendica\Core\Logger; use Friendica\Core\Logger;
use Friendica\Core\Protocol; use Friendica\Core\Protocol;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Core\Worker; use Friendica\Core\Worker;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Model\Attach; use Friendica\Model\Attach;
@ -42,10 +43,10 @@ use Friendica\Util\Security;
use Friendica\Util\Strings; use Friendica\Util\Strings;
use Friendica\Worker\Delivery; use Friendica\Worker\Delivery;
require_once 'include/items.php'; require_once __DIR__ . '/../include/items.php';
function item_post(App $a) { function item_post(App $a) {
if (!local_user() && !remote_user()) { if (!Session::isAuthenticated()) {
return 0; return 0;
} }
@ -63,12 +64,12 @@ function item_post(App $a) {
Logger::log('postvars ' . print_r($_REQUEST, true), Logger::DATA); Logger::log('postvars ' . print_r($_REQUEST, true), Logger::DATA);
$api_source = defaults($_REQUEST, 'api_source', false); $api_source = $_REQUEST['api_source'] ?? false;
$message_id = ((!empty($_REQUEST['message_id']) && $api_source) ? strip_tags($_REQUEST['message_id']) : ''); $message_id = ((!empty($_REQUEST['message_id']) && $api_source) ? strip_tags($_REQUEST['message_id']) : '');
$return_path = defaults($_REQUEST, 'return', ''); $return_path = $_REQUEST['return'] ?? '';
$preview = intval(defaults($_REQUEST, 'preview', 0)); $preview = intval($_REQUEST['preview'] ?? 0);
/* /*
* Check for doubly-submitted posts, and reject duplicates * Check for doubly-submitted posts, and reject duplicates
@ -85,8 +86,8 @@ function item_post(App $a) {
} }
// Is this a reply to something? // Is this a reply to something?
$toplevel_item_id = intval(defaults($_REQUEST, 'parent', 0)); $toplevel_item_id = intval($_REQUEST['parent'] ?? 0);
$thr_parent_uri = trim(defaults($_REQUEST, 'parent_uri', '')); $thr_parent_uri = trim($_REQUEST['parent_uri'] ?? '');
$thread_parent_id = 0; $thread_parent_id = 0;
$thread_parent_contact = null; $thread_parent_contact = null;
@ -97,8 +98,8 @@ function item_post(App $a) {
$parent_contact = null; $parent_contact = null;
$objecttype = null; $objecttype = null;
$profile_uid = defaults($_REQUEST, 'profile_uid', local_user()); $profile_uid = ($_REQUEST['profile_uid'] ?? 0) ?: local_user();
$posttype = defaults($_REQUEST, 'post_type', Item::PT_ARTICLE); $posttype = ($_REQUEST['post_type'] ?? '') ?: Item::PT_ARTICLE;
if ($toplevel_item_id || $thr_parent_uri) { if ($toplevel_item_id || $thr_parent_uri) {
if ($toplevel_item_id) { if ($toplevel_item_id) {
@ -137,10 +138,10 @@ function item_post(App $a) {
Logger::info('mod_item: item_post parent=' . $toplevel_item_id); Logger::info('mod_item: item_post parent=' . $toplevel_item_id);
} }
$post_id = intval(defaults($_REQUEST, 'post_id', 0)); $post_id = intval($_REQUEST['post_id'] ?? 0);
$app = strip_tags(defaults($_REQUEST, 'source', '')); $app = strip_tags($_REQUEST['source'] ?? '');
$extid = strip_tags(defaults($_REQUEST, 'extid', '')); $extid = strip_tags($_REQUEST['extid'] ?? '');
$object = defaults($_REQUEST, 'object', ''); $object = $_REQUEST['object'] ?? '';
// Don't use "defaults" here. It would turn 0 to 1 // Don't use "defaults" here. It would turn 0 to 1
if (!isset($_REQUEST['wall'])) { if (!isset($_REQUEST['wall'])) {
@ -193,20 +194,20 @@ function item_post(App $a) {
$categories = ''; $categories = '';
$postopts = ''; $postopts = '';
$emailcc = ''; $emailcc = '';
$body = defaults($_REQUEST, 'body', ''); $body = $_REQUEST['body'] ?? '';
$has_attachment = defaults($_REQUEST, 'has_attachment', 0); $has_attachment = $_REQUEST['has_attachment'] ?? 0;
// If we have a speparate attachment, we need to add it to the body. // If we have a speparate attachment, we need to add it to the body.
if (!empty($has_attachment)) { if (!empty($has_attachment)) {
$attachment_type = defaults($_REQUEST, 'attachment_type', ''); $attachment_type = $_REQUEST['attachment_type'] ?? '';
$attachment_title = defaults($_REQUEST, 'attachment_title', ''); $attachment_title = $_REQUEST['attachment_title'] ?? '';
$attachment_text = defaults($_REQUEST, 'attachment_text', ''); $attachment_text = $_REQUEST['attachment_text'] ?? '';
$attachment_url = hex2bin(defaults($_REQUEST, 'attachment_url', '')); $attachment_url = hex2bin($_REQUEST['attachment_url'] ?? '');
$attachment_img_src = hex2bin(defaults($_REQUEST, 'attachment_img_src', '')); $attachment_img_src = hex2bin($_REQUEST['attachment_img_src'] ?? '');
$attachment_img_width = defaults($_REQUEST, 'attachment_img_width', 0); $attachment_img_width = $_REQUEST['attachment_img_width'] ?? 0;
$attachment_img_height = defaults($_REQUEST, 'attachment_img_height', 0); $attachment_img_height = $_REQUEST['attachment_img_height'] ?? 0;
$attachment = [ $attachment = [
'type' => $attachment_type, 'type' => $attachment_type,
'title' => $attachment_title, 'title' => $attachment_title,
@ -228,6 +229,9 @@ function item_post(App $a) {
$body .= $att_bbcode; $body .= $att_bbcode;
} }
// Convert links with empty descriptions to links without an explicit description
$body = preg_replace('#\[url=([^\]]*?)\]\[/url\]#ism', '[url]$1[/url]', $body);
if (!empty($orig_post)) { if (!empty($orig_post)) {
$str_group_allow = $orig_post['allow_gid']; $str_group_allow = $orig_post['allow_gid'];
$str_contact_allow = $orig_post['allow_cid']; $str_contact_allow = $orig_post['allow_cid'];
@ -265,29 +269,25 @@ function item_post(App $a) {
$str_contact_deny = $user['deny_cid']; $str_contact_deny = $user['deny_cid'];
} else { } else {
// use the posted permissions // use the posted permissions
$str_group_allow = perms2str(defaults($_REQUEST, 'group_allow', '')); $str_group_allow = perms2str($_REQUEST['group_allow'] ?? '');
$str_contact_allow = perms2str(defaults($_REQUEST, 'contact_allow', '')); $str_contact_allow = perms2str($_REQUEST['contact_allow'] ?? '');
$str_group_deny = perms2str(defaults($_REQUEST, 'group_deny', '')); $str_group_deny = perms2str($_REQUEST['group_deny'] ?? '');
$str_contact_deny = perms2str(defaults($_REQUEST, 'contact_deny', '')); $str_contact_deny = perms2str($_REQUEST['contact_deny'] ?? '');
} }
$title = Strings::escapeTags(trim(defaults($_REQUEST, 'title' , ''))); $title = Strings::escapeTags(trim($_REQUEST['title'] ?? ''));
$location = Strings::escapeTags(trim(defaults($_REQUEST, 'location', ''))); $location = Strings::escapeTags(trim($_REQUEST['location'] ?? ''));
$coord = Strings::escapeTags(trim(defaults($_REQUEST, 'coord' , ''))); $coord = Strings::escapeTags(trim($_REQUEST['coord'] ?? ''));
$verb = Strings::escapeTags(trim(defaults($_REQUEST, 'verb' , ''))); $verb = Strings::escapeTags(trim($_REQUEST['verb'] ?? ''));
$emailcc = Strings::escapeTags(trim(defaults($_REQUEST, 'emailcc' , ''))); $emailcc = Strings::escapeTags(trim($_REQUEST['emailcc'] ?? ''));
$body = Strings::escapeHtml(trim($body)); $body = Strings::escapeHtml(trim($body));
$network = Strings::escapeTags(trim(defaults($_REQUEST, 'network' , Protocol::DFRN))); $network = Strings::escapeTags(trim(($_REQUEST['network'] ?? '') ?: Protocol::DFRN));
$guid = System::createUUID(); $guid = System::createUUID();
$postopts = defaults($_REQUEST, 'postopts', ''); $postopts = $_REQUEST['postopts'] ?? '';
$private = ((strlen($str_group_allow) || strlen($str_contact_allow) || strlen($str_group_deny) || strlen($str_contact_deny)) ? 1 : 0); $private = ((strlen($str_group_allow) || strlen($str_contact_allow) || strlen($str_group_deny) || strlen($str_contact_deny)) ? 1 : 0);
if ($user['hidewall']) {
$private = 2;
}
// If this is a comment, set the permissions from the parent. // If this is a comment, set the permissions from the parent.
if ($toplevel_item) { if ($toplevel_item) {
@ -307,7 +307,7 @@ function item_post(App $a) {
$wall = $toplevel_item['wall']; $wall = $toplevel_item['wall'];
} }
$pubmail_enabled = defaults($_REQUEST, 'pubmail_enable', false) && !$private; $pubmail_enabled = ($_REQUEST['pubmail_enable'] ?? false) && !$private;
// if using the API, we won't see pubmail_enable - figure out if it should be set // if using the API, we won't see pubmail_enable - figure out if it should be set
if ($api_source && $profile_uid && $profile_uid == local_user() && !$private) { if ($api_source && $profile_uid && $profile_uid == local_user() && !$private) {
@ -335,7 +335,7 @@ function item_post(App $a) {
// save old and new categories, so we can determine what needs to be deleted from pconfig // save old and new categories, so we can determine what needs to be deleted from pconfig
$categories_old = $categories; $categories_old = $categories;
$categories = FileTag::listToFile(trim(defaults($_REQUEST, 'category', '')), 'category'); $categories = FileTag::listToFile(trim($_REQUEST['category'] ?? ''), 'category');
$categories_new = $categories; $categories_new = $categories;
if (!empty($filedas) && is_array($filedas)) { if (!empty($filedas) && is_array($filedas)) {
@ -352,18 +352,8 @@ function item_post(App $a) {
if (local_user() && ((local_user() == $profile_uid) || $allow_comment)) { if (local_user() && ((local_user() == $profile_uid) || $allow_comment)) {
$self = true; $self = true;
$author = DBA::selectFirst('contact', [], ['uid' => local_user(), 'self' => true]); $author = DBA::selectFirst('contact', [], ['uid' => local_user(), 'self' => true]);
} elseif (remote_user()) { } elseif (!empty(Session::getRemoteContactID($profile_uid))) {
if (!empty($_SESSION['remote']) && is_array($_SESSION['remote'])) { $author = DBA::selectFirst('contact', [], ['id' => Session::getRemoteContactID($profile_uid)]);
foreach ($_SESSION['remote'] as $v) {
if ($v['uid'] == $profile_uid) {
$contact_id = $v['cid'];
break;
}
}
}
if ($contact_id) {
$author = DBA::selectFirst('contact', [], ['id' => $contact_id]);
}
} }
if (DBA::isResult($author)) { if (DBA::isResult($author)) {
@ -874,7 +864,7 @@ function item_post_return($baseurl, $api_source, $return_path)
function item_content(App $a) function item_content(App $a)
{ {
if (!local_user() && !remote_user()) { if (!Session::isAuthenticated()) {
return; return;
} }
@ -1025,7 +1015,7 @@ function handle_tag(&$body, &$inform, &$str_tags, $profile_uid, $tag, $network =
$profile = $contact["url"]; $profile = $contact["url"];
$alias = $contact["alias"]; $alias = $contact["alias"];
$newname = defaults($contact, "name", $contact["nick"]); $newname = ($contact["name"] ?? '') ?: $contact["nick"];
} }
//if there is an url for this persons profile //if there is an url for this persons profile

View file

@ -1,4 +1,5 @@
<?php <?php
/** /**
* @file mod/lostpass.php * @file mod/lostpass.php
*/ */
@ -27,7 +28,7 @@ function lostpass_post(App $a)
$a->internalRedirect(); $a->internalRedirect();
} }
$pwdreset_token = Strings::getRandomName(12) . mt_rand(1000, 9999); $pwdreset_token = Strings::getRandomName(12) . random_int(1000, 9999);
$fields = [ $fields = [
'pwdreset' => $pwdreset_token, 'pwdreset' => $pwdreset_token,

View file

@ -1,188 +0,0 @@
<?php
/**
* @file mod/manage.php
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\L10n;
use Friendica\Core\Renderer;
use Friendica\Core\Session;
use Friendica\Database\DBA;
function manage_post(App $a) {
if (! local_user()) {
return;
}
$uid = local_user();
$orig_record = $a->user;
if(!empty($_SESSION['submanage'])) {
$r = q("select * from user where uid = %d limit 1",
intval($_SESSION['submanage'])
);
if (DBA::isResult($r)) {
$uid = intval($r[0]['uid']);
$orig_record = $r[0];
}
}
$r = q("SELECT * FROM `manage` WHERE `uid` = %d",
intval($uid)
);
$submanage = $r;
$identity = (!empty($_POST['identity']) ? intval($_POST['identity']) : 0);
if (!$identity) {
return;
}
$limited_id = 0;
$original_id = $uid;
if (DBA::isResult($submanage)) {
foreach ($submanage as $m) {
if ($identity == $m['mid']) {
$limited_id = $m['mid'];
break;
}
}
}
if ($limited_id) {
$r = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1",
intval($limited_id)
);
} else {
// Check if the target user is one of our children
$r = q("SELECT * FROM `user` WHERE `uid` = %d AND `parent-uid` = %d LIMIT 1",
intval($identity),
DBA::escape($orig_record['uid'])
);
// Check if the target user is one of our siblings
if (!DBA::isResult($r) && ($orig_record['parent-uid'] != 0)) {
$r = q("SELECT * FROM `user` WHERE `uid` = %d AND `parent-uid` = %d LIMIT 1",
intval($identity),
DBA::escape($orig_record['parent-uid'])
);
}
// Check if it's our parent
if (!DBA::isResult($r) && ($orig_record['parent-uid'] != 0) && ($orig_record['parent-uid'] == $identity)) {
$r = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1",
intval($identity)
);
}
// Finally check if it's out own user
if (!DBA::isResult($r) && ($orig_record['uid'] != 0) && ($orig_record['uid'] == $identity)) {
$r = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1",
intval($identity)
);
}
}
if (!DBA::isResult($r)) {
return;
}
unset($_SESSION['authenticated']);
unset($_SESSION['uid']);
unset($_SESSION['visitor_id']);
unset($_SESSION['administrator']);
unset($_SESSION['cid']);
unset($_SESSION['theme']);
unset($_SESSION['mobile-theme']);
unset($_SESSION['page_flags']);
unset($_SESSION['return_path']);
if (!empty($_SESSION['submanage'])) {
unset($_SESSION['submanage']);
}
if (!empty($_SESSION['sysmsg'])) {
unset($_SESSION['sysmsg']);
}
if (!empty($_SESSION['sysmsg_info'])) {
unset($_SESSION['sysmsg_info']);
}
Session::setAuthenticatedForUser($a, $r[0], true, true);
if ($limited_id) {
$_SESSION['submanage'] = $original_id;
}
$ret = [];
Hook::callAll('home_init',$ret);
$a->internalRedirect('profile/' . $a->user['nickname'] );
// NOTREACHED
}
function manage_content(App $a) {
if (! local_user()) {
notice(L10n::t('Permission denied.') . EOL);
return;
}
if (!empty($_GET['identity'])) {
$_POST['identity'] = $_GET['identity'];
manage_post($a);
return;
}
$identities = $a->identities;
//getting additinal information for each identity
foreach ($identities as $key=>$id) {
$thumb = q("SELECT `thumb` FROM `contact` WHERE `uid` = '%s' AND `self` = 1",
DBA::escape($id['uid'])
);
$identities[$key]['thumb'] = $thumb[0]['thumb'];
$identities[$key]['selected'] = ($id['nickname'] === $a->user['nickname']);
$notifications = 0;
$r = q("SELECT DISTINCT(`parent`) FROM `notify` WHERE `uid` = %d AND NOT `seen` AND NOT (`type` IN (%d, %d))",
intval($id['uid']), intval(NOTIFY_INTRO), intval(NOTIFY_MAIL));
if (DBA::isResult($r)) {
$notifications = sizeof($r);
}
$r = q("SELECT DISTINCT(`convid`) FROM `mail` WHERE `uid` = %d AND NOT `seen`",
intval($id['uid']));
if (DBA::isResult($r)) {
$notifications = $notifications + sizeof($r);
}
$r = q("SELECT COUNT(*) AS `introductions` FROM `intro` WHERE NOT `blocked` AND NOT `ignore` AND `uid` = %d",
intval($id['uid']));
if (DBA::isResult($r)) {
$notifications = $notifications + $r[0]["introductions"];
}
$identities[$key]['notifications'] = $notifications;
}
$o = Renderer::replaceMacros(Renderer::getMarkupTemplate('manage.tpl'), [
'$title' => L10n::t('Manage Identities and/or Pages'),
'$desc' => L10n::t('Toggle between different identities or community/group pages which share your account details or which you have been granted "manage" permissions'),
'$choose' => L10n::t('Select an identity to manage: '),
'$identities' => $identities,
'$submit' => L10n::t('Submit'),
]);
return $o;
}

View file

@ -66,7 +66,7 @@ function match_content(App $a)
$msearch = json_decode($msearch_json); $msearch = json_decode($msearch_json);
$start = defaults($_GET, 'start', 0); $start = $_GET['start'] ?? 0;
$entries = []; $entries = [];
$paginate = ''; $paginate = '';
@ -92,11 +92,11 @@ function match_content(App $a)
$entry = [ $entry = [
'url' => Contact::magicLink($profile->url), 'url' => Contact::magicLink($profile->url),
'itemurl' => defaults($contact_details, 'addr', $profile->url), 'itemurl' => $contact_details['addr'] ?? $profile->url,
'name' => $profile->name, 'name' => $profile->name,
'details' => defaults($contact_details, 'location', ''), 'details' => $contact_details['location'] ?? '',
'tags' => defaults($contact_details, 'keywords', ''), 'tags' => $contact_details['keywords'] ?? '',
'about' => defaults($contact_details, 'about', ''), 'about' => $contact_details['about'] ?? '',
'account_type' => Contact::getAccountType($contact_details), 'account_type' => Contact::getAccountType($contact_details),
'thumb' => ProxyUtils::proxifyUrl($profile->photo, false, ProxyUtils::SIZE_THUMB), 'thumb' => ProxyUtils::proxifyUrl($profile->photo, false, ProxyUtils::SIZE_THUMB),
'conntxt' => L10n::t('Connect'), 'conntxt' => L10n::t('Connect'),

View file

@ -249,8 +249,8 @@ function message_content(App $a)
'$prefill' => $prefill, '$prefill' => $prefill,
'$preid' => $preid, '$preid' => $preid,
'$subject' => L10n::t('Subject:'), '$subject' => L10n::t('Subject:'),
'$subjtxt' => defaults($_REQUEST, 'subject', ''), '$subjtxt' => $_REQUEST['subject'] ?? '',
'$text' => defaults($_REQUEST, 'body', ''), '$text' => $_REQUEST['body'] ?? '',
'$readonly' => '', '$readonly' => '',
'$yourmessage'=> L10n::t('Your message:'), '$yourmessage'=> L10n::t('Your message:'),
'$select' => $select, '$select' => $select,
@ -530,7 +530,7 @@ function render_messages(array $msg, $t)
'$id' => $rr['id'], '$id' => $rr['id'],
'$from_name' => $participants, '$from_name' => $participants,
'$from_url' => Contact::magicLink($rr['url']), '$from_url' => Contact::magicLink($rr['url']),
'$from_addr' => defaults($contact, 'addr', ''), '$from_addr' => $contact['addr'] ?? '',
'$sparkle' => ' sparkle', '$sparkle' => ' sparkle',
'$from_photo' => ProxyUtils::proxifyUrl($from_photo, false, ProxyUtils::SIZE_THUMB), '$from_photo' => ProxyUtils::proxifyUrl($from_photo, false, ProxyUtils::SIZE_THUMB),
'$subject' => $rr['title'], '$subject' => $rr['title'],

View file

@ -6,9 +6,9 @@ use Friendica\Database\DBA;
function msearch_post(App $a) function msearch_post(App $a)
{ {
$search = defaults($_POST, 's', ''); $search = $_POST['s'] ?? '';
$perpage = intval(defaults($_POST, 'n', 80)); $perpage = intval(($_POST['n'] ?? 0) ?: 80);
$page = intval(defaults($_POST, 'p', 1)); $page = intval(($_POST['p'] ?? 0) ?: 1);
$startrec = ($page - 1) * $perpage; $startrec = ($page - 1) * $perpage;
$total = 0; $total = 0;

View file

@ -40,22 +40,6 @@ function network_init(App $a)
Hook::add('head', __FILE__, 'network_infinite_scroll_head'); Hook::add('head', __FILE__, 'network_infinite_scroll_head');
$search = (!empty($_GET['search']) ? Strings::escapeHtml($_GET['search']) : '');
if (($search != '') && !empty($_GET['submit'])) {
$a->internalRedirect('search?search=' . urlencode($search));
}
if (!empty($_GET['save'])) {
$exists = DBA::exists('search', ['uid' => local_user(), 'term' => $search]);
if (!$exists) {
DBA::insert('search', ['uid' => local_user(), 'term' => $search]);
}
}
if (!empty($_GET['remove'])) {
DBA::delete('search', ['uid' => local_user(), 'term' => $search]);
}
$is_a_date_query = false; $is_a_date_query = false;
$group_id = (($a->argc > 1 && is_numeric($a->argv[1])) ? intval($a->argv[1]) : 0); $group_id = (($a->argc > 1 && is_numeric($a->argv[1])) ? intval($a->argv[1]) : 0);
@ -82,7 +66,7 @@ function network_init(App $a)
// fetch last used network view and redirect if needed // fetch last used network view and redirect if needed
if (!$is_a_date_query) { if (!$is_a_date_query) {
$sel_nets = defaults($_GET, 'nets', ''); $sel_nets = $_GET['nets'] ?? '';
$sel_tabs = network_query_get_sel_tab($a); $sel_tabs = network_query_get_sel_tab($a);
$sel_groups = network_query_get_sel_group($a); $sel_groups = network_query_get_sel_group($a);
$last_sel_tabs = PConfig::get(local_user(), 'network.view', 'tab.selected'); $last_sel_tabs = PConfig::get(local_user(), 'network.view', 'tab.selected');
@ -154,46 +138,9 @@ function network_init(App $a)
$a->page['aside'] .= Group::sidebarWidget('network/0', 'network', 'standard', $group_id); $a->page['aside'] .= Group::sidebarWidget('network/0', 'network', 'standard', $group_id);
$a->page['aside'] .= ForumManager::widget(local_user(), $cid); $a->page['aside'] .= ForumManager::widget(local_user(), $cid);
$a->page['aside'] .= Widget::postedByYear('network', local_user(), false); $a->page['aside'] .= Widget::postedByYear('network', local_user(), false);
$a->page['aside'] .= Widget::networks('network', defaults($_GET, 'nets', '') ); $a->page['aside'] .= Widget::networks('network', $_GET['nets'] ?? '');
$a->page['aside'] .= saved_searches($search); $a->page['aside'] .= Widget\SavedSearches::getHTML($a->query_string);
$a->page['aside'] .= Widget::fileAs('network', defaults($_GET, 'file', '') ); $a->page['aside'] .= Widget::fileAs('network', $_GET['file'] ?? '');
}
function saved_searches($search)
{
$srchurl = '/network?f='
. (!empty($_GET['cid']) ? '&cid=' . rawurlencode($_GET['cid']) : '')
. (!empty($_GET['star']) ? '&star=' . rawurlencode($_GET['star']) : '')
. (!empty($_GET['bmark']) ? '&bmark=' . rawurlencode($_GET['bmark']) : '')
. (!empty($_GET['conv']) ? '&conv=' . rawurlencode($_GET['conv']) : '')
. (!empty($_GET['nets']) ? '&nets=' . rawurlencode($_GET['nets']) : '')
. (!empty($_GET['cmin']) ? '&cmin=' . rawurlencode($_GET['cmin']) : '')
. (!empty($_GET['cmax']) ? '&cmax=' . rawurlencode($_GET['cmax']) : '')
. (!empty($_GET['file']) ? '&file=' . rawurlencode($_GET['file']) : '');
;
$terms = DBA::select('search', ['id', 'term'], ['uid' => local_user()]);
$saved = [];
while ($rr = DBA::fetch($terms)) {
$saved[] = [
'id' => $rr['id'],
'term' => $rr['term'],
'encodedterm' => urlencode($rr['term']),
'delete' => L10n::t('Remove term'),
'selected' => ($search == $rr['term']),
];
}
$tpl = Renderer::getMarkupTemplate('saved_searches_aside.tpl');
$o = Renderer::replaceMacros($tpl, [
'$title' => L10n::t('Saved Searches'),
'$add' => L10n::t('add'),
'$searchbox' => HTML::search($search, 'netsearch-box', $srchurl),
'$saved' => $saved,
]);
return $o;
} }
/** /**
@ -409,7 +356,7 @@ function networkFlatView(App $a, $update = 0)
$o = ''; $o = '';
$file = defaults($_GET, 'file', ''); $file = $_GET['file'] ?? '';
if (!$update && !$rawmode) { if (!$update && !$rawmode) {
$tabs = network_tabs($a); $tabs = network_tabs($a);
@ -532,12 +479,12 @@ function networkThreadedView(App $a, $update, $parent)
$o = ''; $o = '';
$cid = intval(defaults($_GET, 'cid' , 0)); $cid = intval($_GET['cid'] ?? 0);
$star = intval(defaults($_GET, 'star' , 0)); $star = intval($_GET['star'] ?? 0);
$bmark = intval(defaults($_GET, 'bmark', 0)); $bmark = intval($_GET['bmark'] ?? 0);
$conv = intval(defaults($_GET, 'conv' , 0)); $conv = intval($_GET['conv'] ?? 0);
$order = Strings::escapeTags(defaults($_GET, 'order', 'comment')); $order = Strings::escapeTags(($_GET['order'] ?? '') ?: 'comment');
$nets = defaults($_GET, 'nets' , ''); $nets = $_GET['nets'] ?? '';
$allowedCids = []; $allowedCids = [];
if ($cid) { if ($cid) {
@ -676,7 +623,7 @@ function networkThreadedView(App $a, $update, $parent)
$entries[0] = [ $entries[0] = [
'id' => 'network', 'id' => 'network',
'name' => $contact['name'], 'name' => $contact['name'],
'itemurl' => defaults($contact, 'addr', $contact['nurl']), 'itemurl' => ($contact['addr'] ?? '') ?: $contact['nurl'],
'thumb' => ProxyUtils::proxifyUrl($contact['thumb'], false, ProxyUtils::SIZE_THUMB), 'thumb' => ProxyUtils::proxifyUrl($contact['thumb'], false, ProxyUtils::SIZE_THUMB),
'details' => $contact['location'], 'details' => $contact['location'],
]; ];
@ -1066,7 +1013,7 @@ function network_infinite_scroll_head(App $a, &$htmlhead)
global $pager; global $pager;
if (PConfig::get(local_user(), 'system', 'infinite_scroll') if (PConfig::get(local_user(), 'system', 'infinite_scroll')
&& defaults($_GET, 'mode', '') != 'minimal' && ($_GET['mode'] ?? '') != 'minimal'
) { ) {
$tpl = Renderer::getMarkupTemplate('infinite_scroll_head.tpl'); $tpl = Renderer::getMarkupTemplate('infinite_scroll_head.tpl');
$htmlhead .= Renderer::replaceMacros($tpl, [ $htmlhead .= Renderer::replaceMacros($tpl, [

View file

@ -49,7 +49,7 @@ function noscrape_init(App $a)
exit; exit;
} }
$keywords = defaults($a->profile, 'pub_keywords', ''); $keywords = $a->profile['pub_keywords'] ?? '';
$keywords = str_replace(['#',',',' ',',,'], ['',' ',',',','], $keywords); $keywords = str_replace(['#',',',' ',',,'], ['',' ',',',','], $keywords);
$keywords = explode(',', $keywords); $keywords = explode(',', $keywords);

View file

@ -12,9 +12,11 @@ use Friendica\Core\L10n;
use Friendica\Core\NotificationsManager; use Friendica\Core\NotificationsManager;
use Friendica\Core\Protocol; use Friendica\Core\Protocol;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\Core\Logger;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Module\Login; use Friendica\Module\Login;
use Friendica\Model\Contact;
function notifications_post(App $a) function notifications_post(App $a)
{ {
@ -46,13 +48,18 @@ function notifications_post(App $a)
if ($_POST['submit'] == L10n::t('Discard')) { if ($_POST['submit'] == L10n::t('Discard')) {
DBA::delete('intro', ['id' => $intro_id]); DBA::delete('intro', ['id' => $intro_id]);
if (!$fid) { if (!$fid) {
// The check for blocked and pending is in case the friendship was already approved // When the contact entry had been created just for that intro, we want to get rid of it now
// and we just want to get rid of the now pointless notification
$condition = ['id' => $contact_id, 'uid' => local_user(), $condition = ['id' => $contact_id, 'uid' => local_user(),
'self' => false, 'blocked' => true, 'pending' => true]; 'self' => false, 'pending' => true, 'rel' => [0, Contact::FOLLOWER]];
DBA::delete('contact', $condition); $contact_pending = DBA::exists('contact', $condition);
// Remove the "pending" to stop the reappearing in any case
DBA::update('contact', ['pending' => false], ['id' => $contact_id]);
if ($contact_pending) {
Contact::remove($contact_id);
}
} }
$a->internalRedirect('notifications/intros'); $a->internalRedirect('notifications/intros');
} }
@ -71,8 +78,8 @@ function notifications_content(App $a)
return Login::form(); return Login::form();
} }
$page = defaults($_REQUEST, 'page', 1); $page = ($_REQUEST['page'] ?? 0) ?: 1;
$show = defaults($_REQUEST, 'show', 0); $show = $_REQUEST['show'] ?? 0;
Nav::setSelected('notifications'); Nav::setSelected('notifications');
@ -98,9 +105,14 @@ function notifications_content(App $a)
if ((($a->argc > 1) && ($a->argv[1] == 'intros')) || (($a->argc == 1))) { if ((($a->argc > 1) && ($a->argv[1] == 'intros')) || (($a->argc == 1))) {
Nav::setSelected('introductions'); Nav::setSelected('introductions');
$id = 0;
if (!empty($a->argv[2]) && intval($a->argv[2]) != 0) {
$id = (int)$a->argv[2];
}
$all = (($a->argc > 2) && ($a->argv[2] == 'all')); $all = (($a->argc > 2) && ($a->argv[2] == 'all'));
$notifs = $nm->introNotifs($all, $startrec, $perpage); $notifs = $nm->introNotifs($all, $startrec, $perpage, $id);
// Get the network notifications // Get the network notifications
} elseif (($a->argc > 1) && ($a->argv[1] == 'network')) { } elseif (($a->argc > 1) && ($a->argv[1] == 'network')) {
@ -146,7 +158,7 @@ function notifications_content(App $a)
]; ];
// Process the data for template creation // Process the data for template creation
if (defaults($notifs, 'ident', '') === 'introductions') { if (($notifs['ident'] ?? '') == 'introductions') {
$sugg = Renderer::getMarkupTemplate('suggestions.tpl'); $sugg = Renderer::getMarkupTemplate('suggestions.tpl');
$tpl = Renderer::getMarkupTemplate('intros.tpl'); $tpl = Renderer::getMarkupTemplate('intros.tpl');

View file

@ -13,9 +13,9 @@ use Friendica\Util\Strings;
function openid_content(App $a) { function openid_content(App $a) {
$noid = Config::get('system','no_openid'); if (Config::get('system','no_openid')) {
if($noid)
$a->internalRedirect(); $a->internalRedirect();
}
Logger::log('mod_openid ' . print_r($_REQUEST,true), Logger::DATA); Logger::log('mod_openid ' . print_r($_REQUEST,true), Logger::DATA);
@ -24,10 +24,9 @@ function openid_content(App $a) {
$openid = new LightOpenID($a->getHostName()); $openid = new LightOpenID($a->getHostName());
if ($openid->validate()) { if ($openid->validate()) {
$authid = $openid->identity;
$authid = $_REQUEST['openid_identity']; if (empty($authid)) {
if(! strlen($authid)) {
Logger::log(L10n::t('OpenID protocol error. No ID returned.') . EOL); Logger::log(L10n::t('OpenID protocol error. No ID returned.') . EOL);
$a->internalRedirect(); $a->internalRedirect();
} }
@ -37,22 +36,16 @@ function openid_content(App $a) {
// mod/settings.php in 8367cad so it might have left mixed // mod/settings.php in 8367cad so it might have left mixed
// records in the user table // records in the user table
// //
$r = q("SELECT * $condition = ['blocked' => false, 'account_expired' => false, 'account_removed' => false, 'verified' => true,
FROM `user` 'openid' => [$authid, Strings::normaliseOpenID($authid)]];
WHERE ( `openid` = '%s' OR `openid` = '%s' ) $user = DBA::selectFirst('user', [], $condition);
AND `blocked` = 0 AND `account_expired` = 0 if (DBA::isResult($user)) {
AND `account_removed` = 0 AND `verified` = 1
LIMIT 1",
DBA::escape($authid), DBA::escape(Strings::normaliseOpenID($authid))
);
if (DBA::isResult($r)) {
// successful OpenID login // successful OpenID login
unset($_SESSION['openid']); unset($_SESSION['openid']);
Session::setAuthenticatedForUser($a, $r[0],true,true); Session::setAuthenticatedForUser($a, $user, true, true);
// just in case there was no return url set // just in case there was no return url set
// and we fell through // and we fell through
@ -95,15 +88,13 @@ function openid_content(App $a) {
} }
if (!empty($nick)) { if (!empty($nick)) {
$args .= '&nickname=' . urlencode($nick); $args .= '&nickname=' . urlencode($nick);
} } elseif (!empty($first)) {
elseif (!empty($first)) {
$args .= '&nickname=' . urlencode($first); $args .= '&nickname=' . urlencode($first);
} }
if (!empty($photosq)) { if (!empty($photosq)) {
$args .= '&photo=' . urlencode($photosq); $args .= '&photo=' . urlencode($photosq);
} } elseif (!empty($photo)) {
elseif (!empty($photo)) {
$args .= '&photo=' . urlencode($photo); $args .= '&photo=' . urlencode($photo);
} }

View file

@ -15,6 +15,7 @@ use Friendica\Core\L10n;
use Friendica\Core\Logger; use Friendica\Core\Logger;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Model\Group; use Friendica\Model\Group;
@ -35,11 +36,7 @@ use Friendica\Util\XML;
function photos_init(App $a) { function photos_init(App $a) {
if ($a->argc > 1) { if (Config::get('system', 'block_public') && !Session::isAuthenticated()) {
DFRN::autoRedir($a, $a->argv[1]);
}
if (Config::get('system', 'block_public') && !local_user() && !remote_user()) {
return; return;
} }
@ -66,14 +63,14 @@ function photos_init(App $a) {
$vcard_widget = Renderer::replaceMacros($tpl, [ $vcard_widget = Renderer::replaceMacros($tpl, [
'$name' => $profile['name'], '$name' => $profile['name'],
'$photo' => $profile['photo'], '$photo' => $profile['photo'],
'$addr' => defaults($profile, 'addr', ''), '$addr' => $profile['addr'] ?? '',
'$account_type' => $account_type, '$account_type' => $account_type,
'$pdesc' => defaults($profile, 'pdesc', ''), '$pdesc' => $profile['pdesc'] ?? '',
]); ]);
$albums = Photo::getAlbums($a->data['user']['uid']); $albums = Photo::getAlbums($a->data['user']['uid']);
$albums_visible = ((intval($a->data['user']['hidewall']) && !local_user() && !remote_user()) ? false : true); $albums_visible = ((intval($a->data['user']['hidewall']) && !Session::isAuthenticated()) ? false : true);
// add various encodings to the array so we can just loop through and pick them out in a template // add various encodings to the array so we can just loop through and pick them out in a template
$ret = ['success' => false]; $ret = ['success' => false];
@ -88,7 +85,7 @@ function photos_init(App $a) {
$ret['albums'] = []; $ret['albums'] = [];
foreach ($albums as $k => $album) { foreach ($albums as $k => $album) {
//hide profile photos to others //hide profile photos to others
if (!$is_owner && !remote_user() && ($album['album'] == L10n::t('Profile Photos'))) if (!$is_owner && !Session::getRemoteContactID($a->profile_uid) && ($album['album'] == L10n::t('Profile Photos')))
continue; continue;
$entry = [ $entry = [
'text' => $album['album'], 'text' => $album['album'],
@ -154,25 +151,11 @@ function photos_post(App $a)
if (local_user() && (local_user() == $page_owner_uid)) { if (local_user() && (local_user() == $page_owner_uid)) {
$can_post = true; $can_post = true;
} elseif ($community_page && remote_user()) { } elseif ($community_page && !empty(Session::getRemoteContactID($page_owner_uid))) {
$contact_id = 0; $contact_id = Session::getRemoteContactID($page_owner_uid);
if (!empty($_SESSION['remote']) && is_array($_SESSION['remote'])) {
foreach ($_SESSION['remote'] as $v) {
if ($v['uid'] == $page_owner_uid) {
$contact_id = $v['cid'];
break;
}
}
}
if ($contact_id > 0) {
if (DBA::exists('contact', ['id' => $contact_id, 'uid' => $page_owner_uid, 'blocked' => false, 'pending' => false])) {
$can_post = true; $can_post = true;
$visitor = $contact_id; $visitor = $contact_id;
} }
}
}
if (!$can_post) { if (!$can_post) {
notice(L10n::t('Permission denied.') . EOL); notice(L10n::t('Permission denied.') . EOL);
@ -647,10 +630,10 @@ function photos_post(App $a)
$visible = 0; $visible = 0;
} }
$group_allow = defaults($_REQUEST, 'group_allow' , []); $group_allow = $_REQUEST['group_allow'] ?? [];
$contact_allow = defaults($_REQUEST, 'contact_allow', []); $contact_allow = $_REQUEST['contact_allow'] ?? [];
$group_deny = defaults($_REQUEST, 'group_deny' , []); $group_deny = $_REQUEST['group_deny'] ?? [];
$contact_deny = defaults($_REQUEST, 'contact_deny' , []); $contact_deny = $_REQUEST['contact_deny'] ?? [];
$str_group_allow = perms2str(is_array($group_allow) ? $group_allow : explode(',', $group_allow)); $str_group_allow = perms2str(is_array($group_allow) ? $group_allow : explode(',', $group_allow));
$str_contact_allow = perms2str(is_array($contact_allow) ? $contact_allow : explode(',', $contact_allow)); $str_contact_allow = perms2str(is_array($contact_allow) ? $contact_allow : explode(',', $contact_allow));
@ -683,7 +666,7 @@ function photos_post(App $a)
notice(L10n::t('Image exceeds size limit of %s', ini_get('upload_max_filesize')) . EOL); notice(L10n::t('Image exceeds size limit of %s', ini_get('upload_max_filesize')) . EOL);
break; break;
case UPLOAD_ERR_FORM_SIZE: case UPLOAD_ERR_FORM_SIZE:
notice(L10n::t('Image exceeds size limit of %s', Strings::formatBytes(defaults($_REQUEST, 'MAX_FILE_SIZE', 0))) . EOL); notice(L10n::t('Image exceeds size limit of %s', Strings::formatBytes($_REQUEST['MAX_FILE_SIZE'] ?? 0)) . EOL);
break; break;
case UPLOAD_ERR_PARTIAL: case UPLOAD_ERR_PARTIAL:
notice(L10n::t('Image upload didn\'t complete, please try again') . EOL); notice(L10n::t('Image upload didn\'t complete, please try again') . EOL);
@ -846,7 +829,7 @@ function photos_content(App $a)
// photos/name/image/xxxxx/edit // photos/name/image/xxxxx/edit
// photos/name/image/xxxxx/drop // photos/name/image/xxxxx/drop
if (Config::get('system', 'block_public') && !local_user() && !remote_user()) { if (Config::get('system', 'block_public') && !Session::isAuthenticated()) {
notice(L10n::t('Public access denied.') . EOL); notice(L10n::t('Public access denied.') . EOL);
return; return;
} }
@ -892,18 +875,8 @@ function photos_content(App $a)
if (local_user() && (local_user() == $owner_uid)) { if (local_user() && (local_user() == $owner_uid)) {
$can_post = true; $can_post = true;
} else { } elseif ($community_page && !empty(Session::getRemoteContactID($owner_uid))) {
if ($community_page && remote_user()) { $contact_id = Session::getRemoteContactID($owner_uid);
if (is_array($_SESSION['remote'])) {
foreach ($_SESSION['remote'] as $v) {
if ($v['uid'] == $owner_uid) {
$contact_id = $v['cid'];
break;
}
}
}
if ($contact_id) {
$contact = DBA::selectFirst('contact', [], ['id' => $contact_id, 'uid' => $owner_uid, 'blocked' => false, 'pending' => false]); $contact = DBA::selectFirst('contact', [], ['id' => $contact_id, 'uid' => $owner_uid, 'blocked' => false, 'pending' => false]);
if (DBA::isResult($contact)) { if (DBA::isResult($contact)) {
@ -912,31 +885,15 @@ function photos_content(App $a)
$visitor = $contact_id; $visitor = $contact_id;
} }
} }
}
}
$groups = [];
// perhaps they're visiting - but not a community page, so they wouldn't have write access // perhaps they're visiting - but not a community page, so they wouldn't have write access
if (remote_user() && !$visitor) { if (!empty(Session::getRemoteContactID($owner_uid)) && !$visitor) {
$contact_id = 0; $contact_id = Session::getRemoteContactID($owner_uid);
if (is_array($_SESSION['remote'])) {
foreach ($_SESSION['remote'] as $v) {
if ($v['uid'] == $owner_uid) {
$contact_id = $v['cid'];
break;
}
}
}
if ($contact_id) {
$groups = Group::getIdsByContactId($contact_id);
$contact = DBA::selectFirst('contact', [], ['id' => $contact_id, 'uid' => $owner_uid, 'blocked' => false, 'pending' => false]); $contact = DBA::selectFirst('contact', [], ['id' => $contact_id, 'uid' => $owner_uid, 'blocked' => false, 'pending' => false]);
$remote_contact = DBA::isResult($contact); $remote_contact = DBA::isResult($contact);
} }
}
if (!$remote_contact && local_user()) { if (!$remote_contact && local_user()) {
$contact_id = $_SESSION['cid']; $contact_id = $_SESSION['cid'];
@ -948,7 +905,7 @@ function photos_content(App $a)
return; return;
} }
$sql_extra = Security::getPermissionsSQLByUserId($owner_uid, $remote_contact, $groups); $sql_extra = Security::getPermissionsSQLByUserId($owner_uid);
$o = ""; $o = "";
@ -1049,7 +1006,7 @@ function photos_content(App $a)
$pager = new Pager($a->query_string, 20); $pager = new Pager($a->query_string, 20);
/// @TODO I have seen this many times, maybe generalize it script-wide and encapsulate it? /// @TODO I have seen this many times, maybe generalize it script-wide and encapsulate it?
$order_field = defaults($_GET, 'order', ''); $order_field = $_GET['order'] ?? '';
if ($order_field === 'posted') { if ($order_field === 'posted') {
$order = 'ASC'; $order = 'ASC';
} else { } else {
@ -1201,7 +1158,7 @@ function photos_content(App $a)
* By now we hide it if someone wants to. * By now we hide it if someone wants to.
*/ */
if ($cmd === 'view' && !Config::get('system', 'no_count', false)) { if ($cmd === 'view' && !Config::get('system', 'no_count', false)) {
$order_field = defaults($_GET, 'order', ''); $order_field = $_GET['order'] ?? '';
if ($order_field === 'posted') { if ($order_field === 'posted') {
$order = 'ASC'; $order = 'ASC';
@ -1607,7 +1564,7 @@ function photos_content(App $a)
$twist = false; $twist = false;
foreach ($r as $rr) { foreach ($r as $rr) {
//hide profile photos to others //hide profile photos to others
if (!$is_owner && !remote_user() && ($rr['album'] == L10n::t('Profile Photos'))) { if (!$is_owner && !Session::getRemoteContactID($owner_uid) && ($rr['album'] == L10n::t('Profile Photos'))) {
continue; continue;
} }

View file

@ -36,7 +36,7 @@ function poco_init(App $a) {
$system_mode = true; $system_mode = true;
} }
$format = defaults($_GET, 'format', 'json'); $format = ($_GET['format'] ?? '') ?: 'json';
$justme = false; $justme = false;
$global = false; $global = false;

View file

@ -594,7 +594,7 @@ function profiles_content(App $a) {
'$default' => (($is_default) ? '<p id="profile-edit-default-desc">' . L10n::t('This is your <strong>public</strong> profile.<br />It <strong>may</strong> be visible to anybody using the internet.') . '</p>' : ""), '$default' => (($is_default) ? '<p id="profile-edit-default-desc">' . L10n::t('This is your <strong>public</strong> profile.<br />It <strong>may</strong> be visible to anybody using the internet.') . '</p>' : ""),
'$name' => ['name', L10n::t('Your Full Name:'), $r[0]['name']], '$name' => ['name', L10n::t('Your Full Name:'), $r[0]['name']],
'$pdesc' => ['pdesc', L10n::t('Title/Description:'), $r[0]['pdesc']], '$pdesc' => ['pdesc', L10n::t('Title/Description:'), $r[0]['pdesc']],
'$dob' => Temporal::getDateofBirthField($r[0]['dob']), '$dob' => Temporal::getDateofBirthField($r[0]['dob'], $a->user['timezone']),
'$hide_friends' => $hide_friends, '$hide_friends' => $hide_friends,
'$address' => ['address', L10n::t('Street Address:'), $r[0]['address']], '$address' => ['address', L10n::t('Street Address:'), $r[0]['address']],
'$locality' => ['locality', L10n::t('Locality/City:'), $r[0]['locality']], '$locality' => ['locality', L10n::t('Locality/City:'), $r[0]['locality']],

View file

@ -33,10 +33,10 @@ function pubsub_init(App $a)
$contact_id = (($a->argc > 2) ? intval($a->argv[2]) : 0 ); $contact_id = (($a->argc > 2) ? intval($a->argv[2]) : 0 );
if ($_SERVER['REQUEST_METHOD'] === 'GET') { if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$hub_mode = Strings::escapeTags(trim(defaults($_GET, 'hub_mode', ''))); $hub_mode = Strings::escapeTags(trim($_GET['hub_mode'] ?? ''));
$hub_topic = Strings::escapeTags(trim(defaults($_GET, 'hub_topic', ''))); $hub_topic = Strings::escapeTags(trim($_GET['hub_topic'] ?? ''));
$hub_challenge = Strings::escapeTags(trim(defaults($_GET, 'hub_challenge', ''))); $hub_challenge = Strings::escapeTags(trim($_GET['hub_challenge'] ?? ''));
$hub_verify = Strings::escapeTags(trim(defaults($_GET, 'hub_verify_token', ''))); $hub_verify = Strings::escapeTags(trim($_GET['hub_verify_token'] ?? ''));
Logger::log('Subscription from ' . $_SERVER['REMOTE_ADDR'] . ' Mode: ' . $hub_mode . ' Nick: ' . $nick); Logger::log('Subscription from ' . $_SERVER['REMOTE_ADDR'] . ' Mode: ' . $hub_mode . ' Nick: ' . $nick);
Logger::log('Data: ' . print_r($_GET,true), Logger::DATA); Logger::log('Data: ' . print_r($_GET,true), Logger::DATA);

View file

@ -13,18 +13,18 @@ use Friendica\Util\Strings;
function redir_init(App $a) { function redir_init(App $a) {
$url = defaults($_GET, 'url', ''); $url = $_GET['url'] ?? '';
$quiet = !empty($_GET['quiet']) ? '&quiet=1' : ''; $quiet = !empty($_GET['quiet']) ? '&quiet=1' : '';
$con_url = defaults($_GET, 'conurl', '');
if ($a->argc > 1 && intval($a->argv[1])) { if ($a->argc > 1 && intval($a->argv[1])) {
$cid = intval($a->argv[1]); $cid = intval($a->argv[1]);
} elseif (local_user() && !empty($con_url)) {
$cid = Contact::getIdForURL($con_url, local_user());
} else { } else {
$cid = 0; $cid = 0;
} }
// Try magic auth before the legacy stuff
redir_magic($a, $cid, $url);
if (!empty($cid)) { if (!empty($cid)) {
$fields = ['id', 'uid', 'nurl', 'url', 'addr', 'name', 'network', 'poll', 'issued-id', 'dfrn-id', 'duplex', 'pending']; $fields = ['id', 'uid', 'nurl', 'url', 'addr', 'name', 'network', 'poll', 'issued-id', 'dfrn-id', 'duplex', 'pending'];
$contact = DBA::selectFirst('contact', $fields, ['id' => $cid, 'uid' => [0, local_user()]]); $contact = DBA::selectFirst('contact', $fields, ['id' => $cid, 'uid' => [0, local_user()]]);
@ -35,10 +35,10 @@ function redir_init(App $a) {
$contact_url = $contact['url']; $contact_url = $contact['url'];
if ((!local_user() && !remote_user()) // Visitors (not logged in or not remotes) can't authenticate. if (!Session::isAuthenticated() // Visitors (not logged in or not remotes) can't authenticate.
|| (!empty($a->contact['id']) && $a->contact['id'] == $cid)) // Local user is already authenticated. || (!empty($a->contact['id']) && $a->contact['id'] == $cid)) // Local user is already authenticated.
{ {
$a->redirect(defaults($url, $contact_url)); $a->redirect($url ?: $contact_url);
} }
if ($contact['uid'] == 0 && local_user()) { if ($contact['uid'] == 0 && local_user()) {
@ -52,7 +52,7 @@ function redir_init(App $a) {
if (!empty($a->contact['id']) && $a->contact['id'] == $cid) { if (!empty($a->contact['id']) && $a->contact['id'] == $cid) {
// Local user is already authenticated. // Local user is already authenticated.
$target_url = defaults($url, $contact_url); $target_url = $url ?: $contact_url;
Logger::log($contact['name'] . " is already authenticated. Redirecting to " . $target_url, Logger::DEBUG); Logger::log($contact['name'] . " is already authenticated. Redirecting to " . $target_url, Logger::DEBUG);
$a->redirect($target_url); $a->redirect($target_url);
} }
@ -66,34 +66,16 @@ function redir_init(App $a) {
// with the local contact. Otherwise the local user would ask the local contact // with the local contact. Otherwise the local user would ask the local contact
// for authentification everytime he/she is visiting a profile page of the local // for authentification everytime he/she is visiting a profile page of the local
// contact. // contact.
if ($host == $remotehost if (($host == $remotehost) && (Session::getRemoteContactID(Session::get('visitor_visiting')) == Session::get('visitor_id'))) {
&& !empty($_SESSION['remote'])
&& is_array($_SESSION['remote']))
{
foreach ($_SESSION['remote'] as $v) {
if (!empty($v['uid']) && !empty($v['cid']) &&
$v['uid'] == Session::get('visitor_visiting') &&
$v['cid'] == Session::get('visitor_id')) {
// Remote user is already authenticated. // Remote user is already authenticated.
$target_url = defaults($url, $contact_url); $target_url = $url ?: $contact_url;
Logger::log($contact['name'] . " is already authenticated. Redirecting to " . $target_url, Logger::DEBUG); Logger::log($contact['name'] . " is already authenticated. Redirecting to " . $target_url, Logger::DEBUG);
$a->redirect($target_url); $a->redirect($target_url);
} }
} }
}
}
// When the remote page does support OWA, then we enforce the use of it
$basepath = Contact::getBasepath($contact_url);
if (Strings::compareLink($basepath, System::baseUrl())) {
$use_magic = true;
} else {
$serverret = Network::curl($basepath . '/magic');
$use_magic = $serverret->isSuccess();
}
// Doing remote auth with dfrn. // Doing remote auth with dfrn.
if (local_user() && !$use_magic && (!empty($contact['dfrn-id']) || !empty($contact['issued-id'])) && empty($contact['pending'])) { if (local_user() && (!empty($contact['dfrn-id']) || !empty($contact['issued-id'])) && empty($contact['pending'])) {
$dfrn_id = $orig_id = (($contact['issued-id']) ? $contact['issued-id'] : $contact['dfrn-id']); $dfrn_id = $orig_id = (($contact['issued-id']) ? $contact['issued-id'] : $contact['dfrn-id']);
if ($contact['duplex'] && $contact['issued-id']) { if ($contact['duplex'] && $contact['issued-id']) {
@ -119,7 +101,7 @@ function redir_init(App $a) {
. '&dfrn_version=' . DFRN_PROTOCOL_VERSION . '&type=profile&sec=' . $sec . $dest . $quiet); . '&dfrn_version=' . DFRN_PROTOCOL_VERSION . '&type=profile&sec=' . $sec . $dest . $quiet);
} }
$url = defaults($url, $contact_url); $url = $url ?: $contact_url;
} }
// If we don't have a connected contact, redirect with // If we don't have a connected contact, redirect with
@ -140,3 +122,46 @@ function redir_init(App $a) {
notice(L10n::t('Contact not found.')); notice(L10n::t('Contact not found.'));
$a->internalRedirect(); $a->internalRedirect();
} }
function redir_magic($a, $cid, $url)
{
$visitor = Profile::getMyURL();
if (!empty($visitor)) {
Logger::info('Got my url', ['visitor' => $visitor]);
}
$contact = DBA::selectFirst('contact', ['url'], ['id' => $cid]);
if (!DBA::isResult($contact)) {
Logger::info('Contact not found', ['id' => $cid]);
// Shouldn't happen under normal conditions
notice(L10n::t('Contact not found.'));
if (!empty($url)) {
$a->redirect($url);
} else {
$a->internalRedirect();
}
} else {
$contact_url = $contact['url'];
$target_url = $url ?: $contact_url;
}
$basepath = Contact::getBasepath($contact_url);
// We don't use magic auth when there is no visitor, we are on the same system or we visit our own stuff
if (empty($visitor) || Strings::compareLink($basepath, System::baseUrl()) || Strings::compareLink($contact_url, $visitor)) {
Logger::info('Redirecting without magic', ['target' => $target_url, 'visitor' => $visitor, 'contact' => $contact_url]);
$a->redirect($target_url);
}
// Test for magic auth on the target system
$serverret = Network::curl($basepath . '/magic');
if ($serverret->isSuccess()) {
$separator = strpos($target_url, '?') ? '&' : '?';
$target_url .= $separator . 'zrl=' . urlencode($visitor) . '&addr=' . urlencode($contact_url);
Logger::info('Redirecting with magic', ['target' => $target_url, 'visitor' => $visitor, 'contact' => $contact_url]);
$a->redirect($target_url);
} else {
Logger::info('No magic for contact', ['contact' => $contact_url]);
}
}

View file

@ -44,7 +44,7 @@ function user_allow($hash)
$user, $user,
Config::get('config', 'sitename'), Config::get('config', 'sitename'),
$a->getBaseUrl(), $a->getBaseUrl(),
defaults($register, 'password', 'Sent in a previous email') ($register['password'] ?? '') ?: 'Sent in a previous email'
); );
L10n::popLang(); L10n::popLang();

View file

@ -1,245 +0,0 @@
<?php
/**
* @file mod/search.php
*/
use Friendica\App;
use Friendica\Content\Nav;
use Friendica\Content\Pager;
use Friendica\Content\Text\HTML;
use Friendica\Core\Cache;
use Friendica\Core\Config;
use Friendica\Core\L10n;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
use Friendica\Model\Item;
use Friendica\Module\BaseSearchModule;
use Friendica\Util\Strings;
function search_saved_searches() {
$o = '';
$search = (!empty($_GET['search']) ? Strings::escapeTags(trim(rawurldecode($_GET['search']))) : '');
$r = q("SELECT `id`,`term` FROM `search` WHERE `uid` = %d",
intval(local_user())
);
if (DBA::isResult($r)) {
$saved = [];
foreach ($r as $rr) {
$saved[] = [
'id' => $rr['id'],
'term' => $rr['term'],
'encodedterm' => urlencode($rr['term']),
'delete' => L10n::t('Remove term'),
'selected' => ($search==$rr['term']),
];
}
$tpl = Renderer::getMarkupTemplate("saved_searches_aside.tpl");
$o .= Renderer::replaceMacros($tpl, [
'$title' => L10n::t('Saved Searches'),
'$add' => '',
'$searchbox' => '',
'$saved' => $saved,
]);
}
return $o;
}
function search_init(App $a) {
$search = (!empty($_GET['search']) ? Strings::escapeTags(trim(rawurldecode($_GET['search']))) : '');
if (local_user()) {
if (!empty($_GET['save']) && $search) {
$r = q("SELECT * FROM `search` WHERE `uid` = %d AND `term` = '%s' LIMIT 1",
intval(local_user()),
DBA::escape($search)
);
if (!DBA::isResult($r)) {
DBA::insert('search', ['uid' => local_user(), 'term' => $search]);
}
}
if (!empty($_GET['remove']) && $search) {
DBA::delete('search', ['uid' => local_user(), 'term' => $search]);
}
/// @todo Check if there is a case at all that "aside" is prefilled here
if (!isset($a->page['aside'])) {
$a->page['aside'] = '';
}
$a->page['aside'] .= search_saved_searches();
} else {
unset($_SESSION['theme']);
unset($_SESSION['mobile-theme']);
}
}
function search_content(App $a) {
if (Config::get('system','block_public') && !local_user() && !remote_user()) {
notice(L10n::t('Public access denied.') . EOL);
return;
}
if (Config::get('system','local_search') && !local_user() && !remote_user()) {
$e = new \Friendica\Network\HTTPException\ForbiddenException(L10n::t("Only logged in users are permitted to perform a search."));
$e->httpdesc = L10n::t("Public access denied.");
throw $e;
}
if (Config::get('system','permit_crawling') && !local_user() && !remote_user()) {
// Default values:
// 10 requests are "free", after the 11th only a call per minute is allowed
$free_crawls = intval(Config::get('system','free_crawls'));
if ($free_crawls == 0)
$free_crawls = 10;
$crawl_permit_period = intval(Config::get('system','crawl_permit_period'));
if ($crawl_permit_period == 0)
$crawl_permit_period = 10;
$remote = $_SERVER["REMOTE_ADDR"];
$result = Cache::get("remote_search:".$remote);
if (!is_null($result)) {
$resultdata = json_decode($result);
if (($resultdata->time > (time() - $crawl_permit_period)) && ($resultdata->accesses > $free_crawls)) {
throw new \Friendica\Network\HTTPException\TooManyRequestsException(L10n::t("Only one search per minute is permitted for not logged in users."));
}
Cache::set("remote_search:".$remote, json_encode(["time" => time(), "accesses" => $resultdata->accesses + 1]), Cache::HOUR);
} else
Cache::set("remote_search:".$remote, json_encode(["time" => time(), "accesses" => 1]), Cache::HOUR);
}
Nav::setSelected('search');
$search = (!empty($_REQUEST['search']) ? Strings::escapeTags(trim(rawurldecode($_REQUEST['search']))) : '');
$tag = false;
if (!empty($_GET['tag'])) {
$tag = true;
$search = (!empty($_GET['tag']) ? '#' . Strings::escapeTags(trim(rawurldecode($_GET['tag']))) : '');
}
// contruct a wrapper for the search header
$o = Renderer::replaceMacros(Renderer::getMarkupTemplate("content_wrapper.tpl"),[
'name' => "search-header",
'$title' => L10n::t("Search"),
'$title_size' => 3,
'$content' => HTML::search($search,'search-box','search', false)
]);
if (strpos($search,'#') === 0) {
$tag = true;
$search = substr($search,1);
}
if (strpos($search,'@') === 0) {
return BaseSearchModule::performSearch();
}
if (strpos($search,'!') === 0) {
return BaseSearchModule::performSearch();
}
if (parse_url($search, PHP_URL_SCHEME) != '') {
$id = Item::fetchByLink($search);
if (!empty($id)) {
$item = Item::selectFirst(['guid'], ['id' => $id]);
if (DBA::isResult($item)) {
$a->internalRedirect('display/' . $item['guid']);
}
}
}
if (!empty($_GET['search-option']))
switch($_GET['search-option']) {
case 'fulltext':
break;
case 'tags':
$tag = true;
break;
case 'contacts':
return BaseSearchModule::performSearch('@');
case 'forums':
return BaseSearchModule::performSearch('!');
}
if (!$search)
return $o;
if (Config::get('system','only_tag_search'))
$tag = true;
// Here is the way permissions work in the search module...
// Only public posts can be shown
// OR your own posts if you are a logged in member
// No items will be shown if the member has a blocked profile wall.
$pager = new Pager($a->query_string);
if ($tag) {
Logger::log("Start tag search for '".$search."'", Logger::DEBUG);
$condition = ["(`uid` = 0 OR (`uid` = ? AND NOT `global`))
AND `otype` = ? AND `type` = ? AND `term` = ?",
local_user(), TERM_OBJ_POST, TERM_HASHTAG, $search];
$params = ['order' => ['received' => true],
'limit' => [$pager->getStart(), $pager->getItemsPerPage()]];
$terms = DBA::select('term', ['oid'], $condition, $params);
$itemids = [];
while ($term = DBA::fetch($terms)) {
$itemids[] = $term['oid'];
}
DBA::close($terms);
if (!empty($itemids)) {
$params = ['order' => ['id' => true]];
$items = Item::selectForUser(local_user(), [], ['id' => $itemids], $params);
$r = Item::inArray($items);
} else {
$r = [];
}
} else {
Logger::log("Start fulltext search for '".$search."'", Logger::DEBUG);
$condition = ["(`uid` = 0 OR (`uid` = ? AND NOT `global`))
AND `body` LIKE CONCAT('%',?,'%')",
local_user(), $search];
$params = ['order' => ['id' => true],
'limit' => [$pager->getStart(), $pager->getItemsPerPage()]];
$items = Item::selectForUser(local_user(), [], $condition, $params);
$r = Item::inArray($items);
}
if (!DBA::isResult($r)) {
info(L10n::t('No results.') . EOL);
return $o;
}
if ($tag) {
$title = L10n::t('Items tagged with: %s', $search);
} else {
$title = L10n::t('Results for: %s', $search);
}
$o .= Renderer::replaceMacros(Renderer::getMarkupTemplate("section_title.tpl"),[
'$title' => $title
]);
Logger::log("Start Conversation for '".$search."'", Logger::DEBUG);
$o .= conversation($a, $r, $pager, 'search', false, false, 'commented', local_user());
$o .= $pager->renderMinimal(count($r));
Logger::log("Done '".$search."'", Logger::DEBUG);
return $o;
}

View file

@ -35,7 +35,7 @@ function get_theme_config_file($theme)
$theme = Strings::sanitizeFilePathItem($theme); $theme = Strings::sanitizeFilePathItem($theme);
$a = \get_app(); $a = \get_app();
$base_theme = defaults($a->theme_info, 'extends'); $base_theme = $a->theme_info['extends'] ?? '';
if (file_exists("view/theme/$theme/config.php")) { if (file_exists("view/theme/$theme/config.php")) {
return "view/theme/$theme/config.php"; return "view/theme/$theme/config.php";
@ -115,8 +115,8 @@ function settings_init(App $a)
$tabs[] = [ $tabs[] = [
'label' => L10n::t('Delegations'), 'label' => L10n::t('Delegations'),
'url' => 'delegate', 'url' => 'settings/delegation',
'selected' => (($a->argc == 1) && ($a->argv[0] === 'delegate')?'active':''), 'selected' => (($a->argc > 1) && ($a->argv[1] === 'delegation')?'active':''),
'accesskey' => 'd', 'accesskey' => 'd',
]; ];
@ -180,11 +180,11 @@ function settings_post(App $a)
if (($a->argc > 2) && ($a->argv[1] === 'oauth') && ($a->argv[2] === 'edit'||($a->argv[2] === 'add')) && !empty($_POST['submit'])) { if (($a->argc > 2) && ($a->argv[1] === 'oauth') && ($a->argv[2] === 'edit'||($a->argv[2] === 'add')) && !empty($_POST['submit'])) {
BaseModule::checkFormSecurityTokenRedirectOnError('/settings/oauth', 'settings_oauth'); BaseModule::checkFormSecurityTokenRedirectOnError('/settings/oauth', 'settings_oauth');
$name = defaults($_POST, 'name' , ''); $name = $_POST['name'] ?? '';
$key = defaults($_POST, 'key' , ''); $key = $_POST['key'] ?? '';
$secret = defaults($_POST, 'secret' , ''); $secret = $_POST['secret'] ?? '';
$redirect = defaults($_POST, 'redirect', ''); $redirect = $_POST['redirect'] ?? '';
$icon = defaults($_POST, 'icon' , ''); $icon = $_POST['icon'] ?? '';
if ($name == "" || $key == "" || $secret == "") { if ($name == "" || $key == "" || $secret == "") {
notice(L10n::t("Missing some important data!")); notice(L10n::t("Missing some important data!"));
@ -241,24 +241,21 @@ function settings_post(App $a)
PConfig::set(local_user(), 'ostatus', 'default_group', $_POST['group-selection']); PConfig::set(local_user(), 'ostatus', 'default_group', $_POST['group-selection']);
PConfig::set(local_user(), 'ostatus', 'legacy_contact', $_POST['legacy_contact']); PConfig::set(local_user(), 'ostatus', 'legacy_contact', $_POST['legacy_contact']);
} elseif (!empty($_POST['imap-submit'])) { } elseif (!empty($_POST['imap-submit'])) {
$mail_server = $_POST['mail_server'] ?? '';
$mail_port = $_POST['mail_port'] ?? '';
$mail_ssl = strtolower(trim($_POST['mail_ssl'] ?? ''));
$mail_user = $_POST['mail_user'] ?? '';
$mail_pass = trim($_POST['mail_pass'] ?? '');
$mail_action = trim($_POST['mail_action'] ?? '');
$mail_movetofolder = trim($_POST['mail_movetofolder'] ?? '');
$mail_replyto = $_POST['mail_replyto'] ?? '';
$mail_pubmail = $_POST['mail_pubmail'] ?? '';
$mail_server = defaults($_POST, 'mail_server', ''); if (
$mail_port = defaults($_POST, 'mail_port', ''); !Config::get('system', 'dfrn_only')
$mail_ssl = (!empty($_POST['mail_ssl']) ? strtolower(trim($_POST['mail_ssl'])) : ''); && function_exists('imap_open')
$mail_user = defaults($_POST, 'mail_user', ''); && !Config::get('system', 'imap_disabled')
$mail_pass = (!empty($_POST['mail_pass']) ? trim($_POST['mail_pass']) : ''); ) {
$mail_action = (!empty($_POST['mail_action']) ? trim($_POST['mail_action']) : '');
$mail_movetofolder = (!empty($_POST['mail_movetofolder']) ? trim($_POST['mail_movetofolder']) : '');
$mail_replyto = defaults($_POST, 'mail_replyto', '');
$mail_pubmail = defaults($_POST, 'mail_pubmail', '');
$mail_disabled = ((function_exists('imap_open') && (!Config::get('system', 'imap_disabled'))) ? 0 : 1);
if (Config::get('system', 'dfrn_only')) {
$mail_disabled = 1;
}
if (!$mail_disabled) {
$failed = false; $failed = false;
$r = q("SELECT * FROM `mailacct` WHERE `uid` = %d LIMIT 1", $r = q("SELECT * FROM `mailacct` WHERE `uid` = %d LIMIT 1",
intval(local_user()) intval(local_user())
@ -1092,7 +1089,7 @@ function settings_content(App $a)
if (strlen(Config::get('system', 'directory'))) { if (strlen(Config::get('system', 'directory'))) {
$profile_in_net_dir = Renderer::replaceMacros($opt_tpl, [ $profile_in_net_dir = Renderer::replaceMacros($opt_tpl, [
'$field' => ['profile_in_netdirectory', L10n::t('Publish your default profile in the global social directory?'), $profile['net-publish'], L10n::t('Your profile will be published in the global friendica directories (e.g. <a href="%s">%s</a>). Your profile will be visible in public.', Config::get('system', 'directory'), Config::get('system', 'directory')), [L10n::t('No'), L10n::t('Yes')]] '$field' => ['profile_in_netdirectory', L10n::t('Publish your default profile in the global social directory?'), $profile['net-publish'], L10n::t('Your profile will be published in the global friendica directories (e.g. <a href="%s">%s</a>). Your profile will be visible in public.', Config::get('system', 'directory'), Config::get('system', 'directory')) . " " . L10n::t("This setting also determines whether Friendica will inform search engines that your profile should be indexed or not. Third-party search engines may or may not respect this setting."), [L10n::t('No'), L10n::t('Yes')]]
]); ]);
} else { } else {
$profile_in_net_dir = ''; $profile_in_net_dir = '';

View file

@ -6,6 +6,7 @@ use Friendica\App;
use Friendica\Core\Hook; use Friendica\Core\Hook;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Core\Logger; use Friendica\Core\Logger;
use Friendica\Core\Session;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Model\Item; use Friendica\Model\Item;
@ -15,7 +16,7 @@ use Friendica\Util\XML;
function subthread_content(App $a) { function subthread_content(App $a) {
if (!local_user() && !remote_user()) { if (!Session::isAuthenticated()) {
return; return;
} }

View file

@ -7,6 +7,7 @@ use Friendica\Core\Hook;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Core\Logger; use Friendica\Core\Logger;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Core\Worker; use Friendica\Core\Worker;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Model\Item; use Friendica\Model\Item;
@ -16,7 +17,7 @@ use Friendica\Worker\Delivery;
function tagger_content(App $a) { function tagger_content(App $a) {
if (!local_user() && !remote_user()) { if (!Session::isAuthenticated()) {
return; return;
} }

View file

@ -22,11 +22,11 @@ function tagrm_post(App $a)
} }
$tags = []; $tags = [];
foreach (defaults($_POST, 'tag', []) as $tag) { foreach ($_POST['tag'] ?? [] as $tag) {
$tags[] = hex2bin(Strings::escapeTags(trim($tag))); $tags[] = hex2bin(Strings::escapeTags(trim($tag)));
} }
$item_id = defaults($_POST,'item', 0); $item_id = $_POST['item'] ?? 0;
update_tags($item_id, $tags); update_tags($item_id, $tags);
info(L10n::t('Tag(s) removed') . EOL); info(L10n::t('Tag(s) removed') . EOL);

View file

@ -41,14 +41,6 @@ function uimport_content(App $a)
} }
} }
if (!empty($_SESSION['theme'])) {
unset($_SESSION['theme']);
}
if (!empty($_SESSION['mobile-theme'])) {
unset($_SESSION['mobile-theme']);
}
$tpl = Renderer::getMarkupTemplate("uimport.tpl"); $tpl = Renderer::getMarkupTemplate("uimport.tpl");
return Renderer::replaceMacros($tpl, [ return Renderer::replaceMacros($tpl, [
'$regbutt' => L10n::t('Import'), '$regbutt' => L10n::t('Import'),

View file

@ -25,7 +25,7 @@ function unfollow_post(App $a)
} }
$uid = local_user(); $uid = local_user();
$url = Strings::escapeTags(trim(defaults($_REQUEST, 'url', ''))); $url = Strings::escapeTags(trim($_REQUEST['url'] ?? ''));
$condition = ["`uid` = ? AND (`rel` = ? OR `rel` = ?) AND (`nurl` = ? OR `alias` = ? OR `alias` = ?)", $condition = ["`uid` = ? AND (`rel` = ? OR `rel` = ?) AND (`nurl` = ? OR `alias` = ? OR `alias` = ?)",
$uid, Contact::SHARING, Contact::FRIEND, Strings::normaliseLink($url), $uid, Contact::SHARING, Contact::FRIEND, Strings::normaliseLink($url),

View file

@ -10,6 +10,7 @@ use Friendica\Core\Config;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Model\Attach; use Friendica\Model\Attach;
use Friendica\Model\Contact; use Friendica\Model\Contact;
@ -22,11 +23,7 @@ use Friendica\Util\Security;
function videos_init(App $a) function videos_init(App $a)
{ {
if ($a->argc > 1) { if (Config::get('system', 'block_public') && !Session::isAuthenticated()) {
DFRN::autoRedir($a, $a->argv[1]);
}
if ((Config::get('system', 'block_public')) && (!local_user()) && (!remote_user())) {
return; return;
} }
@ -54,9 +51,9 @@ function videos_init(App $a)
$vcard_widget = Renderer::replaceMacros($tpl, [ $vcard_widget = Renderer::replaceMacros($tpl, [
'$name' => $profile['name'], '$name' => $profile['name'],
'$photo' => $profile['photo'], '$photo' => $profile['photo'],
'$addr' => defaults($profile, 'addr', ''), '$addr' => $profile['addr'] ?? '',
'$account_type' => $account_type, '$account_type' => $account_type,
'$pdesc' => defaults($profile, 'pdesc', ''), '$pdesc' => $profile['pdesc'] ?? '',
]); ]);
// If not there, create 'aside' empty // If not there, create 'aside' empty
@ -114,7 +111,7 @@ function videos_content(App $a)
// videos/name/video/xxxxx/edit // videos/name/video/xxxxx/edit
if ((Config::get('system', 'block_public')) && (!local_user()) && (!remote_user())) { if (Config::get('system', 'block_public') && !Session::isAuthenticated()) {
notice(L10n::t('Public access denied.') . EOL); notice(L10n::t('Public access denied.') . EOL);
return; return;
} }
@ -154,64 +151,25 @@ function videos_content(App $a)
if ((local_user()) && (local_user() == $owner_uid)) { if ((local_user()) && (local_user() == $owner_uid)) {
$can_post = true; $can_post = true;
} elseif ($community_page && remote_user()) { } elseif ($community_page && !empty(Session::getRemoteContactID($owner_uid))) {
if (!empty($_SESSION['remote'])) { $contact_id = Session::getRemoteContactID($owner_uid);
foreach ($_SESSION['remote'] as $v) {
if ($v['uid'] == $owner_uid) {
$contact_id = $v['cid'];
break;
}
}
}
if ($contact_id > 0) {
$r = q("SELECT `uid` FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `id` = %d AND `uid` = %d LIMIT 1",
intval($contact_id),
intval($owner_uid)
);
if (DBA::isResult($r)) {
$can_post = true; $can_post = true;
$remote_contact = true; $remote_contact = true;
$visitor = $contact_id; $visitor = $contact_id;
} }
}
}
$groups = [];
// perhaps they're visiting - but not a community page, so they wouldn't have write access // perhaps they're visiting - but not a community page, so they wouldn't have write access
if (remote_user() && (!$visitor)) { if (!empty(Session::getRemoteContactID($owner_uid)) && !$visitor) {
$contact_id = 0; $contact_id = Session::getRemoteContactID($owner_uid);
if (!empty($_SESSION['remote'])) {
foreach($_SESSION['remote'] as $v) {
if($v['uid'] == $owner_uid) {
$contact_id = $v['cid'];
break;
}
}
}
if ($contact_id > 0) {
$groups = Group::getIdsByContactId($contact_id);
$r = q("SELECT * FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `id` = %d AND `uid` = %d LIMIT 1",
intval($contact_id),
intval($owner_uid)
);
if (DBA::isResult($r)) {
$remote_contact = true; $remote_contact = true;
} }
}
}
if ($a->data['user']['hidewall'] && (local_user() != $owner_uid) && (!$remote_contact)) { if ($a->data['user']['hidewall'] && (local_user() != $owner_uid) && !$remote_contact) {
notice(L10n::t('Access to this item is restricted.') . EOL); notice(L10n::t('Access to this item is restricted.') . EOL);
return; return;
} }
$sql_extra = Security::getPermissionsSQLByUserId($owner_uid, $remote_contact, $groups); $sql_extra = Security::getPermissionsSQLByUserId($owner_uid);
$o = ""; $o = "";

View file

@ -6,6 +6,7 @@
use Friendica\App; use Friendica\App;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Core\Session;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Model\Attach; use Friendica\Model\Attach;
use Friendica\Model\User; use Friendica\Model\User;
@ -43,22 +44,10 @@ function wall_attach_post(App $a) {
$page_owner_cid = $r[0]['id']; $page_owner_cid = $r[0]['id'];
$community_page = (($r[0]['page-flags'] == User::PAGE_FLAGS_COMMUNITY) ? true : false); $community_page = (($r[0]['page-flags'] == User::PAGE_FLAGS_COMMUNITY) ? true : false);
if ((local_user()) && (local_user() == $page_owner_uid)) { if (local_user() && (local_user() == $page_owner_uid)) {
$can_post = true; $can_post = true;
} else { } elseif ($community_page && !empty(Session::getRemoteContactID($page_owner_uid))) {
if ($community_page && remote_user()) { $contact_id = Session::getRemoteContactID($page_owner_uid);
$contact_id = 0;
if (is_array($_SESSION['remote'])) {
foreach ($_SESSION['remote'] as $v) {
if ($v['uid'] == $page_owner_uid) {
$contact_id = $v['cid'];
break;
}
}
}
if ($contact_id > 0) {
$r = q("SELECT `uid` FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `id` = %d AND `uid` = %d LIMIT 1", $r = q("SELECT `uid` FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `id` = %d AND `uid` = %d LIMIT 1",
intval($contact_id), intval($contact_id),
intval($page_owner_uid) intval($page_owner_uid)
@ -68,8 +57,6 @@ function wall_attach_post(App $a) {
$can_post = true; $can_post = true;
} }
} }
}
}
if (!$can_post) { if (!$can_post) {
if ($r_json) { if ($r_json) {

View file

@ -12,6 +12,7 @@ use Friendica\App;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Core\Logger; use Friendica\Core\Logger;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Model\Contact; use Friendica\Model\Contact;
@ -74,19 +75,9 @@ function wall_upload_post(App $a, $desktopmode = true)
if ((local_user()) && (local_user() == $page_owner_uid)) { if ((local_user()) && (local_user() == $page_owner_uid)) {
$can_post = true; $can_post = true;
} else { } elseif ($community_page && !empty(Session::getRemoteContactID($page_owner_uid))) {
if ($community_page && remote_user()) { $contact_id = Session::getRemoteContactID($page_owner_uid);
$contact_id = 0;
if (is_array($_SESSION['remote'])) {
foreach ($_SESSION['remote'] as $v) {
if ($v['uid'] == $page_owner_uid) {
$contact_id = $v['cid'];
break;
}
}
}
if ($contact_id) {
$r = q("SELECT `uid` FROM `contact` $r = q("SELECT `uid` FROM `contact`
WHERE `blocked` = 0 AND `pending` = 0 WHERE `blocked` = 0 AND `pending` = 0
AND `id` = %d AND `uid` = %d LIMIT 1", AND `id` = %d AND `uid` = %d LIMIT 1",
@ -98,9 +89,6 @@ function wall_upload_post(App $a, $desktopmode = true)
$visitor = $contact_id; $visitor = $contact_id;
} }
} }
}
}
if (!$can_post) { if (!$can_post) {
if ($r_json) { if ($r_json) {

View file

@ -131,8 +131,8 @@ function wallmessage_content(App $a) {
'$subject' => L10n::t('Subject:'), '$subject' => L10n::t('Subject:'),
'$recipname' => $user['username'], '$recipname' => $user['username'],
'$nickname' => $user['nickname'], '$nickname' => $user['nickname'],
'$subjtxt' => defaults($_REQUEST, 'subject', ''), '$subjtxt' => $_REQUEST['subject'] ?? '',
'$text' => defaults($_REQUEST, 'body', ''), '$text' => $_REQUEST['body'] ?? '',
'$readonly' => '', '$readonly' => '',
'$yourmessage'=> L10n::t('Your message:'), '$yourmessage'=> L10n::t('Your message:'),
'$parent' => '', '$parent' => '',

View file

@ -102,8 +102,8 @@ $HTTP["scheme"] == "https" {
# Got the following 'Drupal Clean URL'after Mike suggested trying # Got the following 'Drupal Clean URL'after Mike suggested trying
# something along those lines, from http://drupal.org/node/1414950 # something along those lines, from http://drupal.org/node/1414950
url.rewrite-if-not-file = ( url.rewrite-if-not-file = (
"^\/([^\?]*)\?(.*)$" => "/index.php?q=$1&$2", "^\/([^\?]*)\?(.*)$" => "/index.php?pagename=$1&$2",
"^\/(.*)$" => "/index.php?q=$1" "^\/(.*)$" => "/index.php?pagename=$1"
) )
} }
else $HTTP["host"] !~ "(friendica.example.com|wordpress.example.com)" { else $HTTP["host"] !~ "(friendica.example.com|wordpress.example.com)" {

View file

@ -92,10 +92,10 @@ class App
*/ */
private $baseURL; private $baseURL;
/** /** @var string The name of the current theme */
* @var string The name of the current theme
*/
private $currentTheme; private $currentTheme;
/** @var string The name of the current mobile theme */
private $currentMobileTheme;
/** /**
* @var Configuration The config * @var Configuration The config
@ -450,10 +450,10 @@ class App
} }
/** /**
* Returns the current theme name. * Returns the current theme name. May be overriden by the mobile theme name.
* *
* @return string the name of the current theme * @return string
* @throws HTTPException\InternalServerErrorException * @throws Exception
*/ */
public function getCurrentTheme() public function getCurrentTheme()
{ {
@ -461,6 +461,16 @@ class App
return ''; return '';
} }
// Specific mobile theme override
if (($this->mode->isMobile() || $this->mode->isTablet()) && Core\Session::get('show-mobile', true)) {
$user_mobile_theme = $this->getCurrentMobileTheme();
// --- means same mobile theme as desktop
if (!empty($user_mobile_theme) && $user_mobile_theme !== '---') {
return $user_mobile_theme;
}
}
if (!$this->currentTheme) { if (!$this->currentTheme) {
$this->computeCurrentTheme(); $this->computeCurrentTheme();
} }
@ -468,13 +478,37 @@ class App
return $this->currentTheme; return $this->currentTheme;
} }
/**
* Returns the current mobile theme name.
*
* @return string
* @throws Exception
*/
public function getCurrentMobileTheme()
{
if ($this->mode->isInstall()) {
return '';
}
if (is_null($this->currentMobileTheme)) {
$this->computeCurrentMobileTheme();
}
return $this->currentMobileTheme;
}
public function setCurrentTheme($theme) public function setCurrentTheme($theme)
{ {
$this->currentTheme = $theme; $this->currentTheme = $theme;
} }
public function setCurrentMobileTheme($theme)
{
$this->currentMobileTheme = $theme;
}
/** /**
* Computes the current theme name based on the node settings, the user settings and the device type * Computes the current theme name based on the node settings, the page owner settings and the user settings
* *
* @throws Exception * @throws Exception
*/ */
@ -486,7 +520,7 @@ class App
} }
// Sane default // Sane default
$this->currentTheme = $system_theme; $this->setCurrentTheme($system_theme);
$page_theme = null; $page_theme = null;
// Find the theme that belongs to the user whose stuff we are looking at // Find the theme that belongs to the user whose stuff we are looking at
@ -499,24 +533,7 @@ class App
} }
} }
$user_theme = Core\Session::get('theme', $system_theme); $theme_name = $page_theme ?: Core\Session::get('theme', $system_theme);
// Specific mobile theme override
if (($this->is_mobile || $this->is_tablet) && Core\Session::get('show-mobile', true)) {
$system_mobile_theme = $this->config->get('system', 'mobile-theme');
$user_mobile_theme = Core\Session::get('mobile-theme', $system_mobile_theme);
// --- means same mobile theme as desktop
if (!empty($user_mobile_theme) && $user_mobile_theme !== '---') {
$user_theme = $user_mobile_theme;
}
}
if ($page_theme) {
$theme_name = $page_theme;
} else {
$theme_name = $user_theme;
}
$theme_name = Strings::sanitizeFilePathItem($theme_name); $theme_name = Strings::sanitizeFilePathItem($theme_name);
if ($theme_name if ($theme_name
@ -524,7 +541,40 @@ class App
&& (file_exists('view/theme/' . $theme_name . '/style.css') && (file_exists('view/theme/' . $theme_name . '/style.css')
|| file_exists('view/theme/' . $theme_name . '/style.php')) || file_exists('view/theme/' . $theme_name . '/style.php'))
) { ) {
$this->currentTheme = $theme_name; $this->setCurrentTheme($theme_name);
}
}
/**
* Computes the current mobile theme name based on the node settings, the page owner settings and the user settings
*/
private function computeCurrentMobileTheme()
{
$system_mobile_theme = $this->config->get('system', 'mobile-theme', '');
// Sane default
$this->setCurrentMobileTheme($system_mobile_theme);
$page_mobile_theme = null;
// Find the theme that belongs to the user whose stuff we are looking at
if ($this->profile_uid && ($this->profile_uid != local_user())) {
// Allow folks to override user themes and always use their own on their own site.
// This works only if the user is on the same server
if (!Core\PConfig::get(local_user(), 'system', 'always_my_theme')) {
$page_mobile_theme = Core\PConfig::get($this->profile_uid, 'system', 'mobile-theme');
}
}
$mobile_theme_name = $page_mobile_theme ?: Core\Session::get('mobile-theme', $system_mobile_theme);
$mobile_theme_name = Strings::sanitizeFilePathItem($mobile_theme_name);
if ($mobile_theme_name == '---'
||
in_array($mobile_theme_name, Theme::getAllowedList())
&& (file_exists('view/theme/' . $mobile_theme_name . '/style.css')
|| file_exists('view/theme/' . $mobile_theme_name . '/style.php'))
) {
$this->setCurrentMobileTheme($mobile_theme_name);
} }
} }
@ -534,7 +584,7 @@ class App
* Provide a sane default if nothing is chosen or the specified theme does not exist. * Provide a sane default if nothing is chosen or the specified theme does not exist.
* *
* @return string * @return string
* @throws HTTPException\InternalServerErrorException * @throws Exception
*/ */
public function getCurrentThemeStylesheetPath() public function getCurrentThemeStylesheetPath()
{ {
@ -588,6 +638,10 @@ class App
* This probably should change to limit the size of this monster method. * This probably should change to limit the size of this monster method.
* *
* @param App\Module $module The determined module * @param App\Module $module The determined module
* @param App\Router $router
* @param PConfiguration $pconfig
* @throws HTTPException\InternalServerErrorException
* @throws \ImagickException
*/ */
public function runFrontend(App\Module $module, App\Router $router, PConfiguration $pconfig) public function runFrontend(App\Module $module, App\Router $router, PConfiguration $pconfig)
{ {
@ -733,8 +787,7 @@ class App
$module = $module->determineClass($this->args, $router, $this->config); $module = $module->determineClass($this->args, $router, $this->config);
// Let the module run it's internal process (init, get, post, ...) // Let the module run it's internal process (init, get, post, ...)
$module->run($this->l10n, $this, $this->logger, $this->getCurrentTheme(), $_SERVER, $_POST); $module->run($this->l10n, $this, $this->logger, $_SERVER, $_POST);
} catch (HTTPException $e) { } catch (HTTPException $e) {
ModuleHTTPException::rawContent($e); ModuleHTTPException::rawContent($e);
} }

View file

@ -70,7 +70,7 @@ class Arguments
/** /**
* Returns the value of a argv key * Returns the value of a argv key
* @todo there are a lot of $a->argv usages in combination with defaults() which can be replaced with this method * @todo there are a lot of $a->argv usages in combination with ?? which can be replaced with this method
* *
* @param int $position the position of the argument * @param int $position the position of the argument
* @param mixed $default the default value if not found * @param mixed $default the default value if not found

View file

@ -338,12 +338,12 @@ class BaseURL
/* Relative script path to the web server root /* Relative script path to the web server root
* Not all of those $_SERVER properties can be present, so we do by inverse priority order * Not all of those $_SERVER properties can be present, so we do by inverse priority order
*/ */
$relative_script_path = ''; $relative_script_path =
$relative_script_path = defaults($this->server, 'REDIRECT_URL', $relative_script_path); ($this->server['REDIRECT_URL'] ?? '') ?:
$relative_script_path = defaults($this->server, 'REDIRECT_URI', $relative_script_path); ($this->server['REDIRECT_URI'] ?? '') ?:
$relative_script_path = defaults($this->server, 'REDIRECT_SCRIPT_URL', $relative_script_path); ($this->server['REDIRECT_SCRIPT_URL'] ?? '') ?:
$relative_script_path = defaults($this->server, 'SCRIPT_URL', $relative_script_path); ($this->server['SCRIPT_URL'] ?? '') ?:
$relative_script_path = defaults($this->server, 'REQUEST_URI', $relative_script_path); $this->server['REQUEST_URI'] ?? '';
/* $relative_script_path gives /relative/path/to/friendica/module/parameter /* $relative_script_path gives /relative/path/to/friendica/module/parameter
* QUERY_STRING gives pagename=module/parameter * QUERY_STRING gives pagename=module/parameter

View file

@ -106,15 +106,16 @@ class Mode
/** /**
* Checks if the site is called via a backend process * Checks if the site is called via a backend process
* *
* @param bool $isBackend True, if the call is from a backend script (daemon, worker, ...)
* @param Module $module The pre-loaded module (just name, not class!) * @param Module $module The pre-loaded module (just name, not class!)
* @param array $server The $_SERVER variable * @param array $server The $_SERVER variable
* @param MobileDetect $mobileDetect The mobile detection library * @param MobileDetect $mobileDetect The mobile detection library
* *
* @return Mode returns the determined mode * @return Mode returns the determined mode
*/ */
public function determineRunMode(Module $module, array $server, MobileDetect $mobileDetect) public function determineRunMode(bool $isBackend, Module $module, array $server, MobileDetect $mobileDetect)
{ {
$isBackend = basename(($server['PHP_SELF'] ?? ''), '.php') !== 'index' || $isBackend = $isBackend ||
$module->isBackend(); $module->isBackend();
$isMobile = $mobileDetect->isMobile(); $isMobile = $mobileDetect->isMobile();
$isTablet = $mobileDetect->isTablet(); $isTablet = $mobileDetect->isTablet();

View file

@ -7,7 +7,10 @@ use Friendica\BaseObject;
use Friendica\Core; use Friendica\Core;
use Friendica\LegacyModule; use Friendica\LegacyModule;
use Friendica\Module\Home; use Friendica\Module\Home;
use Friendica\Module\PageNotFound; use Friendica\Module\HTTPException\MethodNotAllowed;
use Friendica\Module\HTTPException\PageNotFound;
use Friendica\Network\HTTPException\MethodNotAllowedException;
use Friendica\Network\HTTPException\NotFoundException;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
/** /**
@ -138,29 +141,26 @@ class Module
* *
* @return Module The determined module of this call * @return Module The determined module of this call
* *
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Exception
*/ */
public function determineClass(Arguments $args, Router $router, Core\Config\Configuration $config) public function determineClass(Arguments $args, Router $router, Core\Config\Configuration $config)
{ {
$printNotAllowedAddon = false; $printNotAllowedAddon = false;
$module_class = null;
/** /**
* ROUTING * ROUTING
* *
* From the request URL, routing consists of obtaining the name of a BaseModule-extending class of which the * From the request URL, routing consists of obtaining the name of a BaseModule-extending class of which the
* post() and/or content() static methods can be respectively called to produce a data change or an output. * post() and/or content() static methods can be respectively called to produce a data change or an output.
**/ **/
try {
// First we try explicit routes defined in App\Router
$router->collectRoutes();
$data = $router->getRouteCollector();
Core\Hook::callAll('route_collection', $data);
$module_class = $router->getModuleClass($args->getCommand()); $module_class = $router->getModuleClass($args->getCommand());
} catch (MethodNotAllowedException $e) {
$module_class = MethodNotAllowed::class;
} catch (NotFoundException $e) {
// Then we try addon-provided modules that we wrap in the LegacyModule class // Then we try addon-provided modules that we wrap in the LegacyModule class
if (!$module_class && Core\Addon::isEnabled($this->module) && file_exists("addon/{$this->module}/{$this->module}.php")) { if (Core\Addon::isEnabled($this->module) && file_exists("addon/{$this->module}/{$this->module}.php")) {
//Check if module is an app and if public access to apps is allowed or not //Check if module is an app and if public access to apps is allowed or not
$privateapps = $config->get('config', 'private_addons', false); $privateapps = $config->get('config', 'private_addons', false);
if ((!local_user()) && Core\Hook::isAddonApp($this->module) && $privateapps) { if ((!local_user()) && Core\Hook::isAddonApp($this->module) && $privateapps) {
@ -182,7 +182,8 @@ class Module
$module_class = LegacyModule::class; $module_class = LegacyModule::class;
} }
$module_class = !isset($module_class) ? PageNotFound::class : $module_class; $module_class = $module_class ?: PageNotFound::class;
}
return new Module($this->module, $module_class, $this->isBackend, $printNotAllowedAddon); return new Module($this->module, $module_class, $this->isBackend, $printNotAllowedAddon);
} }
@ -193,13 +194,12 @@ class Module
* @param Core\L10n\L10n $l10n The L10n instance * @param Core\L10n\L10n $l10n The L10n instance
* @param App $app The whole Friendica app (for method arguments) * @param App $app The whole Friendica app (for method arguments)
* @param LoggerInterface $logger The Friendica logger * @param LoggerInterface $logger The Friendica logger
* @param string $currentTheme The chosen theme
* @param array $server The $_SERVER variable * @param array $server The $_SERVER variable
* @param array $post The $_POST variables * @param array $post The $_POST variables
* *
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/ */
public function run(Core\L10n\L10n $l10n, App $app, LoggerInterface $logger, string $currentTheme, array $server, array $post) public function run(Core\L10n\L10n $l10n, App $app, LoggerInterface $logger, array $server, array $post)
{ {
if ($this->printNotAllowedAddon) { if ($this->printNotAllowedAddon) {
info($l10n->t("You must be logged in to use addons. ")); info($l10n->t("You must be logged in to use addons. "));
@ -239,17 +239,6 @@ class Module
// This endpoint doesn't need any theme initialization or other comparable stuff. // This endpoint doesn't need any theme initialization or other comparable stuff.
call_user_func([$this->module_class, 'rawContent']); call_user_func([$this->module_class, 'rawContent']);
// Load current theme info after module has been initialized as theme could have been set in module
$theme_info_file = 'view/theme/' . $currentTheme . '/theme.php';
if (file_exists($theme_info_file)) {
require_once $theme_info_file;
}
if (function_exists(str_replace('-', '_', $currentTheme) . '_init')) {
$func = str_replace('-', '_', $currentTheme) . '_init';
$func($app);
}
if ($server['REQUEST_METHOD'] === 'POST') { if ($server['REQUEST_METHOD'] === 'POST') {
Core\Hook::callAll($this->module . '_mod_post', $post); Core\Hook::callAll($this->module . '_mod_post', $post);
call_user_func([$this->module_class, 'post']); call_user_func([$this->module_class, 'post']);

View file

@ -364,6 +364,18 @@ class Page implements ArrayAccess
*/ */
$this->initContent($module, $mode); $this->initContent($module, $mode);
// Load current theme info after module has been initialized as theme could have been set in module
$currentTheme = $app->getCurrentTheme();
$theme_info_file = 'view/theme/' . $currentTheme . '/theme.php';
if (file_exists($theme_info_file)) {
require_once $theme_info_file;
}
if (function_exists(str_replace('-', '_', $currentTheme) . '_init')) {
$func = str_replace('-', '_', $currentTheme) . '_init';
$func($app);
}
/* Create the page head after setting the language /* Create the page head after setting the language
* and getting any auth credentials. * and getting any auth credentials.
* *

View file

@ -7,7 +7,9 @@ use FastRoute\DataGenerator\GroupCountBased;
use FastRoute\Dispatcher; use FastRoute\Dispatcher;
use FastRoute\RouteCollector; use FastRoute\RouteCollector;
use FastRoute\RouteParser\Std; use FastRoute\RouteParser\Std;
use Friendica\Module; use Friendica\Core\Hook;
use Friendica\Core\L10n;
use Friendica\Network\HTTPException;
/** /**
* Wrapper for FastRoute\Router * Wrapper for FastRoute\Router
@ -21,212 +23,129 @@ use Friendica\Module;
*/ */
class Router class Router
{ {
const POST = 'POST';
const GET = 'GET';
const ALLOWED_METHODS = [
self::POST,
self::GET,
];
/** @var RouteCollector */ /** @var RouteCollector */
protected $routeCollector; protected $routeCollector;
/** /**
* Static declaration of Friendica routes. * @var string The HTTP method
*
* Supports:
* - Route groups
* - Variable parts
* Disregards:
* - HTTP method other than GET
* - Named parameters
*
* Handler must be the name of a class extending Friendica\BaseModule.
*
* @brief Static declaration of Friendica routes.
*/ */
public function collectRoutes() private $httpMethod;
/**
* @param array $server The $_SERVER variable
* @param RouteCollector|null $routeCollector Optional the loaded Route collector
*/
public function __construct(array $server, RouteCollector $routeCollector = null)
{ {
$this->routeCollector->addRoute(['GET'], '[/]', Module\Home::class); $httpMethod = $server['REQUEST_METHOD'] ?? self::GET;
$this->routeCollector->addGroup('/.well-known', function (RouteCollector $collector) { $this->httpMethod = in_array($httpMethod, self::ALLOWED_METHODS) ? $httpMethod : self::GET;
$collector->addRoute(['GET'], '/host-meta' , Module\WellKnown\HostMeta::class);
$collector->addRoute(['GET'], '/nodeinfo[/1.0]' , Module\NodeInfo::class);
$collector->addRoute(['GET'], '/webfinger' , Module\Xrd::class);
$collector->addRoute(['GET'], '/x-social-relay' , Module\WellKnown\XSocialRelay::class);
});
$this->routeCollector->addGroup('/2fa', function (RouteCollector $collector) {
$collector->addRoute(['GET', 'POST'], '[/]' , Module\TwoFactor\Verify::class);
$collector->addRoute(['GET', 'POST'], '/recovery' , Module\TwoFactor\Recovery::class);
});
$this->routeCollector->addGroup('/admin', function (RouteCollector $collector) {
$collector->addRoute(['GET'] , '[/]' , Module\Admin\Summary::class);
$collector->addRoute(['GET', 'POST'], '/addons' , Module\Admin\Addons\Index::class); $this->routeCollector = isset($routeCollector) ?
$collector->addRoute(['GET', 'POST'], '/addons/{addon}' , Module\Admin\Addons\Details::class); $routeCollector :
new RouteCollector(new Std(), new GroupCountBased());
$collector->addRoute(['GET', 'POST'], '/blocklist/contact' , Module\Admin\Blocklist\Contact::class);
$collector->addRoute(['GET', 'POST'], '/blocklist/server' , Module\Admin\Blocklist\Server::class);
$collector->addRoute(['GET'] , '/dbsync[/check]' , Module\Admin\DBSync::class);
$collector->addRoute(['GET'] , '/dbsync/{update:\d+}' , Module\Admin\DBSync::class);
$collector->addRoute(['GET'] , '/dbsync/mark/{update:\d+}', Module\Admin\DBSync::class);
$collector->addRoute(['GET', 'POST'], '/features' , Module\Admin\Features::class);
$collector->addRoute(['GET'] , '/federation' , Module\Admin\Federation::class);
$collector->addRoute(['GET', 'POST'], '/item/delete' , Module\Admin\Item\Delete::class);
$collector->addRoute(['GET', 'POST'], '/item/source[/{guid}]' , Module\Admin\Item\Source::class);
$collector->addRoute(['GET'] , '/logs/view' , Module\Admin\Logs\View::class);
$collector->addRoute(['GET', 'POST'], '/logs' , Module\Admin\Logs\Settings::class);
$collector->addRoute(['GET'] , '/phpinfo' , Module\Admin\PhpInfo::class);
$collector->addRoute(['GET'] , '/queue[/deferred]' , Module\Admin\Queue::class);
$collector->addRoute(['GET', 'POST'], '/site' , Module\Admin\Site::class);
$collector->addRoute(['GET', 'POST'], '/themes' , Module\Admin\Themes\Index::class);
$collector->addRoute(['GET', 'POST'], '/themes/{theme}' , Module\Admin\Themes\Details::class);
$collector->addRoute(['GET', 'POST'], '/themes/{theme}/embed' , Module\Admin\Themes\Embed::class);
$collector->addRoute(['GET', 'POST'], '/tos' , Module\Admin\Tos::class);
$collector->addRoute(['GET', 'POST'], '/users[/{action}/{uid}]' , Module\Admin\Users::class);
});
$this->routeCollector->addRoute(['GET'], '/amcd', Module\AccountManagementControlDocument::class);
$this->routeCollector->addRoute(['GET'], '/acctlink', Module\Acctlink::class);
$this->routeCollector->addRoute(['GET'], '/allfriends/{id:\d+}', Module\AllFriends::class);
$this->routeCollector->addRoute(['GET'], '/apps', Module\Apps::class);
$this->routeCollector->addRoute(['GET'], '/attach/{item:\d+}', Module\Attach::class);
$this->routeCollector->addRoute(['GET'], '/babel', Module\Debug\Babel::class);
$this->routeCollector->addRoute(['GET'], '/bookmarklet', Module\Bookmarklet::class);
$this->routeCollector->addRoute(['GET', 'POST'], '/compose[/{type}]', Module\Item\Compose::class);
$this->routeCollector->addGroup('/contact', function (RouteCollector $collector) {
$collector->addRoute(['GET'], '[/]', Module\Contact::class);
$collector->addRoute(['GET', 'POST'], '/{id:\d+}[/]', Module\Contact::class);
$collector->addRoute(['GET'], '/{id:\d+}/archive', Module\Contact::class);
$collector->addRoute(['GET'], '/{id:\d+}/block', Module\Contact::class);
$collector->addRoute(['GET'], '/{id:\d+}/conversations', Module\Contact::class);
$collector->addRoute(['GET'], '/{id:\d+}/drop', Module\Contact::class);
$collector->addRoute(['GET'], '/{id:\d+}/ignore', Module\Contact::class);
$collector->addRoute(['GET'], '/{id:\d+}/posts', Module\Contact::class);
$collector->addRoute(['GET'], '/{id:\d+}/update', Module\Contact::class);
$collector->addRoute(['GET'], '/{id:\d+}/updateprofile', Module\Contact::class);
$collector->addRoute(['GET'], '/archived', Module\Contact::class);
$collector->addRoute(['GET', 'POST'], '/batch', Module\Contact::class);
$collector->addRoute(['GET'], '/blocked', Module\Contact::class);
$collector->addRoute(['GET'], '/hidden', Module\Contact::class);
$collector->addRoute(['GET'], '/ignored', Module\Contact::class);
});
$this->routeCollector->addRoute(['GET'], '/credits', Module\Credits::class);
$this->routeCollector->addRoute(['GET'], '/dirfind', Module\Search\Directory::class);
$this->routeCollector->addRoute(['GET'], '/directory', Module\Directory::class);
$this->routeCollector->addGroup('/feed', function (RouteCollector $collector) {
$collector->addRoute(['GET'], '/{nickname}', Module\Feed::class);
$collector->addRoute(['GET'], '/{nickname}/posts', Module\Feed::class);
$collector->addRoute(['GET'], '/{nickname}/comments', Module\Feed::class);
$collector->addRoute(['GET'], '/{nickname}/replies', Module\Feed::class);
$collector->addRoute(['GET'], '/{nickname}/activity', Module\Feed::class);
});
$this->routeCollector->addRoute(['GET'], '/feedtest', Module\Debug\Feed::class);
$this->routeCollector->addGroup('/fetch', function (RouteCollector $collector) {
$collector->addRoute(['GET'], '/post/{guid}', Module\Diaspora\Fetch::class);
$collector->addRoute(['GET'], '/status_message/{guid}', Module\Diaspora\Fetch::class);
$collector->addRoute(['GET'], '/reshare/{guid}', Module\Diaspora\Fetch::class);
});
$this->routeCollector->addRoute(['GET'], '/filer[/{id:\d+}]', Module\Filer\SaveTag::class);
$this->routeCollector->addRoute(['GET'], '/filerm/{id:\d+}', Module\Filer\RemoveTag::class);
$this->routeCollector->addRoute(['GET', 'POST'], '/follow_confirm', Module\FollowConfirm::class);
$this->routeCollector->addRoute(['GET'], '/followers/{owner}', Module\Followers::class);
$this->routeCollector->addRoute(['GET'], '/following/{owner}', Module\Following::class);
$this->routeCollector->addRoute(['GET'], '/friendica[/json]', Module\Friendica::class);
$this->routeCollector->addGroup('/group', function (RouteCollector $collector) {
$collector->addRoute(['GET', 'POST'], '[/]', Module\Group::class);
$collector->addRoute(['GET', 'POST'], '/{group:\d+}', Module\Group::class);
$collector->addRoute(['GET', 'POST'], '/none', Module\Group::class);
$collector->addRoute(['GET', 'POST'], '/new', Module\Group::class);
$collector->addRoute(['GET', 'POST'], '/drop/{group:\d+}', Module\Group::class);
$collector->addRoute(['GET', 'POST'], '/{group:\d+}/{contact:\d+}', Module\Group::class);
$collector->addRoute(['GET', 'POST'], '/{group:\d+}/add/{contact:\d+}', Module\Group::class);
$collector->addRoute(['GET', 'POST'], '/{group:\d+}/remove/{contact:\d+}', Module\Group::class);
});
$this->routeCollector->addRoute(['GET'], '/hashtag', Module\Hashtag::class);
$this->routeCollector->addRoute(['GET'], '/home', Module\Home::class);
$this->routeCollector->addRoute(['GET'], '/help[/{doc:.+}]', Module\Help::class);
$this->routeCollector->addRoute(['GET'], '/inbox[/{nickname}]', Module\Inbox::class);
$this->routeCollector->addRoute(['GET', 'POST'], '/invite', Module\Invite::class);
$this->routeCollector->addGroup('/install', function (RouteCollector $collector) {
$collector->addRoute(['GET', 'POST'], '[/]', Module\Install::class);
$collector->addRoute(['GET'], '/testrewrite', Module\Install::class);
});
$this->routeCollector->addRoute(['GET'], '/like/{item:\d+}', Module\Like::class);
$this->routeCollector->addRoute(['GET', 'POST'], '/localtime', Module\Debug\Localtime::class);
$this->routeCollector->addRoute(['GET', 'POST'], '/login', Module\Login::class);
$this->routeCollector->addRoute(['GET', 'POST'], '/logout', Module\Logout::class);
$this->routeCollector->addRoute(['GET'], '/magic', Module\Magic::class);
$this->routeCollector->addRoute(['GET'], '/maintenance', Module\Maintenance::class);
$this->routeCollector->addRoute(['GET'], '/manifest', Module\Manifest::class);
$this->routeCollector->addRoute(['GET'], '/modexp/{nick}', Module\PublicRSAKey::class);
$this->routeCollector->addRoute(['GET'], '/newmember', Module\Welcome::class);
$this->routeCollector->addRoute(['GET'], '/nodeinfo/1.0', Module\NodeInfo::class);
$this->routeCollector->addRoute(['GET'], '/nogroup', Module\Group::class);
$this->routeCollector->addGroup('/notify', function (RouteCollector $collector) {
$collector->addRoute(['GET'], '[/]', Module\Notifications\Notify::class);
$collector->addRoute(['GET'], '/view/{id:\d+}', Module\Notifications\Notify::class);
$collector->addRoute(['GET'], '/mark/all', Module\Notifications\Notify::class);
});
$this->routeCollector->addRoute(['GET'], '/objects/{guid}', Module\Objects::class);
$this->routeCollector->addGroup('/oembed', function (RouteCollector $collector) {
$collector->addRoute(['GET'], '/b2h', Module\Oembed::class);
$collector->addRoute(['GET'], '/h2b', Module\Oembed::class);
$collector->addRoute(['GET'], '/{hash}', Module\Oembed::class);
});
$this->routeCollector->addRoute(['GET'], '/outbox/{owner}', Module\Outbox::class);
$this->routeCollector->addRoute(['GET'], '/owa', Module\Owa::class);
$this->routeCollector->addRoute(['GET'], '/opensearch', Module\OpenSearch::class);
$this->routeCollector->addGroup('/photo', function (RouteCollector $collector) {
$collector->addRoute(['GET'], '/{name}', Module\Photo::class);
$collector->addRoute(['GET'], '/{type}/{name}', Module\Photo::class);
$collector->addRoute(['GET'], '/{type}/{customize}/{name}', Module\Photo::class);
});
$this->routeCollector->addRoute(['GET'], '/pretheme', Module\ThemeDetails::class);
$this->routeCollector->addRoute(['GET'], '/probe', Module\Debug\Probe::class);
$this->routeCollector->addGroup('/profile', function (RouteCollector $collector) {
$collector->addRoute(['GET'], '/{nickname}', Module\Profile::class);
$collector->addRoute(['GET'], '/{nickname}/{to:\d{4}-\d{2}-\d{2}}/{from:\d{4}-\d{2}-\d{2}}', Module\Profile::class);
$collector->addRoute(['GET'], '/{nickname}/contacts[/{type}]', Module\Profile\Contacts::class);
$collector->addRoute(['GET'], '/{profile:\d+}/view', Module\Profile::class);
});
$this->routeCollector->addGroup('/proxy', function (RouteCollector $collector) {
$collector->addRoute(['GET'], '[/]' , Module\Proxy::class);
$collector->addRoute(['GET'], '/{url}' , Module\Proxy::class);
$collector->addRoute(['GET'], '/{sub1}/{url}' , Module\Proxy::class);
$collector->addRoute(['GET'], '/{sub1}/{sub2}/{url}' , Module\Proxy::class);
});
$this->routeCollector->addGroup('/settings', function (RouteCollector $collector) {
$collector->addGroup('/2fa', function (RouteCollector $collector) {
$collector->addRoute(['GET', 'POST'], '[/]' , Module\Settings\TwoFactor\Index::class);
$collector->addRoute(['GET', 'POST'], '/recovery' , Module\Settings\TwoFactor\Recovery::class);
$collector->addRoute(['GET', 'POST'], '/app_specific' , Module\Settings\TwoFactor\AppSpecific::class);
$collector->addRoute(['GET', 'POST'], '/verify' , Module\Settings\TwoFactor\Verify::class);
});
});
$this->routeCollector->addRoute(['GET'], '/randprof', Module\RandomProfile::class);
$this->routeCollector->addRoute(['GET', 'POST'], '/register', Module\Register::class);
$this->routeCollector->addRoute(['GET'], '/robots.txt', Module\RobotsTxt::class);
$this->routeCollector->addRoute(['GET'], '/rsd.xml', Module\ReallySimpleDiscovery::class);
$this->routeCollector->addRoute(['GET'], '/smilies[/json]', Module\Smilies::class);
$this->routeCollector->addRoute(['GET'], '/statistics.json', Module\Statistics::class);
$this->routeCollector->addRoute(['GET'], '/starred/{item:\d+}', Module\Starred::class);
$this->routeCollector->addRoute(['GET'], '/toggle_mobile', Module\ToggleMobile::class);
$this->routeCollector->addRoute(['GET'], '/tos', Module\Tos::class);
$this->routeCollector->addRoute(['GET'], '/view/theme/{theme}/style.pcss', Module\Theme::class);
$this->routeCollector->addRoute(['GET'], '/viewsrc/{item:\d+}', Module\Debug\ItemBody::class);
$this->routeCollector->addRoute(['GET'], '/webfinger', Module\Debug\WebFinger::class);
$this->routeCollector->addRoute(['GET'], '/xrd', Module\Xrd::class);
} }
public function __construct() /**
* @param array $routes The routes to add to the Router
*
* @return self The router instance with the loaded routes
*
* @throws HTTPException\InternalServerErrorException In case of invalid configs
*/
public function addRoutes(array $routes)
{ {
$this->routeCollector = new RouteCollector(new Std(), new GroupCountBased()); $routeCollector = (isset($this->routeCollector) ?
$this->routeCollector :
new RouteCollector(new Std(), new GroupCountBased()));
foreach ($routes as $route => $config) {
if ($this->isGroup($config)) {
$this->addGroup($route, $config, $routeCollector);
} elseif ($this->isRoute($config)) {
$routeCollector->addRoute($config[1], $route, $config[0]);
} else {
throw new HTTPException\InternalServerErrorException("Wrong route config for route '" . print_r($route, true) . "'");
}
} }
$this->routeCollector = $routeCollector;
return $this;
}
/**
* Adds a group of routes to a given group
*
* @param string $groupRoute The route of the group
* @param array $routes The routes of the group
* @param RouteCollector $routeCollector The route collector to add this group
*/
private function addGroup(string $groupRoute, array $routes, RouteCollector $routeCollector)
{
$routeCollector->addGroup($groupRoute, function (RouteCollector $routeCollector) use ($routes) {
foreach ($routes as $route => $config) {
if ($this->isGroup($config)) {
$this->addGroup($route, $config, $routeCollector);
} elseif ($this->isRoute($config)) {
$routeCollector->addRoute($config[1], $route, $config[0]);
}else {
throw new HTTPException\InternalServerErrorException("Wrong route config for route '" . print_r($route, true) . "'");
}
}
});
}
/**
* Returns true in case the config is a group config
*
* @param array $config
*
* @return bool
*/
private function isGroup(array $config)
{
return
is_array($config) &&
is_string(array_keys($config)[0]) &&
// This entry should NOT be a BaseModule
(substr(array_keys($config)[0], 0, strlen('Friendica\Module')) !== 'Friendica\Module') &&
// The second argument is an array (another routes)
is_array(array_values($config)[0]);
}
/**
* Returns true in case the config is a route config
*
* @param array $config
*
* @return bool
*/
private function isRoute(array $config)
{
return
// The config array should at least have one entry
!empty($config[0]) &&
// This entry should be a BaseModule
(substr($config[0], 0, strlen('Friendica\Module')) === 'Friendica\Module') &&
// Either there is no other argument
(empty($config[1]) ||
// Or the second argument is an array (HTTP-Methods)
is_array($config[1]));
}
/**
* The current route collector
*
* @return RouteCollector|null
*/
public function getRouteCollector() public function getRouteCollector()
{ {
return $this->routeCollector; return $this->routeCollector;
@ -236,21 +155,31 @@ class Router
* Returns the relevant module class name for the given page URI or NULL if no route rule matched. * Returns the relevant module class name for the given page URI or NULL if no route rule matched.
* *
* @param string $cmd The path component of the request URL without the query string * @param string $cmd The path component of the request URL without the query string
* @return string|null A Friendica\BaseModule-extending class name if a route rule matched *
* @return string A Friendica\BaseModule-extending class name if a route rule matched
*
* @throws HTTPException\InternalServerErrorException
* @throws HTTPException\MethodNotAllowedException If a rule matched but the method didn't
* @throws HTTPException\NotFoundException If no rule matched
*/ */
public function getModuleClass($cmd) public function getModuleClass($cmd)
{ {
// Add routes from addons
Hook::callAll('route_collection', $this->routeCollector);
$cmd = '/' . ltrim($cmd, '/'); $cmd = '/' . ltrim($cmd, '/');
$dispatcher = new \FastRoute\Dispatcher\GroupCountBased($this->routeCollector->getData()); $dispatcher = new \FastRoute\Dispatcher\GroupCountBased($this->routeCollector->getData());
$moduleClass = null; $moduleClass = null;
// @TODO: Enable method-specific modules $routeInfo = $dispatcher->dispatch($this->httpMethod, $cmd);
$httpMethod = 'GET';
$routeInfo = $dispatcher->dispatch($httpMethod, $cmd);
if ($routeInfo[0] === Dispatcher::FOUND) { if ($routeInfo[0] === Dispatcher::FOUND) {
$moduleClass = $routeInfo[1]; $moduleClass = $routeInfo[1];
} elseif ($routeInfo[0] === Dispatcher::METHOD_NOT_ALLOWED) {
throw new HTTPException\MethodNotAllowedException(L10n::t('Method not allowed for this module. Allowed method(s): %s', implode(', ', $routeInfo[1])));
} else {
throw new HTTPException\NotFoundException(L10n::t('Page not found.'));
} }
return $moduleClass; return $moduleClass;

View file

@ -4,7 +4,6 @@ namespace Friendica;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Core\Logger; use Friendica\Core\Logger;
use Friendica\Core\System;
/** /**
* All modules in Friendica should extend BaseModule, although not all modules * All modules in Friendica should extend BaseModule, although not all modules
@ -121,7 +120,7 @@ abstract class BaseModule extends BaseObject
$a = \get_app(); $a = \get_app();
$x = explode('.', $hash); $x = explode('.', $hash);
if (time() > (IntVal($x[0]) + $max_livetime)) { if (time() > (intval($x[0]) + $max_livetime)) {
return false; return false;
} }

View file

@ -129,16 +129,13 @@ HELP;
$config_file = $this->getOption(['f', 'file']); $config_file = $this->getOption(['f', 'file']);
if (!empty($config_file)) { if (!empty($config_file)) {
if ($config_file != 'config' . DIRECTORY_SEPARATOR . 'local.config.php') {
// Copy config file if (!file_exists($config_file)) {
$this->out("Copying config file...\n"); throw new RuntimeException("ERROR: Config file does not exist.\n");
if (!copy($basePathConf . DIRECTORY_SEPARATOR . $config_file, $basePathConf . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'local.config.php')) {
throw new RuntimeException("ERROR: Saving config file failed. Please copy '$config_file' to '" . $basePathConf . "'" . DIRECTORY_SEPARATOR . "config" . DIRECTORY_SEPARATOR . "local.config.php' manually.\n");
}
} }
//reload the config cache //reload the config cache
$loader = new ConfigFileLoader($basePathConf); $loader = new ConfigFileLoader($config_file);
$loader->setupCache($configCache); $loader->setupCache($configCache);
} else { } else {
@ -219,6 +216,14 @@ HELP;
throw new RuntimeException($errorMessage); throw new RuntimeException($errorMessage);
} }
if (!empty($config_file) && $config_file != 'config' . DIRECTORY_SEPARATOR . 'local.config.php') {
// Copy config file
$this->out("Copying config file...\n");
if (!copy($basePathConf . DIRECTORY_SEPARATOR . $config_file, $basePathConf . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'local.config.php')) {
throw new RuntimeException("ERROR: Saving config file failed. Please copy '$config_file' to '" . $basePathConf . "'" . DIRECTORY_SEPARATOR . "config" . DIRECTORY_SEPARATOR . "local.config.php' manually.\n");
}
}
$this->out(" Complete!\n\n"); $this->out(" Complete!\n\n");
// Install theme // Install theme

View file

@ -43,7 +43,7 @@ class ForumManager
$params = ['order' => ['name']]; $params = ['order' => ['name']];
} }
$condition_str = "`network` = ? AND `uid` = ? AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND "; $condition_str = "`network` IN (?, ?) AND `uid` = ? AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND ";
if ($showprivate) { if ($showprivate) {
$condition_str .= '(`forum` OR `prv`)'; $condition_str .= '(`forum` OR `prv`)';
@ -58,7 +58,7 @@ class ForumManager
$forumlist = []; $forumlist = [];
$fields = ['id', 'url', 'name', 'micro', 'thumb']; $fields = ['id', 'url', 'name', 'micro', 'thumb'];
$condition = [$condition_str, Protocol::DFRN, $uid]; $condition = [$condition_str, Protocol::DFRN, Protocol::ACTIVITYPUB, $uid];
$contacts = DBA::select('contact', $fields, $condition, $params); $contacts = DBA::select('contact', $fields, $condition, $params);
if (!$contacts) { if (!$contacts) {
return($forumlist); return($forumlist);

View file

@ -29,7 +29,7 @@ class Nav
'directory' => null, 'directory' => null,
'settings' => null, 'settings' => null,
'contacts' => null, 'contacts' => null,
'manage' => null, 'delegation'=> null,
'events' => null, 'events' => null,
'register' => null 'register' => null
]; ];
@ -149,7 +149,7 @@ class Nav
$nav['usermenu'] = []; $nav['usermenu'] = [];
$userinfo = null; $userinfo = null;
if (local_user() || remote_user()) { if (Session::isAuthenticated()) {
$nav['logout'] = ['logout', L10n::t('Logout'), '', L10n::t('End this session')]; $nav['logout'] = ['logout', L10n::t('Logout'), '', L10n::t('End this session')];
} else { } else {
$nav['login'] = ['login', L10n::t('Login'), ($a->module == 'login' ? 'selected' : ''), L10n::t('Sign in')]; $nav['login'] = ['login', L10n::t('Login'), ($a->module == 'login' ? 'selected' : ''), L10n::t('Sign in')];
@ -182,7 +182,7 @@ class Nav
$nav['home'] = [$homelink, L10n::t('Home'), '', L10n::t('Home Page')]; $nav['home'] = [$homelink, L10n::t('Home'), '', L10n::t('Home Page')];
} }
if (intval(Config::get('config', 'register_policy')) === \Friendica\Module\Register::OPEN && !local_user() && !remote_user()) { if (intval(Config::get('config', 'register_policy')) === \Friendica\Module\Register::OPEN && !Session::isAuthenticated()) {
$nav['register'] = ['register', L10n::t('Register'), '', L10n::t('Create an account')]; $nav['register'] = ['register', L10n::t('Register'), '', L10n::t('Create an account')];
} }
@ -257,11 +257,9 @@ class Nav
$nav['messages']['new'] = ['message/new', L10n::t('New Message'), '', L10n::t('New Message')]; $nav['messages']['new'] = ['message/new', L10n::t('New Message'), '', L10n::t('New Message')];
if (is_array($a->identities) && count($a->identities) > 1) { if (is_array($a->identities) && count($a->identities) > 1) {
$nav['manage'] = ['manage', L10n::t('Manage'), '', L10n::t('Manage other pages')]; $nav['delegation'] = ['delegation', L10n::t('Delegation'), '', L10n::t('Manage other pages')];
} }
$nav['delegations'] = ['delegate', L10n::t('Delegations'), '', L10n::t('Delegate Page Management')];
$nav['settings'] = ['settings', L10n::t('Settings'), '', L10n::t('Account settings')]; $nav['settings'] = ['settings', L10n::t('Settings'), '', L10n::t('Account settings')];
if (Feature::isEnabled(local_user(), 'multi_profiles')) { if (Feature::isEnabled(local_user(), 'multi_profiles')) {

View file

@ -39,7 +39,7 @@ class Pager
{ {
$this->setQueryString($queryString); $this->setQueryString($queryString);
$this->setItemsPerPage($itemsPerPage); $this->setItemsPerPage($itemsPerPage);
$this->setPage(defaults($_GET, 'page', 1)); $this->setPage(($_GET['page'] ?? 0) ?: 1);
} }
/** /**

View file

@ -38,7 +38,7 @@ class BBCode extends BaseObject
* *
* @param string $body Message body * @param string $body Message body
* @return array * @return array
* 'type' -> Message type ("link", "video", "photo") * 'type' -> Message type ('link', 'video', 'photo')
* 'text' -> Text before the shared message * 'text' -> Text before the shared message
* 'after' -> Text after the shared message * 'after' -> Text after the shared message
* 'image' -> Preview image of the message * 'image' -> Preview image of the message
@ -56,19 +56,19 @@ class BBCode extends BaseObject
if (preg_match_all("(\[class=(.*?)\](.*?)\[\/class\])ism", $body, $attached, PREG_SET_ORDER)) { if (preg_match_all("(\[class=(.*?)\](.*?)\[\/class\])ism", $body, $attached, PREG_SET_ORDER)) {
foreach ($attached as $data) { foreach ($attached as $data) {
if (!in_array($data[1], ["type-link", "type-video", "type-photo"])) { if (!in_array($data[1], ['type-link', 'type-video', 'type-photo'])) {
continue; continue;
} }
$post["type"] = substr($data[1], 5); $post['type'] = substr($data[1], 5);
$pos = strpos($body, $data[0]); $pos = strpos($body, $data[0]);
if ($pos > 0) { if ($pos > 0) {
$post["text"] = trim(substr($body, 0, $pos)); $post['text'] = trim(substr($body, 0, $pos));
$post["after"] = trim(substr($body, $pos + strlen($data[0]))); $post['after'] = trim(substr($body, $pos + strlen($data[0])));
} else { } else {
$post["text"] = trim(str_replace($data[0], "", $body)); $post['text'] = trim(str_replace($data[0], '', $body));
$post["after"] = ''; $post['after'] = '';
} }
$attacheddata = $data[2]; $attacheddata = $data[2];
@ -79,25 +79,25 @@ class BBCode extends BaseObject
if ($picturedata) { if ($picturedata) {
if (($picturedata[0] >= 500) && ($picturedata[0] >= $picturedata[1])) { if (($picturedata[0] >= 500) && ($picturedata[0] >= $picturedata[1])) {
$post["image"] = $matches[1]; $post['image'] = $matches[1];
} else { } else {
$post["preview"] = $matches[1]; $post['preview'] = $matches[1];
} }
} }
} }
if (preg_match("/\[bookmark\=(.*?)\](.*?)\[\/bookmark\]/ism", $attacheddata, $matches)) { if (preg_match("/\[bookmark\=(.*?)\](.*?)\[\/bookmark\]/ism", $attacheddata, $matches)) {
$post["url"] = $matches[1]; $post['url'] = $matches[1];
$post["title"] = $matches[2]; $post['title'] = $matches[2];
} }
if (!empty($post["url"]) && (in_array($post["type"], ["link", "video"])) if (!empty($post['url']) && (in_array($post['type'], ['link', 'video']))
&& preg_match("/\[url\=(.*?)\](.*?)\[\/url\]/ism", $attacheddata, $matches)) { && preg_match("/\[url\=(.*?)\](.*?)\[\/url\]/ism", $attacheddata, $matches)) {
$post["url"] = $matches[1]; $post['url'] = $matches[1];
} }
// Search for description // Search for description
if (preg_match("/\[quote\](.*?)\[\/quote\]/ism", $attacheddata, $matches)) { if (preg_match("/\[quote\](.*?)\[\/quote\]/ism", $attacheddata, $matches)) {
$post["description"] = $matches[1]; $post['description'] = $matches[1];
} }
} }
} }
@ -109,7 +109,7 @@ class BBCode extends BaseObject
* *
* @param string $body Message body * @param string $body Message body
* @return array * @return array
* 'type' -> Message type ("link", "video", "photo") * 'type' -> Message type ('link', 'video', 'photo')
* 'text' -> Text before the shared message * 'text' -> Text before the shared message
* 'after' -> Text after the shared message * 'after' -> Text after the shared message
* 'image' -> Preview image of the message * 'image' -> Preview image of the message
@ -136,9 +136,9 @@ class BBCode extends BaseObject
$attributes = $match[2]; $attributes = $match[2];
$data["text"] = trim($match[1]); $data['text'] = trim($match[1]);
$type = ""; $type = '';
preg_match("/type='(.*?)'/ism", $attributes, $matches); preg_match("/type='(.*?)'/ism", $attributes, $matches);
if (!empty($matches[1])) { if (!empty($matches[1])) {
$type = strtolower($matches[1]); $type = strtolower($matches[1]);
@ -149,19 +149,19 @@ class BBCode extends BaseObject
$type = strtolower($matches[1]); $type = strtolower($matches[1]);
} }
if ($type == "") { if ($type == '') {
return []; return [];
} }
if (!in_array($type, ["link", "audio", "photo", "video"])) { if (!in_array($type, ['link', 'audio', 'photo', 'video'])) {
return []; return [];
} }
if ($type != "") { if ($type != '') {
$data["type"] = $type; $data['type'] = $type;
} }
$url = ""; $url = '';
preg_match("/url='(.*?)'/ism", $attributes, $matches); preg_match("/url='(.*?)'/ism", $attributes, $matches);
if (!empty($matches[1])) { if (!empty($matches[1])) {
$url = $matches[1]; $url = $matches[1];
@ -172,11 +172,11 @@ class BBCode extends BaseObject
$url = $matches[1]; $url = $matches[1];
} }
if ($url != "") { if ($url != '') {
$data["url"] = html_entity_decode($url, ENT_QUOTES, 'UTF-8'); $data['url'] = html_entity_decode($url, ENT_QUOTES, 'UTF-8');
} }
$title = ""; $title = '';
preg_match("/title='(.*?)'/ism", $attributes, $matches); preg_match("/title='(.*?)'/ism", $attributes, $matches);
if (!empty($matches[1])) { if (!empty($matches[1])) {
$title = $matches[1]; $title = $matches[1];
@ -187,14 +187,14 @@ class BBCode extends BaseObject
$title = $matches[1]; $title = $matches[1];
} }
if ($title != "") { if ($title != '') {
$title = self::convert(html_entity_decode($title, ENT_QUOTES, 'UTF-8'), false, true); $title = self::convert(html_entity_decode($title, ENT_QUOTES, 'UTF-8'), false, true);
$title = html_entity_decode($title, ENT_QUOTES, 'UTF-8'); $title = html_entity_decode($title, ENT_QUOTES, 'UTF-8');
$title = str_replace(["[", "]"], ["&#91;", "&#93;"], $title); $title = str_replace(['[', ']'], ['&#91;', '&#93;'], $title);
$data["title"] = $title; $data['title'] = $title;
} }
$image = ""; $image = '';
preg_match("/image='(.*?)'/ism", $attributes, $matches); preg_match("/image='(.*?)'/ism", $attributes, $matches);
if (!empty($matches[1])) { if (!empty($matches[1])) {
$image = $matches[1]; $image = $matches[1];
@ -205,11 +205,11 @@ class BBCode extends BaseObject
$image = $matches[1]; $image = $matches[1];
} }
if ($image != "") { if ($image != '') {
$data["image"] = html_entity_decode($image, ENT_QUOTES, 'UTF-8'); $data['image'] = html_entity_decode($image, ENT_QUOTES, 'UTF-8');
} }
$preview = ""; $preview = '';
preg_match("/preview='(.*?)'/ism", $attributes, $matches); preg_match("/preview='(.*?)'/ism", $attributes, $matches);
if (!empty($matches[1])) { if (!empty($matches[1])) {
$preview = $matches[1]; $preview = $matches[1];
@ -220,13 +220,13 @@ class BBCode extends BaseObject
$preview = $matches[1]; $preview = $matches[1];
} }
if ($preview != "") { if ($preview != '') {
$data["preview"] = html_entity_decode($preview, ENT_QUOTES, 'UTF-8'); $data['preview'] = html_entity_decode($preview, ENT_QUOTES, 'UTF-8');
} }
$data["description"] = trim($match[3]); $data['description'] = trim($match[3]);
$data["after"] = trim($match[4]); $data['after'] = trim($match[4]);
return $data; return $data;
} }
@ -244,7 +244,7 @@ class BBCode extends BaseObject
*/ */
$has_title = !empty($item['title']); $has_title = !empty($item['title']);
$plink = defaults($item, 'plink', ''); $plink = $item['plink'] ?? '';
$post = self::getAttachmentData($body); $post = self::getAttachmentData($body);
// Get all linked images with alternative image description // Get all linked images with alternative image description
@ -268,11 +268,11 @@ class BBCode extends BaseObject
} }
// if nothing is found, it maybe having an image. // if nothing is found, it maybe having an image.
if (!isset($post["type"])) { if (!isset($post['type'])) {
// Simplify image codes // Simplify image codes
$body = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $body); $body = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $body);
$body = preg_replace("/\[img\=(.*?)\](.*?)\[\/img\]/ism", '[img]$1[/img]', $body); $body = preg_replace("/\[img\=(.*?)\](.*?)\[\/img\]/ism", '[img]$1[/img]', $body);
$post["text"] = $body; $post['text'] = $body;
if (preg_match_all("(\[url=(.*?)\]\s*\[img\](.*?)\[\/img\]\s*\[\/url\])ism", $body, $pictures, PREG_SET_ORDER)) { if (preg_match_all("(\[url=(.*?)\]\s*\[img\](.*?)\[\/img\]\s*\[\/url\])ism", $body, $pictures, PREG_SET_ORDER)) {
if ((count($pictures) == 1) && !$has_title) { if ((count($pictures) == 1) && !$has_title) {
@ -288,75 +288,75 @@ class BBCode extends BaseObject
// Workaround: // Workaround:
// Sometimes photo posts to the own album are not detected at the start. // Sometimes photo posts to the own album are not detected at the start.
// So we seem to cannot use the cache for these cases. That's strange. // So we seem to cannot use the cache for these cases. That's strange.
if (($data["type"] != "photo") && strstr($pictures[0][1], "/photos/")) { if (($data['type'] != 'photo') && strstr($pictures[0][1], "/photos/")) {
$data = ParseUrl::getSiteinfo($pictures[0][1], true); $data = ParseUrl::getSiteinfo($pictures[0][1], true);
} }
if ($data["type"] == "photo") { if ($data['type'] == 'photo') {
$post["type"] = "photo"; $post['type'] = 'photo';
if (isset($data["images"][0])) { if (isset($data['images'][0])) {
$post["image"] = $data["images"][0]["src"]; $post['image'] = $data['images'][0]['src'];
$post["url"] = $data["url"]; $post['url'] = $data['url'];
} else { } else {
$post["image"] = $data["url"]; $post['image'] = $data['url'];
} }
$post["preview"] = $pictures[0][2]; $post['preview'] = $pictures[0][2];
$post["text"] = trim(str_replace($pictures[0][0], "", $body)); $post['text'] = trim(str_replace($pictures[0][0], '', $body));
} else { } else {
$imgdata = Image::getInfoFromURL($pictures[0][1]); $imgdata = Image::getInfoFromURL($pictures[0][1]);
if ($imgdata && substr($imgdata["mime"], 0, 6) == "image/") { if ($imgdata && substr($imgdata['mime'], 0, 6) == 'image/') {
$post["type"] = "photo"; $post['type'] = 'photo';
$post["image"] = $pictures[0][1]; $post['image'] = $pictures[0][1];
$post["preview"] = $pictures[0][2]; $post['preview'] = $pictures[0][2];
$post["text"] = trim(str_replace($pictures[0][0], "", $body)); $post['text'] = trim(str_replace($pictures[0][0], '', $body));
} }
} }
} elseif (count($pictures) > 0) { } elseif (count($pictures) > 0) {
$post["type"] = "link"; $post['type'] = 'link';
$post["url"] = $plink; $post['url'] = $plink;
$post["image"] = $pictures[0][2]; $post['image'] = $pictures[0][2];
$post["text"] = $body; $post['text'] = $body;
foreach ($pictures as $picture) { foreach ($pictures as $picture) {
$post["text"] = trim(str_replace($picture[0], "", $post["text"])); $post['text'] = trim(str_replace($picture[0], '', $post['text']));
} }
} }
} elseif (preg_match_all("(\[img\](.*?)\[\/img\])ism", $body, $pictures, PREG_SET_ORDER)) { } elseif (preg_match_all("(\[img\](.*?)\[\/img\])ism", $body, $pictures, PREG_SET_ORDER)) {
if ((count($pictures) == 1) && !$has_title) { if ((count($pictures) == 1) && !$has_title) {
$post["type"] = "photo"; $post['type'] = 'photo';
$post["image"] = $pictures[0][1]; $post['image'] = $pictures[0][1];
$post["text"] = str_replace($pictures[0][0], "", $body); $post['text'] = str_replace($pictures[0][0], '', $body);
} elseif (count($pictures) > 0) { } elseif (count($pictures) > 0) {
$post["type"] = "link"; $post['type'] = 'link';
$post["url"] = $plink; $post['url'] = $plink;
$post["image"] = $pictures[0][1]; $post['image'] = $pictures[0][1];
$post["text"] = $body; $post['text'] = $body;
foreach ($pictures as $picture) { foreach ($pictures as $picture) {
$post["text"] = trim(str_replace($picture[0], "", $post["text"])); $post['text'] = trim(str_replace($picture[0], '', $post['text']));
} }
} }
} }
// Test for the external links // Test for the external links
preg_match_all("(\[url\](.*?)\[\/url\])ism", $post["text"], $links1, PREG_SET_ORDER); preg_match_all("(\[url\](.*?)\[\/url\])ism", $post['text'], $links1, PREG_SET_ORDER);
preg_match_all("(\[url\=(.*?)\].*?\[\/url\])ism", $post["text"], $links2, PREG_SET_ORDER); preg_match_all("(\[url\=(.*?)\].*?\[\/url\])ism", $post['text'], $links2, PREG_SET_ORDER);
$links = array_merge($links1, $links2); $links = array_merge($links1, $links2);
// If there is only a single one, then use it. // If there is only a single one, then use it.
// This should cover link posts via API. // This should cover link posts via API.
if ((count($links) == 1) && !isset($post["preview"]) && !$has_title) { if ((count($links) == 1) && !isset($post['preview']) && !$has_title) {
$post["type"] = "link"; $post['type'] = 'link';
$post["url"] = $links[0][1]; $post['url'] = $links[0][1];
} }
// Now count the number of external media links // Now count the number of external media links
preg_match_all("(\[vimeo\](.*?)\[\/vimeo\])ism", $post["text"], $links1, PREG_SET_ORDER); preg_match_all("(\[vimeo\](.*?)\[\/vimeo\])ism", $post['text'], $links1, PREG_SET_ORDER);
preg_match_all("(\[youtube\\](.*?)\[\/youtube\\])ism", $post["text"], $links2, PREG_SET_ORDER); preg_match_all("(\[youtube\\](.*?)\[\/youtube\\])ism", $post['text'], $links2, PREG_SET_ORDER);
preg_match_all("(\[video\\](.*?)\[\/video\\])ism", $post["text"], $links3, PREG_SET_ORDER); preg_match_all("(\[video\\](.*?)\[\/video\\])ism", $post['text'], $links3, PREG_SET_ORDER);
preg_match_all("(\[audio\\](.*?)\[\/audio\\])ism", $post["text"], $links4, PREG_SET_ORDER); preg_match_all("(\[audio\\](.*?)\[\/audio\\])ism", $post['text'], $links4, PREG_SET_ORDER);
// Add them to the other external links // Add them to the other external links
$links = array_merge($links, $links1, $links2, $links3, $links4); $links = array_merge($links, $links1, $links2, $links3, $links4);
@ -364,19 +364,19 @@ class BBCode extends BaseObject
// Are there more than one? // Are there more than one?
if (count($links) > 1) { if (count($links) > 1) {
// The post will be the type "text", which means a blog post // The post will be the type "text", which means a blog post
unset($post["type"]); unset($post['type']);
$post["url"] = $plink; $post['url'] = $plink;
} }
if (!isset($post["type"])) { if (!isset($post['type'])) {
$post["type"] = "text"; $post['type'] = "text";
$post["text"] = trim($body); $post['text'] = trim($body);
} }
} elseif (isset($post["url"]) && ($post["type"] == "video")) { } elseif (isset($post['url']) && ($post['type'] == 'video')) {
$data = ParseUrl::getSiteinfoCached($post["url"], true); $data = ParseUrl::getSiteinfoCached($post['url'], true);
if (isset($data["images"][0])) { if (isset($data['images'][0])) {
$post["image"] = $data["images"][0]["src"]; $post['image'] = $data['images'][0]['src'];
} }
} }
@ -581,27 +581,27 @@ class BBCode extends BaseObject
private static function convertAttachment($return, $simplehtml = false, $tryoembed = true) private static function convertAttachment($return, $simplehtml = false, $tryoembed = true)
{ {
$data = self::getAttachmentData($return); $data = self::getAttachmentData($return);
if (empty($data) || empty($data["url"])) { if (empty($data) || empty($data['url'])) {
return $return; return $return;
} }
if (isset($data["title"])) { if (isset($data['title'])) {
$data["title"] = strip_tags($data["title"]); $data['title'] = strip_tags($data['title']);
$data["title"] = str_replace(["http://", "https://"], "", $data["title"]); $data['title'] = str_replace(['http://', 'https://'], '', $data['title']);
} else { } else {
$data["title"] = null; $data['title'] = null;
} }
if (((strpos($data["text"], "[img=") !== false) || (strpos($data["text"], "[img]") !== false) || Config::get('system', 'always_show_preview')) && !empty($data["image"])) { if (((strpos($data['text'], "[img=") !== false) || (strpos($data['text'], "[img]") !== false) || Config::get('system', 'always_show_preview')) && !empty($data['image'])) {
$data["preview"] = $data["image"]; $data['preview'] = $data['image'];
$data["image"] = ""; $data['image'] = '';
} }
$return = ''; $return = '';
if (in_array($simplehtml, [7, 9])) { if (in_array($simplehtml, [7, 9])) {
$return = self::convertUrlForOStatus($data["url"]); $return = self::convertUrlForActivityPub($data['url']);
} elseif (($simplehtml != 4) && ($simplehtml != 0)) { } elseif (($simplehtml != 4) && ($simplehtml != 0)) {
$return = sprintf('<a href="%s" target="_blank">%s</a><br>', $data["url"], $data["title"]); $return = sprintf('<a href="%s" target="_blank">%s</a><br>', $data['url'], $data['title']);
} else { } else {
try { try {
if ($tryoembed && OEmbed::isAllowedURL($data['url'])) { if ($tryoembed && OEmbed::isAllowedURL($data['url'])) {
@ -610,28 +610,28 @@ class BBCode extends BaseObject
throw new Exception('OEmbed is disabled for this attachment.'); throw new Exception('OEmbed is disabled for this attachment.');
} }
} catch (Exception $e) { } catch (Exception $e) {
$data["title"] = defaults($data, 'title', $data['url']); $data['title'] = ($data['title'] ?? '') ?: $data['url'];
if ($simplehtml != 4) { if ($simplehtml != 4) {
$return = sprintf('<div class="type-%s">', $data["type"]); $return = sprintf('<div class="type-%s">', $data['type']);
} }
if (!empty($data['title']) && !empty($data['url'])) { if (!empty($data['title']) && !empty($data['url'])) {
if (!empty($data["image"]) && empty($data["text"]) && ($data["type"] == "photo")) { if (!empty($data['image']) && empty($data['text']) && ($data['type'] == 'photo')) {
$return .= sprintf('<a href="%s" target="_blank"><img src="%s" alt="" title="%s" class="attachment-image" /></a>', $data["url"], self::proxyUrl($data["image"], $simplehtml), $data["title"]); $return .= sprintf('<a href="%s" target="_blank"><img src="%s" alt="" title="%s" class="attachment-image" /></a>', $data['url'], self::proxyUrl($data['image'], $simplehtml), $data['title']);
} else { } else {
if (!empty($data["image"])) { if (!empty($data['image'])) {
$return .= sprintf('<a href="%s" target="_blank"><img src="%s" alt="" title="%s" class="attachment-image" /></a><br />', $data["url"], self::proxyUrl($data["image"], $simplehtml), $data["title"]); $return .= sprintf('<a href="%s" target="_blank"><img src="%s" alt="" title="%s" class="attachment-image" /></a><br />', $data['url'], self::proxyUrl($data['image'], $simplehtml), $data['title']);
} elseif (!empty($data["preview"])) { } elseif (!empty($data['preview'])) {
$return .= sprintf('<a href="%s" target="_blank"><img src="%s" alt="" title="%s" class="attachment-preview" /></a><br />', $data["url"], self::proxyUrl($data["preview"], $simplehtml), $data["title"]); $return .= sprintf('<a href="%s" target="_blank"><img src="%s" alt="" title="%s" class="attachment-preview" /></a><br />', $data['url'], self::proxyUrl($data['preview'], $simplehtml), $data['title']);
} }
$return .= sprintf('<h4><a href="%s">%s</a></h4>', $data['url'], $data['title']); $return .= sprintf('<h4><a href="%s">%s</a></h4>', $data['url'], $data['title']);
} }
} }
if (!empty($data["description"]) && $data["description"] != $data["title"]) { if (!empty($data['description']) && $data['description'] != $data['title']) {
// Sanitize the HTML by converting it to BBCode // Sanitize the HTML by converting it to BBCode
$bbcode = HTML::toBBCode($data["description"]); $bbcode = HTML::toBBCode($data['description']);
$return .= sprintf('<blockquote>%s</blockquote>', trim(self::convert($bbcode))); $return .= sprintf('<blockquote>%s</blockquote>', trim(self::convert($bbcode)));
} }
@ -645,7 +645,7 @@ class BBCode extends BaseObject
} }
} }
return trim(defaults($data, 'text', '') . ' ' . $return . ' ' . defaults($data, 'after', '')); return trim(($data['text'] ?? '') . ' ' . $return . ' ' . ($data['after'] ?? ''));
} }
public static function removeShareInformation($Text, $plaintext = false, $nolink = false) public static function removeShareInformation($Text, $plaintext = false, $nolink = false)
@ -655,36 +655,36 @@ class BBCode extends BaseObject
if (!$data) { if (!$data) {
return $Text; return $Text;
} elseif ($nolink) { } elseif ($nolink) {
return $data["text"] . defaults($data, 'after', ''); return $data['text'] . ($data['after'] ?? '');
} }
$title = htmlentities(defaults($data, 'title', ''), ENT_QUOTES, 'UTF-8', false); $title = htmlentities($data['title'] ?? '', ENT_QUOTES, 'UTF-8', false);
$text = htmlentities($data["text"], ENT_QUOTES, 'UTF-8', false); $text = htmlentities($data['text'], ENT_QUOTES, 'UTF-8', false);
if ($plaintext || (($title != "") && strstr($text, $title))) { if ($plaintext || (($title != '') && strstr($text, $title))) {
$data["title"] = $data["url"]; $data['title'] = $data['url'];
} elseif (($text != "") && strstr($title, $text)) { } elseif (($text != '') && strstr($title, $text)) {
$data["text"] = $data["title"]; $data['text'] = $data['title'];
$data["title"] = $data["url"]; $data['title'] = $data['url'];
} }
if (empty($data["text"]) && !empty($data["title"]) && empty($data["url"])) { if (empty($data['text']) && !empty($data['title']) && empty($data['url'])) {
return $data["title"] . $data["after"]; return $data['title'] . $data['after'];
} }
// If the link already is included in the post, don't add it again // If the link already is included in the post, don't add it again
if (!empty($data["url"]) && strpos($data["text"], $data["url"])) { if (!empty($data['url']) && strpos($data['text'], $data['url'])) {
return $data["text"] . $data["after"]; return $data['text'] . $data['after'];
} }
$text = $data["text"]; $text = $data['text'];
if (!empty($data["url"]) && !empty($data["title"])) { if (!empty($data['url']) && !empty($data['title'])) {
$text .= "\n[url=" . $data["url"] . "]" . $data["title"] . "[/url]"; $text .= "\n[url=" . $data['url'] . ']' . $data['title'] . '[/url]';
} elseif (!empty($data["url"])) { } elseif (!empty($data['url'])) {
$text .= "\n[url]" . $data["url"] . "[/url]"; $text .= "\n[url]" . $data['url'] . '[/url]';
} }
return $text . "\n" . $data["after"]; return $text . "\n" . $data['after'];
} }
/** /**
@ -694,7 +694,7 @@ class BBCode extends BaseObject
* @param array $match Array with the matching values * @param array $match Array with the matching values
* @return string reformatted link including HTML codes * @return string reformatted link including HTML codes
*/ */
private static function convertUrlForOStatusCallback($match) private static function convertUrlForActivityPubCallback($match)
{ {
$url = $match[1]; $url = $match[1];
@ -707,15 +707,26 @@ class BBCode extends BaseObject
return $match[0]; return $match[0];
} }
return self::convertUrlForOStatus($url); return self::convertUrlForActivityPub($url);
} }
/** /**
* @brief Converts [url] BBCodes in a format that looks fine on OStatus systems. * @brief Converts [url] BBCodes in a format that looks fine on ActivityPub systems.
* @param string $url URL that is about to be reformatted * @param string $url URL that is about to be reformatted
* @return string reformatted link including HTML codes * @return string reformatted link including HTML codes
*/ */
private static function convertUrlForOStatus($url) private static function convertUrlForActivityPub($url)
{
$html = '<a href="%s" target="_blank">%s</a>';
return sprintf($html, $url, self::getStyledURL($url));
}
/**
* Converts an URL in a nicer format (without the scheme and possibly shortened)
* @param string $url URL that is about to be reformatted
* @return string reformatted link
*/
private static function getStyledURL($url)
{ {
$parts = parse_url($url); $parts = parse_url($url);
$scheme = $parts['scheme'] . '://'; $scheme = $parts['scheme'] . '://';
@ -725,9 +736,7 @@ class BBCode extends BaseObject
$styled_url = substr($styled_url, 0, 30) . ""; $styled_url = substr($styled_url, 0, 30) . "";
} }
$html = '<a href="%s" target="_blank">%s</a>'; return $styled_url;
return sprintf($html, $url, $styled_url);
} }
/* /*
@ -932,7 +941,7 @@ class BBCode extends BaseObject
$attributes = []; $attributes = [];
foreach(['author', 'profile', 'avatar', 'link', 'posted'] as $field) { foreach(['author', 'profile', 'avatar', 'link', 'posted'] as $field) {
preg_match("/$field=(['\"])(.+?)\\1/ism", $attribute_string, $matches); preg_match("/$field=(['\"])(.+?)\\1/ism", $attribute_string, $matches);
$attributes[$field] = html_entity_decode(defaults($matches, 2, ''), ENT_QUOTES, 'UTF-8'); $attributes[$field] = html_entity_decode($matches[2] ?? '', ENT_QUOTES, 'UTF-8');
} }
// We only call this so that a previously unknown contact can be added. // We only call this so that a previously unknown contact can be added.
@ -951,11 +960,11 @@ class BBCode extends BaseObject
Contact::getIdForURL($attributes['profile'], 0, true, $default); Contact::getIdForURL($attributes['profile'], 0, true, $default);
$author_contact = Contact::getDetailsByURL($attributes['profile']); $author_contact = Contact::getDetailsByURL($attributes['profile']);
$author_contact['addr'] = defaults($author_contact, 'addr' , Protocol::getAddrFromProfileUrl($attributes['profile'])); $author_contact['addr'] = ($author_contact['addr'] ?? '') ?: Protocol::getAddrFromProfileUrl($attributes['profile']);
$attributes['author'] = defaults($author_contact, 'name' , $attributes['author']); $attributes['author'] = ($author_contact['name'] ?? '') ?: $attributes['author'];
$attributes['avatar'] = defaults($author_contact, 'micro', $attributes['avatar']); $attributes['avatar'] = ($author_contact['micro'] ?? '') ?: $attributes['avatar'];
$attributes['profile'] = defaults($author_contact, 'url' , $attributes['profile']); $attributes['profile'] = ($author_contact['url'] ?? '') ?: $attributes['profile'];
if ($attributes['avatar']) { if ($attributes['avatar']) {
$attributes['avatar'] = ProxyUtils::proxifyUrl($attributes['avatar'], false, ProxyUtils::SIZE_THUMB); $attributes['avatar'] = ProxyUtils::proxifyUrl($attributes['avatar'], false, ProxyUtils::SIZE_THUMB);
@ -1056,7 +1065,8 @@ class BBCode extends BaseObject
private static function removePictureLinksCallback($match) private static function removePictureLinksCallback($match)
{ {
$text = Cache::get($match[1]); $cache_key = 'remove:' . $match[1];
$text = Cache::get($cache_key);
if (is_null($text)) { if (is_null($text)) {
$a = self::getApp(); $a = self::getApp();
@ -1072,10 +1082,10 @@ class BBCode extends BaseObject
$a->getProfiler()->saveTimestamp($stamp1, "network", System::callstack()); $a->getProfiler()->saveTimestamp($stamp1, "network", System::callstack());
if (substr($curl_info["content_type"], 0, 6) == "image/") { if (substr($curl_info['content_type'], 0, 6) == 'image/') {
$text = "[url=" . $match[1] . "]" . $match[1] . "[/url]"; $text = "[url=" . $match[1] . ']' . $match[1] . "[/url]";
} else { } else {
$text = "[url=" . $match[2] . "]" . $match[2] . "[/url]"; $text = "[url=" . $match[2] . ']' . $match[2] . "[/url]";
// if its not a picture then look if its a page that contains a picture link // if its not a picture then look if its a page that contains a picture link
$body = Network::fetchUrl($match[1]); $body = Network::fetchUrl($match[1]);
@ -1093,12 +1103,12 @@ class BBCode extends BaseObject
} }
} }
if (strtolower($attr["name"]) == "twitter:image") { if (strtolower($attr['name']) == 'twitter:image') {
$text = "[url=" . $attr["content"] . "]" . $attr["content"] . "[/url]"; $text = '[url=' . $attr['content'] . ']' . $attr['content'] . '[/url]';
} }
} }
} }
Cache::set($match[1], $text); Cache::set($cache_key, $text);
} }
return $text; return $text;
@ -1106,7 +1116,7 @@ class BBCode extends BaseObject
private static function expandLinksCallback($match) private static function expandLinksCallback($match)
{ {
if (($match[3] == "") || ($match[2] == $match[3]) || stristr($match[2], $match[3])) { if (($match[3] == '') || ($match[2] == $match[3]) || stristr($match[2], $match[3])) {
return ($match[1] . "[url]" . $match[2] . "[/url]"); return ($match[1] . "[url]" . $match[2] . "[/url]");
} else { } else {
return ($match[1] . $match[3] . " [url]" . $match[2] . "[/url]"); return ($match[1] . $match[3] . " [url]" . $match[2] . "[/url]");
@ -1115,11 +1125,26 @@ class BBCode extends BaseObject
private static function cleanPictureLinksCallback($match) private static function cleanPictureLinksCallback($match)
{ {
$text = Cache::get($match[1]);
if (is_null($text)) {
$a = self::getApp(); $a = self::getApp();
// When the picture link is the own photo path then we can avoid fetching the link
$own_photo_url = preg_quote(Strings::normaliseLink($a->getBaseURL()) . '/photos/');
if (preg_match('|' . $own_photo_url . '.*?/image/|', Strings::normaliseLink($match[1]))) {
if (!empty($match[3])) {
$text = '[img=' . str_replace('-1.', '-0.', $match[2]) . ']' . $match[3] . '[/img]';
} else {
$text = '[img]' . str_replace('-1.', '-0.', $match[2]) . '[/img]';
}
return $text;
}
$cache_key = 'clean:' . $match[1];
$text = Cache::get($cache_key);
if (!is_null($text)) {
return $text;
}
// Only fetch the header, not the content
$stamp1 = microtime(true); $stamp1 = microtime(true);
$ch = @curl_init($match[1]); $ch = @curl_init($match[1]);
@ -1132,13 +1157,13 @@ class BBCode extends BaseObject
$a->getProfiler()->saveTimestamp($stamp1, "network", System::callstack()); $a->getProfiler()->saveTimestamp($stamp1, "network", System::callstack());
// if its a link to a picture then embed this picture // if its a link to a picture then embed this picture
if (substr($curl_info["content_type"], 0, 6) == "image/") { if (substr($curl_info['content_type'], 0, 6) == 'image/') {
$text = "[img]" . $match[1] . "[/img]"; $text = '[img]' . $match[1] . '[/img]';
} else { } else {
if (!empty($match[3])) { if (!empty($match[3])) {
$text = "[img=" . $match[2] . "]" . $match[3] . "[/img]"; $text = '[img=' . $match[2] . ']' . $match[3] . '[/img]';
} else { } else {
$text = "[img]" . $match[2] . "[/img]"; $text = '[img]' . $match[2] . '[/img]';
} }
// if its not a picture then look if its a page that contains a picture link // if its not a picture then look if its a page that contains a picture link
@ -1156,17 +1181,16 @@ class BBCode extends BaseObject
} }
} }
if (strtolower($attr["name"]) == "twitter:image") { if (strtolower($attr['name']) == "twitter:image") {
if (!empty($match[3])) { if (!empty($match[3])) {
$text = "[img=" . $attr["content"] . "]" . $match[3] . "[/img]"; $text = "[img=" . $attr['content'] . "]" . $match[3] . "[/img]";
} else { } else {
$text = "[img]" . $attr["content"] . "[/img]"; $text = "[img]" . $attr['content'] . "[/img]";
} }
} }
} }
} }
Cache::set($match[1], $text); Cache::set($cache_key, $text);
}
return $text; return $text;
} }
@ -1217,7 +1241,7 @@ class BBCode extends BaseObject
$try_oembed_callback = function ($match) $try_oembed_callback = function ($match)
{ {
$url = $match[1]; $url = $match[1];
$title = defaults($match, 2, null); $title = $match[2] ?? null;
try { try {
$return = OEmbed::getHTML($url, $title); $return = OEmbed::getHTML($url, $title);
@ -1318,7 +1342,7 @@ class BBCode extends BaseObject
$text = str_replace($search, $replace, $text); $text = str_replace($search, $replace, $text);
// removing multiplicated newlines // removing multiplicated newlines
if (Config::get("system", "remove_multiplicated_lines")) { if (Config::get('system', 'remove_multiplicated_lines')) {
$search = ["\n\n\n", "\n ", " \n", "[/quote]\n\n", "\n[/quote]", "[/li]\n", "\n[li]", "\n[ul]", "[/ul]\n", "\n\n[share ", "[/attachment]\n", $search = ["\n\n\n", "\n ", " \n", "[/quote]\n\n", "\n[/quote]", "[/li]\n", "\n[li]", "\n[ul]", "[/ul]\n", "\n\n[share ", "[/attachment]\n",
"\n[h1]", "[/h1]\n", "\n[h2]", "[/h2]\n", "\n[h3]", "[/h3]\n", "\n[h4]", "[/h4]\n", "\n[h5]", "[/h5]\n", "\n[h6]", "[/h6]\n"]; "\n[h1]", "[/h1]\n", "\n[h2]", "[/h2]\n", "\n[h3]", "[/h3]\n", "\n[h4]", "[/h4]\n", "\n[h5]", "[/h5]\n", "\n[h6]", "[/h6]\n"];
$replace = ["\n\n", "\n", "\n", "[/quote]\n", "[/quote]", "[/li]", "[li]", "[ul]", "[/ul]", "\n[share ", "[/attachment]", $replace = ["\n\n", "\n", "\n", "[/quote]\n", "[/quote]", "[/li]", "[li]", "[ul]", "[/ul]", "\n[share ", "[/attachment]",
@ -1389,8 +1413,14 @@ class BBCode extends BaseObject
// Check for sized text // Check for sized text
// [size=50] --> font-size: 50px (with the unit). // [size=50] --> font-size: 50px (with the unit).
if ($simple_html != 3) {
$text = preg_replace("(\[size=(\d*?)\](.*?)\[\/size\])ism", "<span style=\"font-size: $1px; line-height: initial;\">$2</span>", $text); $text = preg_replace("(\[size=(\d*?)\](.*?)\[\/size\])ism", "<span style=\"font-size: $1px; line-height: initial;\">$2</span>", $text);
$text = preg_replace("(\[size=(.*?)\](.*?)\[\/size\])ism", "<span style=\"font-size: $1; line-height: initial;\">$2</span>", $text); $text = preg_replace("(\[size=(.*?)\](.*?)\[\/size\])ism", "<span style=\"font-size: $1; line-height: initial;\">$2</span>", $text);
} else {
// Issue 2199: Diaspora doesn't interpret the construct above, nor the <small> or <big> element
$text = preg_replace("(\[size=(.*?)\](.*?)\[\/size\])ism", "$2", $text);
}
// Check for centered text // Check for centered text
$text = preg_replace("(\[center\](.*?)\[\/center\])ism", "<div style=\"text-align:center;\">$1</div>", $text); $text = preg_replace("(\[center\](.*?)\[\/center\])ism", "<div style=\"text-align:center;\">$1</div>", $text);
@ -1445,6 +1475,11 @@ class BBCode extends BaseObject
$text = str_replace('[hr]', '<hr />', $text); $text = str_replace('[hr]', '<hr />', $text);
if (!$for_plaintext) {
// Autolinker for isolated URLs
$text = preg_replace(Strings::autoLinkRegEx(), '[url]$1[/url]', $text);
}
// This is actually executed in Item::prepareBody() // This is actually executed in Item::prepareBody()
$nosmile = strpos($text, '[nosmile]') !== false; $nosmile = strpos($text, '[nosmile]') !== false;
@ -1454,24 +1489,22 @@ class BBCode extends BaseObject
$text = preg_replace("/\[font=(.*?)\](.*?)\[\/font\]/sm", "<span style=\"font-family: $1;\">$2</span>", $text); $text = preg_replace("/\[font=(.*?)\](.*?)\[\/font\]/sm", "<span style=\"font-family: $1;\">$2</span>", $text);
// Declare the format for [spoiler] layout // Declare the format for [spoiler] layout
$SpoilerLayout = '<blockquote class="spoiler">$1</blockquote>'; $SpoilerLayout = '<details class="spoiler"><summary>' . L10n::t('Click to open/close') . '</summary>$1</details>';
// Check for [spoiler] text // Check for [spoiler] text
// handle nested quotes // handle nested quotes
$endlessloop = 0; $endlessloop = 0;
while ((strpos($text, "[/spoiler]") !== false) && (strpos($text, "[spoiler]") !== false) && (++$endlessloop < 20)) { while ((strpos($text, "[/spoiler]") !== false) && (strpos($text, "[spoiler]") !== false) && (++$endlessloop < 20)) {
$text = preg_replace("/\[spoiler\](.*?)\[\/spoiler\]/ism", "$SpoilerLayout", $text); $text = preg_replace("/\[spoiler\](.*?)\[\/spoiler\]/ism", $SpoilerLayout, $text);
} }
// Check for [spoiler=Author] text // Check for [spoiler=Title] text
$t_wrote = L10n::t('$1 wrote:');
// handle nested quotes // handle nested quotes
$endlessloop = 0; $endlessloop = 0;
while ((strpos($text, "[/spoiler]")!== false) && (strpos($text, "[spoiler=") !== false) && (++$endlessloop < 20)) { while ((strpos($text, "[/spoiler]")!== false) && (strpos($text, "[spoiler=") !== false) && (++$endlessloop < 20)) {
$text = preg_replace("/\[spoiler=[\"\']*(.*?)[\"\']*\](.*?)\[\/spoiler\]/ism", $text = preg_replace("/\[spoiler=[\"\']*(.*?)[\"\']*\](.*?)\[\/spoiler\]/ism",
"<br /><strong class=".'"spoiler"'.">" . $t_wrote . "</strong><blockquote class=".'"spoiler"'.">$2</blockquote>", '<details class="spoiler"><summary>$1</summary>$2</details>',
$text); $text);
} }
@ -1629,12 +1662,10 @@ class BBCode extends BaseObject
$text = Smilies::replace($text); $text = Smilies::replace($text);
} }
// if the HTML is used to generate plain text, then don't do this search, but replace all URL of that kind to text
if (!$for_plaintext) { if (!$for_plaintext) {
$text = preg_replace(Strings::autoLinkRegEx(), '[url]$1[/url]', $text);
if (in_array($simple_html, [7, 9])) { if (in_array($simple_html, [7, 9])) {
$text = preg_replace_callback("/\[url\](.*?)\[\/url\]/ism", 'self::convertUrlForOStatusCallback', $text); $text = preg_replace_callback("/\[url\](.*?)\[\/url\]/ism", 'self::convertUrlForActivityPubCallback', $text);
$text = preg_replace_callback("/\[url\=(.*?)\](.*?)\[\/url\]/ism", 'self::convertUrlForOStatusCallback', $text); $text = preg_replace_callback("/\[url\=(.*?)\](.*?)\[\/url\]/ism", 'self::convertUrlForActivityPubCallback', $text);
} }
} else { } else {
$text = preg_replace("(\[url\](.*?)\[\/url\])ism", " $1 ", $text); $text = preg_replace("(\[url\](.*?)\[\/url\])ism", " $1 ", $text);
@ -1810,7 +1841,7 @@ class BBCode extends BaseObject
// Clean up the HTML by loading and saving the HTML with the DOM. // Clean up the HTML by loading and saving the HTML with the DOM.
// Bad structured html can break a whole page. // Bad structured html can break a whole page.
// For performance reasons do it only with activated item cache or at export. // For performance reasons do it only with activated item cache or at export.
if (!$try_oembed || (get_itemcachepath() != "")) { if (!$try_oembed || (get_itemcachepath() != '')) {
$doc = new DOMDocument(); $doc = new DOMDocument();
$doc->preserveWhiteSpace = false; $doc->preserveWhiteSpace = false;
@ -1818,10 +1849,10 @@ class BBCode extends BaseObject
$doctype = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">'; $doctype = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">';
$encoding = '<?xml encoding="UTF-8">'; $encoding = '<?xml encoding="UTF-8">';
@$doc->loadHTML($encoding.$doctype."<html><body>".$text."</body></html>"); @$doc->loadHTML($encoding . $doctype . '<html><body>' . $text . '</body></html>');
$doc->encoding = 'UTF-8'; $doc->encoding = 'UTF-8';
$text = $doc->saveHTML(); $text = $doc->saveHTML();
$text = str_replace(["<html><body>", "</body></html>", $doctype, $encoding], ["", "", "", ""], $text); $text = str_replace(['<html><body>', '</body></html>', $doctype, $encoding], ['', '', '', ''], $text);
$text = str_replace('<br></li>', '</li>', $text); $text = str_replace('<br></li>', '</li>', $text);
@ -1861,9 +1892,9 @@ class BBCode extends BaseObject
* @param string $addon The addon for which the abstract is meant for * @param string $addon The addon for which the abstract is meant for
* @return string The abstract * @return string The abstract
*/ */
public static function getAbstract($text, $addon = "") public static function getAbstract($text, $addon = '')
{ {
$abstract = ""; $abstract = '';
$abstracts = []; $abstracts = [];
$addon = strtolower($addon); $addon = strtolower($addon);
@ -1877,7 +1908,7 @@ class BBCode extends BaseObject
$abstract = $abstracts[$addon]; $abstract = $abstracts[$addon];
} }
if ($abstract == "" && preg_match("/\[abstract\](.*?)\[\/abstract\]/ism", $text, $result)) { if ($abstract == '' && preg_match("/\[abstract\](.*?)\[\/abstract\]/ism", $text, $result)) {
$abstract = $result[1]; $abstract = $result[1];
} }
@ -1953,7 +1984,7 @@ class BBCode extends BaseObject
// Add all tags that maybe were removed // Add all tags that maybe were removed
if (preg_match_all("/#\[url\=([$url_search_string]*)\](.*?)\[\/url\]/ism", $original_text, $tags)) { if (preg_match_all("/#\[url\=([$url_search_string]*)\](.*?)\[\/url\]/ism", $original_text, $tags)) {
$tagline = ""; $tagline = '';
foreach ($tags[2] as $tag) { foreach ($tags[2] as $tag) {
$tag = html_entity_decode($tag, ENT_QUOTES, 'UTF-8'); $tag = html_entity_decode($tag, ENT_QUOTES, 'UTF-8');
if (!strpos(html_entity_decode($text, ENT_QUOTES, 'UTF-8'), '#' . $tag)) { if (!strpos(html_entity_decode($text, ENT_QUOTES, 'UTF-8'), '#' . $tag)) {
@ -1971,7 +2002,7 @@ class BBCode extends BaseObject
// If a link is followed by a quote then there should be a newline before it // If a link is followed by a quote then there should be a newline before it
// Maybe we should make this newline at every time before a quote. // Maybe we should make this newline at every time before a quote.
$text = str_replace(["</a><blockquote>"], ["</a><br><blockquote>"], $text); $text = str_replace(['</a><blockquote>'], ['</a><br><blockquote>'], $text);
$stamp1 = microtime(true); $stamp1 = microtime(true);

View file

@ -42,14 +42,32 @@ class HTML
return $cleaned; return $cleaned;
} }
private static function tagToBBCode(DOMDocument $doc, $tag, $attributes, $startbb, $endbb) /**
* Search all instances of a specific HTML tag node in the provided DOM document and replaces them with BBCode text nodes.
*
* @see HTML::tagToBBCodeSub()
*/
private static function tagToBBCode(DOMDocument $doc, string $tag, array $attributes, string $startbb, string $endbb, bool $ignoreChildren = false)
{ {
do { do {
$done = self::tagToBBCodeSub($doc, $tag, $attributes, $startbb, $endbb); $done = self::tagToBBCodeSub($doc, $tag, $attributes, $startbb, $endbb, $ignoreChildren);
} while ($done); } while ($done);
} }
private static function tagToBBCodeSub(DOMDocument $doc, $tag, $attributes, $startbb, $endbb) /**
* Search the first specific HTML tag node in the provided DOM document and replaces it with BBCode text nodes.
*
* @param DOMDocument $doc
* @param string $tag HTML tag name
* @param array $attributes Array of attributes to match and optionally use the value from
* @param string $startbb BBCode tag opening
* @param string $endbb BBCode tag closing
* @param bool $ignoreChildren If set to false, the HTML tag children will be appended as text inside the BBCode tag
* Otherwise, they will be entirely ignored. Useful for simple BBCode that draw their
* inner value from an attribute value and disregard the tag children.
* @return bool Whether a replacement was done
*/
private static function tagToBBCodeSub(DOMDocument $doc, string $tag, array $attributes, string $startbb, string $endbb, bool $ignoreChildren = false)
{ {
$savestart = str_replace('$', '\x01', $startbb); $savestart = str_replace('$', '\x01', $startbb);
$replace = false; $replace = false;
@ -98,7 +116,7 @@ class HTML
$node->parentNode->insertBefore($StartCode, $node); $node->parentNode->insertBefore($StartCode, $node);
if ($node->hasChildNodes()) { if (!$ignoreChildren && $node->hasChildNodes()) {
/** @var \DOMNode $child */ /** @var \DOMNode $child */
foreach ($node->childNodes as $key => $child) { foreach ($node->childNodes as $key => $child) {
/* Remove empty text nodes at the start or at the end of the children list */ /* Remove empty text nodes at the start or at the end of the children list */
@ -296,14 +314,14 @@ class HTML
self::tagToBBCode($doc, 'a', ['href' => '/mailto:(.+)/'], '[mail=$1]', '[/mail]'); self::tagToBBCode($doc, 'a', ['href' => '/mailto:(.+)/'], '[mail=$1]', '[/mail]');
self::tagToBBCode($doc, 'a', ['href' => '/(.+)/'], '[url=$1]', '[/url]'); self::tagToBBCode($doc, 'a', ['href' => '/(.+)/'], '[url=$1]', '[/url]');
self::tagToBBCode($doc, 'img', ['src' => '/(.+)/', 'alt' => '/(.+)/'], '[img=$1]$2', '[/img]'); self::tagToBBCode($doc, 'img', ['src' => '/(.+)/', 'alt' => '/(.+)/'], '[img=$1]$2', '[/img]', true);
self::tagToBBCode($doc, 'img', ['src' => '/(.+)/', 'width' => '/(\d+)/', 'height' => '/(\d+)/'], '[img=$2x$3]$1', '[/img]'); self::tagToBBCode($doc, 'img', ['src' => '/(.+)/', 'width' => '/(\d+)/', 'height' => '/(\d+)/'], '[img=$2x$3]$1', '[/img]', true);
self::tagToBBCode($doc, 'img', ['src' => '/(.+)/'], '[img]$1', '[/img]'); self::tagToBBCode($doc, 'img', ['src' => '/(.+)/'], '[img]$1', '[/img]', true);
self::tagToBBCode($doc, 'video', ['src' => '/(.+)/'], '[video]$1', '[/video]'); self::tagToBBCode($doc, 'video', ['src' => '/(.+)/'], '[video]$1', '[/video]', true);
self::tagToBBCode($doc, 'audio', ['src' => '/(.+)/'], '[audio]$1', '[/audio]'); self::tagToBBCode($doc, 'audio', ['src' => '/(.+)/'], '[audio]$1', '[/audio]', true);
self::tagToBBCode($doc, 'iframe', ['src' => '/(.+)/'], '[iframe]$1', '[/iframe]'); self::tagToBBCode($doc, 'iframe', ['src' => '/(.+)/'], '[iframe]$1', '[/iframe]', true);
self::tagToBBCode($doc, 'key', [], '[code]', '[/code]'); self::tagToBBCode($doc, 'key', [], '[code]', '[/code]');
self::tagToBBCode($doc, 'code', [], '[code]', '[/code]'); self::tagToBBCode($doc, 'code', [], '[code]', '[/code]');
@ -854,8 +872,8 @@ class HTML
$url = ''; $url = '';
} }
return Renderer::replaceMacros(Renderer::getMarkupTemplate(($textmode)?'micropro_txt.tpl':'micropro_img.tpl'), [ return Renderer::replaceMacros(Renderer::getMarkupTemplate($textmode ? 'micropro_txt.tpl' : 'micropro_img.tpl'), [
'$click' => defaults($contact, 'click', ''), '$click' => $contact['click'] ?? '',
'$class' => $class, '$class' => $class,
'$url' => $url, '$url' => $url,
'$photo' => ProxyUtils::proxifyUrl($contact['thumb'], false, ProxyUtils::SIZE_THUMB), '$photo' => ProxyUtils::proxifyUrl($contact['thumb'], false, ProxyUtils::SIZE_THUMB),
@ -875,9 +893,9 @@ class HTML
* @param bool $aside Display the search widgit aside. * @param bool $aside Display the search widgit aside.
* *
* @return string Formatted HTML. * @return string Formatted HTML.
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Exception
*/ */
public static function search($s, $id = 'search-box', $url = 'search', $aside = true) public static function search($s, $id = 'search-box', $aside = true)
{ {
$mode = 'text'; $mode = 'text';
@ -888,23 +906,24 @@ class HTML
$values = [ $values = [
'$s' => $s, '$s' => $s,
'$q' => urlencode($s),
'$id' => $id, '$id' => $id,
'$action_url' => $url,
'$search_label' => L10n::t('Search'), '$search_label' => L10n::t('Search'),
'$save_label' => $save_label, '$save_label' => $save_label,
'$savedsearch' => 'savedsearch',
'$search_hint' => L10n::t('@name, !forum, #tags, content'), '$search_hint' => L10n::t('@name, !forum, #tags, content'),
'$mode' => $mode '$mode' => $mode,
'$return_url' => urlencode('search?q=' . urlencode($s)),
]; ];
if (!$aside) { if (!$aside) {
$values['$searchoption'] = [ $values['$search_options'] = [
L10n::t("Full Text"), 'fulltext' => L10n::t('Full Text'),
L10n::t("Tags"), 'tags' => L10n::t('Tags'),
L10n::t("Contacts")]; 'contacts' => L10n::t('Contacts')
];
if (Config::get('system', 'poco_local_search')) { if (Config::get('system', 'poco_local_search')) {
$values['$searchoption'][] = L10n::t("Forums"); $values['$searchoption']['forums'] = L10n::t('Forums');
} }
} }

View file

@ -11,6 +11,7 @@ use Friendica\Core\PConfig;
use Friendica\Core\Protocol; use Friendica\Core\Protocol;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Model\FileTag; use Friendica\Model\FileTag;
@ -337,16 +338,9 @@ class Widget
return; return;
} }
$cid = $zcid = 0; $zcid = 0;
if (!empty($_SESSION['remote'])) { $cid = Session::getRemoteContactID($profile_uid);
foreach ($_SESSION['remote'] as $visitor) {
if ($visitor['uid'] == $profile_uid) {
$cid = $visitor['cid'];
break;
}
}
}
if (!$cid) { if (!$cid) {
if (Profile::getMyURL()) { if (Profile::getMyURL()) {

View file

@ -57,7 +57,7 @@ class CalendarExport
// $a->data is only available if the profile page is visited. If the visited page is not part // $a->data is only available if the profile page is visited. If the visited page is not part
// of the profile page it should be the personal /events page. So we can use $a->user. // of the profile page it should be the personal /events page. So we can use $a->user.
$user = defaults($a->data['user'], 'nickname', $a->user['nickname']); $user = ($a->data['user']['nickname'] ?? '') ?: $a->user['nickname'];
$tpl = Renderer::getMarkupTemplate("widget/events.tpl"); $tpl = Renderer::getMarkupTemplate("widget/events.tpl");
$return = Renderer::replaceMacros($tpl, [ $return = Renderer::replaceMacros($tpl, [

View file

@ -61,7 +61,7 @@ class ContactBlock
if ($total) { if ($total) {
// Only show followed for personal accounts, followers for pages // Only show followed for personal accounts, followers for pages
if (defaults($profile, 'account-type', User::ACCOUNT_TYPE_PERSON) == User::ACCOUNT_TYPE_PERSON) { if ((($profile['account-type'] ?? '') ?: User::ACCOUNT_TYPE_PERSON) == User::ACCOUNT_TYPE_PERSON) {
$rel = [Contact::SHARING, Contact::FRIEND]; $rel = [Contact::SHARING, Contact::FRIEND];
} else { } else {
$rel = [Contact::FOLLOWER, Contact::FRIEND]; $rel = [Contact::FOLLOWER, Contact::FRIEND];

View file

@ -0,0 +1,47 @@
<?php
namespace Friendica\Content\Widget;
use Friendica\Core\L10n;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
class SavedSearches
{
/**
* @param string $return_url
* @param string $search
* @return string
* @throws \Exception
*/
public static function getHTML($return_url, $search = '')
{
$o = '';
$saved_searches = DBA::select('search', ['id', 'term'], ['uid' => local_user()]);
if (DBA::isResult($saved_searches)) {
$saved = [];
foreach ($saved_searches as $saved_search) {
$saved[] = [
'id' => $saved_search['id'],
'term' => $saved_search['term'],
'encodedterm' => urlencode($saved_search['term']),
'delete' => L10n::t('Remove term'),
'selected' => $search == $saved_search['term'],
];
}
$tpl = Renderer::getMarkupTemplate('widget/saved_searches.tpl');
$o = Renderer::replaceMacros($tpl, [
'$title' => L10n::t('Saved Searches'),
'$add' => '',
'$searchbox' => '',
'$saved' => $saved,
'$return_url' => urlencode($return_url),
]);
}
return $o;
}
}

View file

@ -11,6 +11,7 @@ use Friendica\Content\Feature;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Model\GContact; use Friendica\Model\GContact;
use Friendica\Core\Session;
use Friendica\Util\Network; use Friendica\Util\Network;
/** /**
@ -40,12 +41,12 @@ class ACL extends BaseObject
$networks = null; $networks = null;
$size = defaults($options, 'size', 4); $size = ($options['size'] ?? 0) ?: 4;
$mutual = !empty($options['mutual_friends']); $mutual = !empty($options['mutual_friends']);
$single = !empty($options['single']) && empty($options['multiple']); $single = !empty($options['single']) && empty($options['multiple']);
$exclude = defaults($options, 'exclude', false); $exclude = $options['exclude'] ?? false;
switch (defaults($options, 'networks', Protocol::PHANTOM)) { switch (($options['networks'] ?? '') ?: Protocol::PHANTOM) {
case 'DFRN_ONLY': case 'DFRN_ONLY':
$networks = [Protocol::DFRN]; $networks = [Protocol::DFRN];
break; break;
@ -225,13 +226,13 @@ class ACL extends BaseObject
$acl_regex = '/<([0-9]+)>/i'; $acl_regex = '/<([0-9]+)>/i';
preg_match_all($acl_regex, defaults($user, 'allow_cid', ''), $matches); preg_match_all($acl_regex, $user['allow_cid'] ?? '', $matches);
$allow_cid = $matches[1]; $allow_cid = $matches[1];
preg_match_all($acl_regex, defaults($user, 'allow_gid', ''), $matches); preg_match_all($acl_regex, $user['allow_gid'] ?? '', $matches);
$allow_gid = $matches[1]; $allow_gid = $matches[1];
preg_match_all($acl_regex, defaults($user, 'deny_cid', ''), $matches); preg_match_all($acl_regex, $user['deny_cid'] ?? '', $matches);
$deny_cid = $matches[1]; $deny_cid = $matches[1];
preg_match_all($acl_regex, defaults($user, 'deny_gid', ''), $matches); preg_match_all($acl_regex, $user['deny_gid'] ?? '', $matches);
$deny_gid = $matches[1]; $deny_gid = $matches[1];
// Reformats the ACL data so that it is accepted by the JS frontend // Reformats the ACL data so that it is accepted by the JS frontend
@ -300,10 +301,10 @@ class ACL extends BaseObject
'$showall' => L10n::t('Visible to everybody'), '$showall' => L10n::t('Visible to everybody'),
'$show' => L10n::t('show'), '$show' => L10n::t('show'),
'$hide' => L10n::t('don\'t show'), '$hide' => L10n::t('don\'t show'),
'$allowcid' => json_encode(defaults($default_permissions, 'allow_cid', [])), // we need arrays for Javascript since we call .remove() and .push() on this values '$allowcid' => json_encode(($default_permissions['allow_cid'] ?? '') ?: []), // We need arrays for
'$allowgid' => json_encode(defaults($default_permissions, 'allow_gid', [])), '$allowgid' => json_encode(($default_permissions['allow_gid'] ?? '') ?: []), // Javascript since we
'$denycid' => json_encode(defaults($default_permissions, 'deny_cid', [])), '$denycid' => json_encode(($default_permissions['deny_cid'] ?? '') ?: []), // call .remove() and
'$denygid' => json_encode(defaults($default_permissions, 'deny_gid', [])), '$denygid' => json_encode(($default_permissions['deny_gid'] ?? '') ?: []), // .push() on these values
'$networks' => $show_jotnets, '$networks' => $show_jotnets,
'$emailcc' => L10n::t('CC: email addresses'), '$emailcc' => L10n::t('CC: email addresses'),
'$emtitle' => L10n::t('Example: bob@example.com, mary@example.com'), '$emtitle' => L10n::t('Example: bob@example.com, mary@example.com'),
@ -320,46 +321,4 @@ class ACL extends BaseObject
return $o; return $o;
} }
/**
* Searching for global contacts for autocompletion
*
* @brief Searching for global contacts for autocompletion
* @param string $search Name or part of a name or nick
* @param string $mode Search mode (e.g. "community")
* @return array with the search results
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function contactAutocomplete($search, $mode)
{
if (Config::get('system', 'block_public') && !local_user() && !remote_user()) {
return [];
}
// don't search if search term has less than 2 characters
if (!$search || mb_strlen($search) < 2) {
return [];
}
if (substr($search, 0, 1) === '@') {
$search = substr($search, 1);
}
// check if searching in the local global contact table is enabled
if (Config::get('system', 'poco_local_search')) {
$return = GContact::searchByName($search, $mode);
} else {
$p = defaults($_GET, 'page', 1) != 1 ? '&p=' . defaults($_GET, 'page', 1) : '';
$curlResult = Network::curl(get_server() . '/lsearch?f=' . $p . '&search=' . urlencode($search));
if ($curlResult->isSuccess()) {
$lsearch = json_decode($curlResult->getBody(), true);
if (!empty($lsearch['results'])) {
$return = $lsearch['results'];
}
}
}
return defaults($return, []);
}
} }

View file

@ -1,4 +1,5 @@
<?php <?php
/** /**
* @file /src/Core/Authentication.php * @file /src/Core/Authentication.php
*/ */
@ -24,9 +25,11 @@ class Authentication extends BaseObject
*/ */
public static function getCookieHashForUser($user) public static function getCookieHashForUser($user)
{ {
return(hash("sha256", Config::get("system", "site_prvkey") . return hash_hmac(
$user["prvkey"] . "sha256",
$user["password"])); hash_hmac("sha256", $user["password"], $user["prvkey"]),
Config::get("system", "site_prvkey")
);
} }
/** /**
@ -43,9 +46,11 @@ class Authentication extends BaseObject
} }
if ($user) { if ($user) {
$value = json_encode(["uid" => $user["uid"], $value = json_encode([
"uid" => $user["uid"],
"hash" => self::getCookieHashForUser($user), "hash" => self::getCookieHashForUser($user),
"ip" => defaults($_SERVER, 'REMOTE_ADDR', '0.0.0.0')]); "ip" => ($_SERVER['REMOTE_ADDR'] ?? '') ?: '0.0.0.0'
]);
} else { } else {
$value = ""; $value = "";
} }
@ -88,4 +93,3 @@ class Authentication extends BaseObject
} }
} }
} }

View file

@ -15,6 +15,7 @@ class MemcacheCache extends Cache implements IMemoryCache
{ {
use TraitCompareSet; use TraitCompareSet;
use TraitCompareDelete; use TraitCompareDelete;
use TraitMemcacheCommand;
/** /**
* @var Memcache * @var Memcache
@ -34,11 +35,11 @@ class MemcacheCache extends Cache implements IMemoryCache
$this->memcache = new Memcache(); $this->memcache = new Memcache();
$memcache_host = $config->get('system', 'memcache_host'); $this->server = $config->get('system', 'memcache_host');;
$memcache_port = $config->get('system', 'memcache_port'); $this->port = $config->get('system', 'memcache_port');
if (!$this->memcache->connect($memcache_host, $memcache_port)) { if (!@$this->memcache->connect($this->server, $this->port)) {
throw new Exception('Expected Memcache server at ' . $memcache_host . ':' . $memcache_port . ' isn\'t available'); throw new Exception('Expected Memcache server at ' . $this->server . ':' . $this->port . ' isn\'t available');
} }
} }
@ -47,21 +48,7 @@ class MemcacheCache extends Cache implements IMemoryCache
*/ */
public function getAllKeys($prefix = null) public function getAllKeys($prefix = null)
{ {
$keys = []; $keys = $this->getOriginalKeys($this->getMemcacheKeys());
$allSlabs = $this->memcache->getExtendedStats('slabs');
foreach ($allSlabs as $slabs) {
foreach (array_keys($slabs) as $slabId) {
$cachedump = $this->memcache->getExtendedStats('cachedump', (int)$slabId);
foreach ($cachedump as $key => $arrVal) {
if (!is_array($arrVal)) {
continue;
}
$keys = array_merge($keys, array_keys($arrVal));
}
}
}
$keys = $this->getOriginalKeys($keys);
return $this->filterArrayKeysByPrefix($keys, $prefix); return $this->filterArrayKeysByPrefix($keys, $prefix);
} }

Some files were not shown because too many files have changed in this diff Show more