8 Commits

Author SHA1 Message Date
harukin
059ee6d792 test 2019-06-14 16:29:15 +09:00
harukin
51bdae7590 move position 2019-06-14 16:27:14 +09:00
harukin
68b692c233 continue? 2019-06-14 16:24:45 +09:00
harukin
2c80a07457 continue. 2019-06-14 16:19:03 +09:00
harukin
4e4d7fcc11 test事案 2019-06-14 16:17:08 +09:00
harukin
3ca637bec2 edit path 2019-06-14 16:15:16 +09:00
harukin
ce45eab3cc remove tpl edit 2019-06-14 16:13:14 +09:00
harukin
b9e77d6a49 recaptha test 2019-06-14 16:11:12 +09:00
1935 changed files with 517366 additions and 186823 deletions

View File

@@ -1,10 +1,50 @@
# How to use # Hubzilla at Home next to your Router
This readme will show you how to install and run Hubzilla or Zap at home.
The installation is done by a script.
What the script will do for you...
+ install everything required by Zap/Hubzilla, basically a web server (Apache), PHP, a database (MySQL), certbot,...
+ create a database
+ run certbot to have everything for a secure connection (httpS)
+ create a script for daily maintenance
- backup to external disk (certificates, database, /var/www/)
- renew certfificate (letsencrypt)
- update of Zap/Hubzilla
- update of Debian
- restart
+ create cron jobs for
- DynDNS (selfHOST.de or freedns.afraid.org) every 5 minutes
- Master.php for Zap/Hubzilla every 10 minutes
- daily maintenance script every day at 05:30
The script is known to work without adjustments with
+ Hardware
- Mini-PC with Debian 9 (stretch), or
- Rapberry 3 with Raspbian, Debian 9
+ DynDNS
- selfHOST.de
- freedns.afraid.org
The script can install both [Hubzilla](https://zotlabs.org/page/hubzilla/hubzilla-project) and [Zap](https://zotlabs.com/zap/). Make sure to use the correct GIT repositories.
+ Hubzilla
- core: git clone https://framagit.org/hubzilla/core.git html (in this readme)
- addons: util/add_addon_repo https://framagit.org/hubzilla/addons.git hzaddons (in hubzilla-setup.sh)
+ Zap
- core: git clone https://framagit.org/zot/zap.git html (in this readme)
- addons: util/add_addon_repo https://framagit.org/zot/zap-addons.git zaddons (in hubzilla-setup.sh)
## Disclaimers ## Disclaimers
- This script does work with Debian 10 only. - This script does work with Debian 9 only.
- This script has to be used on a fresh debian install only (it does not take account for a possibly already installed and configured webserver or sql implementation). - This script has to be used on a fresh debian install only (it does not take account for a possibly already installed and configured webserver or sql implementation).
# Step-by-Step Overwiew
## Preconditions ## Preconditions
Hardware Hardware
@@ -15,10 +55,10 @@ Hardware
Software Software
+ Fresh installation of Debian 10 (Stretch) + Fresh installation of Debian 9 (Stretch)
+ Router with open ports 80 and 443 for your web server + Router with open ports 80 and 443 for your web server
## How to run the script ## The basic steps (quick overview)
+ Register your own domain (for example at selfHOST) or a free subdomain (for example at freeDNS) + Register your own domain (for example at selfHOST) or a free subdomain (for example at freeDNS)
+ Log on to your fresh Debian + Log on to your fresh Debian
@@ -36,6 +76,13 @@ Software
- ... wait, wait, wait until the script is finised - ... wait, wait, wait until the script is finised
+ Open your domain with a browser and step throught the initial configuration of hubzilla. + Open your domain with a browser and step throught the initial configuration of hubzilla.
## Troubleshooting
If the check of the mail address fails when you try to register the very first user in the browser. Do...
cd /var/www/html
util/config system.do_not_check_dns 1
## Optional - Set path to imagemagick ## Optional - Set path to imagemagick
In Admin settings of hubzilla or via terminal In Admin settings of hubzilla or via terminal
@@ -43,61 +90,17 @@ In Admin settings of hubzilla or via terminal
cd /var/www/html cd /var/www/html
util/config system.imagick_convert_path /usr/bin/convert util/config system.imagick_convert_path /usr/bin/convert
## Optional - Switch verification of email on/off # Step-by-Step in Detail
Do this just befor you register the user. ## Preparations Software
In Admin settings of hubzilla or via terminal ## Install Debian 9
cd /var/www/html Provided you use a Raspberry Pi 3...
Check the current setting Download the OS Raspbian from https://www.raspberrypi.org/downloads/raspbian/
util/config system verify_email Follow the installation instruction there.
Switch the verification on/off (1/0)
util/config system verify_email 0
## What the script will do for you...
+ install everything required by Hubzilla, basically a web server (Apache), PHP, a database (MySQL), certbot,...
+ create a database
+ run certbot to have everything for a secure connection (httpS)
+ create a script for daily maintenance
- backup to external disk (certificates, database, /var/www/)
- renew certfificate (letsencrypt)
- update of Hubzilla
- update of Debian
- restart
+ create cron jobs for
- DynDNS (selfHOST.de or freedns.afraid.org) every 5 minutes
- Master.php for Zap/Hubzilla every 10 minutes
- daily maintenance script every day at 05:30
The script is known to work without adjustments with
+ Hardware
- Mini-PC with Debian 10 (stretch), or
- Rapberry 3 with Raspbian, Debian 10
+ DynDNS
- selfHOST.de
- freedns.afraid.org
The script can install both [Hubzilla](https://zotlabs.org/page/hubzilla/hubzilla-project) and [Zap](https://zotlabs.com/zap/). Make sure to use the correct GIT repositories.
+ Hubzilla
- core: git clone https://framagit.org/hubzilla/core.git html (in this readme)
- addons: util/add_addon_repo https://framagit.org/hubzilla/addons.git hzaddons (in hubzilla-setup.sh)
+ Zap
- core: git clone https://framagit.org/zot/zap.git html (in this readme)
- addons: util/add_addon_repo https://framagit.org/zot/zap-addons.git zaddons (in hubzilla-setup.sh)
# Step-by-Step - some Details
## Preparations
## Configure your Router ## Configure your Router
@@ -133,7 +136,7 @@ The cost is 1,50 € per month (2019).
## Note on Rasperry ## Note on Rasperry
The script was tested with an Raspberry 3 under Raspian, Debian 10. The script was tested with an Raspberry 3 under Raspian, Debian 9.
It is recommended to run the Raspi without graphical frontend (X-Server). Use... It is recommended to run the Raspi without graphical frontend (X-Server). Use...
@@ -143,5 +146,12 @@ to boot the Rapsi to the client console.
DO NOT FORGET TO CHANGE THE DEFAULT PASSWORD FOR USER PI! DO NOT FORGET TO CHANGE THE DEFAULT PASSWORD FOR USER PI!
On a Raspian Stretch (Debian 9) the validation of the mail address fails for the very first user.
This used to happen on some *bsd distros but there was some work to fix that a year ago (2017).
So if your system isn't registered in DNS or DNS isn't active do
cd /var/www/html
util/config system.do_not_check_dns 1

177
.homeinstall/hubzilla-setup.sh Executable file → Normal file
View File

@@ -26,15 +26,16 @@
# - install # - install
# * apache webserer, # * apache webserer,
# * php, # * php,
# * mariadb - the database for hubzilla, # * mysql - the database for hubzilla,
# * adminer, # * phpmyadmin,
# * git to download and update addons # * git to download and update hubzilla addon
# - download hubzilla core and addons
# - configure cron # - configure cron
# * "Master.php" for regular background prozesses of hubzilla # * "Master.php" for regular background prozesses of hubzilla
# * "apt-get update" and "apt-get dist-upgrade" and "apt-get autoremove" to keep linux up-to-date # * "apt-get update" and "apt-get dist-upgrade" and "apt-get autoremove" to keep linux up-to-date
# * run command to keep the IP up-to-date > DynDNS provided by selfHOST.de or freedns.afraid.org # * run command to keep the IP up-to-date > DynDNS provided by selfHOST.de or freedns.afraid.org
# * backup hubzillas database and files (rsync) # * backup hubzillas database and files (rsync)
# - run letsencrypt to create, register and use a certifacte for https # - letsencrypt
# #
# #
# Discussion # Discussion
@@ -44,6 +45,11 @@
# - The script runs into installation errors for phpmyadmin if it uses # - The script runs into installation errors for phpmyadmin if it uses
# different passwords. For the sake of simplicity one singel password. # different passwords. For the sake of simplicity one singel password.
# #
# Hubzilla - email verification
# - The script switches off email verification off in all htconfig.tpl.
# Example: /var/www/html/view/en/htconfig.tpl
# - Is this a silly idea or not?
#
# How to restore from backup # How to restore from backup
# -------------------------- # --------------------------
# #
@@ -55,7 +61,7 @@
# - creates a daily cron that runs the hubzilla-daily.sh # - creates a daily cron that runs the hubzilla-daily.sh
# #
# hubzilla-daily.sh makes a (daily) backup of all relevant files # hubzilla-daily.sh makes a (daily) backup of all relevant files
# - /var/lib/mysql/ > database # - /var/lib/mysql/ > hubzilla database
# - /var/www/ > hubzilla/zap from github # - /var/www/ > hubzilla/zap from github
# - /etc/letsencrypt/ > certificates # - /etc/letsencrypt/ > certificates
# #
@@ -67,6 +73,8 @@
# The script is based on Thomas Willinghams script "debian-setup.sh" # The script is based on Thomas Willinghams script "debian-setup.sh"
# which he used to install the red#matrix. # which he used to install the red#matrix.
# #
# The script uses another script from https://github.com/lukas2511/letsencrypt.sh
#
# The documentation for bash is here # The documentation for bash is here
# https://www.gnu.org/software/bash/manual/bash.html # https://www.gnu.org/software/bash/manual/bash.html
# #
@@ -86,9 +94,9 @@ function check_sanity {
then then
die "Debian is supported only" die "Debian is supported only"
fi fi
if ! grep -q 'Linux 10' /etc/issue if ! grep -q 'Linux 9' /etc/issue
then then
die "Linux 10 (buster) is supported only"x die "Linux 9 (stretch) is supported only"x
fi fi
} }
@@ -199,17 +207,21 @@ function print_warn {
} }
function stop_hubzilla { function stop_hubzilla {
if [ -d /etc/apache2 ]
then
print_info "stopping apache webserver..." print_info "stopping apache webserver..."
systemctl stop apache2 service apache2 stop
fi
if [ -f /etc/init.d/mysql ]
then
print_info "stopping mysql db..." print_info "stopping mysql db..."
systemctl stop mariadb /etc/init.d/mysql stop
fi
} }
function install_apache { function install_apache {
print_info "installing apache..." print_info "installing apache..."
nocheck_install "apache2 apache2-utils" nocheck_install "apache2 apache2-utils"
a2enmod rewrite
systemctl restart apache2
} }
function install_imagemagick { function install_imagemagick {
@@ -222,11 +234,6 @@ function install_curl {
nocheck_install "curl" nocheck_install "curl"
} }
function install_wget {
print_info "installing wget..."
nocheck_install "wget"
}
function install_sendmail { function install_sendmail {
print_info "installing sendmail..." print_info "installing sendmail..."
nocheck_install "sendmail sendmail-bin" nocheck_install "sendmail sendmail-bin"
@@ -235,47 +242,65 @@ function install_sendmail {
function install_php { function install_php {
# openssl and mbstring are included in libapache2-mod-php # openssl and mbstring are included in libapache2-mod-php
print_info "installing php..." print_info "installing php..."
nocheck_install "libapache2-mod-php php php-pear php-curl php-gd php-mysqli php-mbstring php-xml php-zip" nocheck_install "libapache2-mod-php php php-pear php-curl php-mcrypt php-gd php-mysqli php-mbstring php-xml"
sed -i "s/^upload_max_filesize =.*/upload_max_filesize = 100M/g" /etc/php/7.3/apache2/php.ini sed -i "s/^upload_max_filesize =.*/upload_max_filesize = 100M/g" /etc/php/7.0/apache2/php.ini
sed -i "s/^post_max_size =.*/post_max_size = 100M/g" /etc/php/7.3/apache2/php.ini sed -i "s/^post_max_size =.*/post_max_size = 100M/g" /etc/php/7.0/apache2/php.ini
} }
function install_mysql { function install_mysql {
# http://www.microhowto.info/howto/perform_an_unattended_installation_of_a_debian_package.html
#
# To determine the required package name, key and type you can perform
# a trial installation then search the configuration database.
#
# debconf-get-selections | grep mysql-server
#
# The command debconf-get-selections is provided by the package
# debconf-utils, which you may need to install.
#
# apt-get install debconf-utils
#
# If you want to supply an answer to a configuration question but do not
# want to be prompted for it then this can be arranged by preseeding the
# DebConf database with the required information.
#
# echo mysql-server mysql-server/root_password password xyzzy | debconf-set-selections
# echo mysql-server mysql-server/root_password_again password xyzzy | debconf-set-selections
#
print_info "installing mysql..." print_info "installing mysql..."
if [ -z "$mysqlpass" ] if [ -z "$mysqlpass" ]
then then
die "mysqlpass not set in $configfile" die "mysqlpass not set in $configfile"
fi fi
if type mysql ; then echo mysql-server mysql-server/root_password password $mysqlpass | debconf-set-selections
echo "Yes, mysql is installed" echo mysql-server mysql-server/root_password_again password $mysqlpass | debconf-set-selections
else nocheck_install "php-mysql mysql-server mysql-client"
echo "mariadb-server"
nocheck_install "mariadb-server"
systemctl status mariadb
systemctl start mariadb
mysql --user=root <<_EOF_
UPDATE mysql.user SET Password=PASSWORD('${db_root_password}') WHERE User='root';
DELETE FROM mysql.user WHERE User='';
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';
FLUSH PRIVILEGES;
_EOF_
fi
} }
function install_adminer { function install_phpmyadmin {
print_info "installing adminer..." print_info "installing phpmyadmin..."
nocheck_install "adminer" if [ -z "$phpmyadminpass" ]
if [ ! -f /etc/adminer/adminer.conf ]
then then
echo "Alias /adminer /usr/share/adminer/adminer" > /etc/adminer/adminer.conf die "phpmyadminpass not set in $configfile"
ln -s /etc/adminer/adminer.conf /etc/apache2/conf-available/adminer.conf
else
print_info "file /etc/adminer/adminer.conf exists already"
fi fi
echo phpmyadmin phpmyadmin/setup-password password $phpmyadminpass | debconf-set-selections
echo phpmyadmin phpmyadmin/mysql/app-pass password $phpmyadminpass | debconf-set-selections
echo phpmyadmin phpmyadmin/app-password-confirm password $phpmyadminpass | debconf-set-selections
echo phpmyadmin phpmyadmin/mysql/admin-pass password $phpmyadminpass | debconf-set-selections
echo phpmyadmin phpmyadmin/password-confirm password $phpmyadminpass | debconf-set-selections
echo phpmyadmin phpmyadmin/reconfigure-webserver multiselect apache2 | debconf-set-selections
nocheck_install "phpmyadmin"
# It seems to be not neccessary to check rewrite.load because it comes
# with the installation. To be sure you could check this manually by:
#
# nano /etc/apache2/mods-available/rewrite.load
#
# You should find the content:
#
# LoadModule rewrite_module /usr/lib/apache2/modules/mod_rewrite.so
a2enmod rewrite a2enmod rewrite
if [ ! -f /etc/apache2/apache2.conf ] if [ ! -f /etc/apache2/apache2.conf ]
then then
die "could not find file /etc/apache2/apache2.conf" die "could not find file /etc/apache2/apache2.conf"
@@ -283,10 +308,12 @@ function install_adminer {
sed -i \ sed -i \
"s/AllowOverride None/AllowOverride all/" \ "s/AllowOverride None/AllowOverride all/" \
/etc/apache2/apache2.conf /etc/apache2/apache2.conf
if [ -z "`grep 'Include /etc/phpmyadmin/apache.conf' /etc/apache2/apache2.conf`" ]
a2enconf adminer then
systemctl restart mariadb echo "Include /etc/phpmyadmin/apache.conf" >> /etc/apache2/apache2.conf
systemctl reload apache2 fi
service apache2 restart
/etc/init.d/mysql start
} }
function create_hubzilla_db { function create_hubzilla_db {
@@ -303,7 +330,6 @@ function create_hubzilla_db {
then then
die "hubzilla_db_pass not set in $configfile" die "hubzilla_db_pass not set in $configfile"
fi fi
systemctl restart mariadb
Q1="CREATE DATABASE IF NOT EXISTS $hubzilla_db_name;" Q1="CREATE DATABASE IF NOT EXISTS $hubzilla_db_name;"
Q2="GRANT USAGE ON *.* TO $hubzilla_db_user@localhost IDENTIFIED BY '$hubzilla_db_pass';" Q2="GRANT USAGE ON *.* TO $hubzilla_db_user@localhost IDENTIFIED BY '$hubzilla_db_pass';"
Q3="GRANT ALL PRIVILEGES ON $hubzilla_db_name.* to $hubzilla_db_user@localhost identified by '$hubzilla_db_pass';" Q3="GRANT ALL PRIVILEGES ON $hubzilla_db_name.* to $hubzilla_db_user@localhost identified by '$hubzilla_db_pass';"
@@ -423,11 +449,22 @@ function install_letsencrypt {
then then
die "Failed to install let's encrypt: 'le_domain' is empty in $configfile" die "Failed to install let's encrypt: 'le_domain' is empty in $configfile"
fi fi
# check if user gave mail address
if [ -z "$le_email" ] if [ -z "$le_email" ]
then then
die "Failed to install let's encrypt: 'le_email' is empty in $configfile" die "Failed to install let's encrypt: 'le_domain' is empty in $configfile"
fi fi
nocheck_install "certbot python-certbot-apache" nocheck_install "apt-transport-https"
# add backports to your sources.list
backports_list=/etc/apt/sources.list.d/backports.list
if [ -f $backports_list ]
then
print_info "$backports_list exist already"
else
echo "deb https://deb.debian.org/debian stretch-backports main" > $backports_list
fi
apt-get -y update
DEBIAN_FRONTEND=noninteractive apt-get -q -y -t stretch-backports install certbot python-certbot-apache
print_info "run certbot ..." print_info "run certbot ..."
certbot --apache -w /var/www/html -d $le_domain -m $le_email --agree-tos --non-interactive --redirect --hsts --uir certbot --apache -w /var/www/html -d $le_domain -m $le_email --agree-tos --non-interactive --redirect --hsts --uir
service apache2 restart service apache2 restart
@@ -446,19 +483,12 @@ function check_https {
} }
function install_hubzilla { function install_hubzilla {
print_info "installing addons..." print_info "installing hubzilla addons..."
cd /var/www/html/ cd /var/www/html/
if git remote -v | grep -i "origin.*hubzilla.*core" # if you install Hubzilla
then
print_info "hubzilla"
util/add_addon_repo https://framagit.org/hubzilla/addons hzaddons util/add_addon_repo https://framagit.org/hubzilla/addons hzaddons
elif git remote -v | grep -i "origin.*zap.*core" # if you install ZAP
then #util/add_addon_repo https://framagit.org/zot/zap-addons.git zaddons
print_info "zap"
util/add_addon_repo https://framagit.org/zot/zap-addons.git zaddons
else
die "neither zap nor hubzilla repository > did not install addons or zap/hubzilla"
fi
mkdir -p "store/[data]/smarty3" mkdir -p "store/[data]/smarty3"
chmod -R 777 store chmod -R 777 store
touch .htconfig.php touch .htconfig.php
@@ -468,7 +498,13 @@ function install_hubzilla {
chown root:www-data /var/www/html/ chown root:www-data /var/www/html/
chown root:www-data /var/www/html/.htaccess chown root:www-data /var/www/html/.htaccess
chmod 0644 /var/www/html/.htaccess chmod 0644 /var/www/html/.htaccess
print_info "installed addons" print_info "try to switch off email registration..."
sed -i "s/verify_email.*1/verify_email'] = 0/" /var/www/html/view/*/ht*
if [ -n "`grep -r 'verify_email.*1' /var/www/html/view/`" ]
then
print_warn "Hubzillas registration prozess might have email verification switched on."
fi
print_info "installed hubzilla"
} }
function install_rsync { function install_rsync {
@@ -599,6 +635,7 @@ source $configfile
selfhostdir=/etc/selfhost selfhostdir=/etc/selfhost
selfhostscript=selfhost-updater.sh selfhostscript=selfhost-updater.sh
hubzilladaily=hubzilla-daily.sh hubzilladaily=hubzilla-daily.sh
plugins_update=.homeinstall/plugins_update.sh
backup_mount_point=/media/hubzilla_backup backup_mount_point=/media/hubzilla_backup
#set -x # activate debugging from here #set -x # activate debugging from here
@@ -607,13 +644,12 @@ check_config
stop_hubzilla stop_hubzilla
update_upgrade update_upgrade
install_curl install_curl
install_wget
install_sendmail install_sendmail
install_apache install_apache
install_imagemagick install_imagemagick
install_php install_php
install_mysql install_mysql
install_adminer install_phpmyadmin
create_hubzilla_db create_hubzilla_db
run_freedns run_freedns
install_run_selfhost install_run_selfhost
@@ -624,7 +660,6 @@ configure_cron_selfhost
if [ "$le_domain" != "localhost" ] if [ "$le_domain" != "localhost" ]
then then
install_letsencrypt install_letsencrypt
configure_apache_for_https
check_https check_https
else else
print_info "is localhost - skipped installation of letsencrypt and configuration of apache for https" print_info "is localhost - skipped installation of letsencrypt and configuration of apache for https"
@@ -632,25 +667,15 @@ fi
install_hubzilla install_hubzilla
if [ "$le_domain" != "localhost" ]
then
rewrite_to_https
install_rsnapshot
else
print_info "is localhost - skipped rewrite to https and installation of rsnapshot"
fi
configure_cron_daily configure_cron_daily
if [ "$le_domain" != "localhost" ] if [ "$le_domain" != "localhost" ]
then then
install_rsync
install_cryptosetup install_cryptosetup
write_uninstall_script
else else
print_info "is localhost - skipped installation of cryptosetup" print_info "is localhost - skipped installation of cryptosetup"
fi fi
#set +x # stop debugging from here #set +x # stop debugging from here

147
CHANGELOG
View File

@@ -1,150 +1,3 @@
Hubzilla 4.6 (2019-12-04)
- Improve opengraph support for channels
- Add opengraph support for articles
- Update abook_connected for RSS feeds only if handle_feed() returned success
- Do not embed PDF files by default but allow to enabled this feature in security options
- Check if file exists before we include it in the router
- Update jquery to version 3.4.1
- Update composer libraries
- Remove old and unused javascript libraries
- Improved BBcode to Markdown conversion
- Introduce inline SVG support via BBcode
- Sanitize title on Atom/RSS feed import
- Improved HTTP headers cache support for photos
- Add date headers to signed headers
- Add check if item['tag'] is an array
- Add hook comments_are_now_closed for addons to override date based comment closure
- Change mysql schema for item.llink and item.plink for new installs from char(191) to text
- Improved photo cache expiration
- Improved plural function processing on translation strings creation from .po file with util/po2php utlility
- Improved support for CDN/Infrastructure caching (especially profile images)
- New japanese translation
- Add connect button for non-zot networks not connected in current location
- Allow to send forum channels wall2wall or sent by mentions post to external sites via addons
- Allow addons to process forum posts published through mentions
- Improved internal routing for ActivityPub messages
- Improved admin documentation
- Add ITEM_TYPE_CUSTOM and hooks to permit addons to create and distribute custom item types
- Support "comment policy" in Zot6 communications
- Add selected text as quote on reply if comment button is used
- Add more nofollow tags to links to discourage backlink farmers
- Improved conversion of emoji reactions from zot to zot6
- Add CardDAV/CalDAV autodiscovery
- Label source project of zotfeed since it is not completely compatible across projects
- Update homeinstall script
Bugfixes
- Fix once cached embedded content is used and stored forever
- Fix wildcard tag issue
- Fix duplicate attachment in jot fileupload
- Fix regression with audio file upload
- Fix can not edit menu name or title (#1402)
- Fix pagination encoding issue for some server setups
- Fix Zap->Hubzilla event title compatibility
- Fix event timezones for Zot6
- Fix missing summary in mod article_edit
- Fix PHP warning failed to write session data using user defined save handler
- Fix possible thumbnails distortion on rebuild with util/thumbrepair utility
- Fix issues with image import to zot6
- Fix attachment permissions on clonned channels sync
- Fix entries without sitekey returned from DB in queue_deliver() and Lib/Queue
Addons
- Twitter: send tweet even if attached image uploading was unsuccessful
- Livejournal: add link to original post option
- Flashcards: update to version 2.08
- Pubcrawl: compatibility changes to support pixelfed
- Cart: update paypal button to API v2
- Photocache: rework for speed and lower memory consumption
- Photocache: etag support for cached photos
- Photocache: purge cache on addon uninstall
- Openstreetmap: fix regression if no default values set
- Livejournal: allow send posts from non channel owner
- Pubcrawl: fix event timezones
- Pubcrawl: better ActivityPub channel URL detection
- Pubcrawl: fix comments delivery for other channels on the same hub
- New addon "workflow" with initial basic "issue tracker" capability
Hubzilla 4.4.1 (2019-08-16)
- Fix wrong profile photo displayed when previewing and editing profiles
- Fix regression from 4.4 which prevented encrypted signatures from being used for encrypted messages
- Fix typo in queueworker addon which broke filtering of duplicate work
Hubzilla 4.4 (2019-08-13)
- Change primary directory from zotadel.net to hub.netzgemeinde.eu (requested by zotadel admin)
- Add Russian context help files
- Replace plink URL with share tag if possible
- Catch and exclude trailing punctuation while URL embedding
- Do not limit channel if service class property value is set to zero
- Streamline keyId and creator/actor
- Add daemon_master_summon hook
- Serve static files directly if not caught by web server
- Update cacert.pem
- Calendar: allow different date/time format inputs
- Calendar: hide timezone select for allday events
⁻ Add opengraph meta info to channel page
- Begin directory migration to zot6
- Support zot and zot6 in social graph operations
- Lowlevel support for zot6 direct messages
- Consolidate HTTP signatures
- Allow api login by address or url
- Provide auto redirect from zot6 /item permalinks
- Export all items except photos in channel_export_items_date()
- Calendar: clicking a day or week number will now open the day or week view
- Remove cached photo location directory on delete if empty
- Include zot6 hubs in the Grid scope
- Fix os_path replace for thumbnails
- Avoid to process original images using storeThumbnail()
Bugfixes
- Fix URLs on imported item taxonomy
- Fix admin not allowed to delete any item
- Fix webfiunger issue with URLs containing an @
- Fix missing object in emoji reactions
- Fix appschema to include diaspora:guid
- Fix zotfinger in update_directory_entry()
- Fix incorrect media type on links for photo objects
- Fix mid not dbesc'd in item_store()
- Fix calendar encoding issues
Addons
- twitter: various rendering improvements
- cavatar: fix wrong image mimetype
- gravatar: fix wrong image mimetype
- Add license file
- pubcrawl: make repeats render like wall to wall posts
- pubcrawl: fix pubcrawl_import_author() sometimes returning a non activitypub xchan
- pubcrawl: use Lib/Activity for taxonomy en/decoding
- pubcrawl: fix wrong uuid in like activity
- pubcrawl: fix issue with encoding hashtags
- openstreetmap: use https URLs by default
- queueworker: refactor and efficiency improvements
- pubcrawl: use unique IDs for follow and accept activities
- pubcrawl: implement thread completion
- pubcrawl: implement delete activity
- photocache: reduce the size of the photo cache subdirectories tree
- photocache: use html_entity_decode() for cached photo URL
- diaspora: fix possible issue with diaspora relay not initializing
Hubzilla 4.2.1 (2019-06-17)
- Deprecate mod events
- Revisit mod cal
- Fix issues with deletion of linked items and resources
- Fix zot6 delete issue
- Fix attach sync issue
- Remove sizeRangeSuffixes in justified gallery wrapper
- Fix storageconv issue with postgres
- Fix embedphotos image size
- pubcrawl: use URI instead of object for actor url
- diaspora: adjust loglevel
- gallery: remove workaround for margin issue which has been fixed upstream
- cart: warn about unsaved changes
Hubzilla 4.2 (2019-06-04) Hubzilla 4.2 (2019-06-04)
- Introduce Calendar app which deprecates Events and CalDAV apps and streamlines the featuresets - Introduce Calendar app which deprecates Events and CalDAV apps and streamlines the featuresets
- Update mod cal to reflect changes in the calendar app - Update mod cal to reflect changes in the calendar app

11
LICENSE
View File

@@ -1,5 +1,4 @@
Copyright (c) 2019 Hubzilla Community Copyright (c) 2010-2018 the Hubzilla Community
All rights reserved. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -9,13 +8,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all The above copyright notice and this permission notice shall be included in
copies or substantial portions of the Software. all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
SOFTWARE. THE SOFTWARE.

View File

@@ -97,26 +97,26 @@ class Cron {
// Clean expired photos from cache // Clean expired photos from cache
$age = get_config('system','active_expire_days', '30');
$r = q("SELECT DISTINCT xchan, content FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s", $r = q("SELECT DISTINCT xchan, content FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
intval(PHOTO_CACHE), intval(PHOTO_CACHE),
db_utcnow(), db_utcnow(),
db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY') db_quoteinterval($age . ' DAY')
); );
if($r) { if($r) {
q("DELETE FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
intval(PHOTO_CACHE),
db_utcnow(),
db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY')
);
foreach($r as $rr) { foreach($r as $rr) {
$file = dbunescbin($rr['content']); $file = dbunescbin($rr['content']);
if(is_file($file)) { if(is_file($file)) {
@unlink($file); @unlink($file);
@rmdir(dirname($file));
logger('info: deleted cached photo file ' . $file, LOGGER_DEBUG); logger('info: deleted cached photo file ' . $file, LOGGER_DEBUG);
} }
} }
} }
q("DELETE FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
intval(PHOTO_CACHE),
db_utcnow(),
db_quoteinterval($age . ' DAY')
);
// publish any applicable items that were set to be published in the future // publish any applicable items that were set to be published in the future
// (time travel posts). Restrict to items that have come of age in the last // (time travel posts). Restrict to items that have come of age in the last
@@ -187,7 +187,7 @@ class Cron {
if($r) { if($r) {
require_once('include/photo/photo_driver.php'); require_once('include/photo/photo_driver.php');
foreach($r as $rr) { foreach($r as $rr) {
$photos = import_xchan_photo($rr['xchan_photo_l'], $rr['xchan_hash'], false, true); $photos = import_xchan_photo($rr['xchan_photo_l'],$rr['xchan_hash']);
$x = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' $x = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s'
where xchan_hash = '%s'", where xchan_hash = '%s'",
dbesc($photos[0]), dbesc($photos[0]),
@@ -214,7 +214,7 @@ class Cron {
$restart = true; $restart = true;
$generation = intval($argv[2]); $generation = intval($argv[2]);
if(! $generation) if(! $generation)
return; killme();
} }
reload_plugins(); reload_plugins();

View File

@@ -44,11 +44,6 @@ class Cron_daily {
db_utcnow(), db_quoteinterval('1 YEAR') db_utcnow(), db_quoteinterval('1 YEAR')
); );
// Clean up emdedded content cache
q("DELETE FROM cache WHERE updated < %s - INTERVAL %s",
db_utcnow(),
db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY')
);
//update statistics in config //update statistics in config
require_once('include/statistics_fns.php'); require_once('include/statistics_fns.php');

View File

@@ -13,7 +13,7 @@ class CurlAuth {
static public function run($argc,$argv) { static public function run($argc,$argv) {
if($argc != 2) if($argc != 2)
return; killme();
\App::$session->start(); \App::$session->start();
@@ -50,6 +50,6 @@ class CurlAuth {
file_put_contents($c,$x); file_put_contents($c,$x);
return; killme();
} }
} }

View File

@@ -9,7 +9,7 @@ if(array_search( __file__ , get_included_files()) === 0) {
if($argc) if($argc)
Master::Release($argc,$argv); Master::Release($argc,$argv);
return; killme();
} }
@@ -17,22 +17,7 @@ if(array_search( __file__ , get_included_files()) === 0) {
class Master { class Master {
static public function Summon($arr) { static public function Summon($arr) {
$hookinfo = [ proc_run('php','Zotlabs/Daemon/Master.php',$arr);
'argv'=>$arr
];
call_hooks ('daemon_master_summon',$hookinfo);
$arr = $hookinfo['argv'];
$argc = count($arr);
if ((!is_array($arr) || (count($arr) < 1))) {
logger("Summon handled by hook.",LOGGER_DEBUG);
return;
}
$phpbin = get_config('system','phpbin','php');
proc_run($phpbin,'Zotlabs/Daemon/Master.php',$arr);
} }
static public function Release($argc,$argv) { static public function Release($argc,$argv) {
@@ -48,7 +33,6 @@ class Master {
$argc = count($argv); $argc = count($argv);
if ((!is_array($argv) || (count($argv) < 1))) { if ((!is_array($argv) || (count($argv) < 1))) {
logger("Release handled by hook.",LOGGER_DEBUG);
return; return;
} }

View File

@@ -285,23 +285,10 @@ class Notifier {
} }
if(! in_array(intval($target_item['item_type']), [ ITEM_TYPE_POST ] )) { if(! in_array(intval($target_item['item_type']), [ ITEM_TYPE_POST ] )) {
$hookinfo=[
'targetitem'=>$target_item,
'deliver'=>false
];
if (intval($target_item['item_type'] == ITEM_TYPE_CUSTOM)) {
call_hooks('customitem_deliver',$hookinfo);
}
if (!$hookinfo['deliver']) {
logger('notifier: target item not forwardable: type ' . $target_item['item_type'], LOGGER_DEBUG); logger('notifier: target item not forwardable: type ' . $target_item['item_type'], LOGGER_DEBUG);
return; return;
} }
$target_item = $hookinfo['targetitem'];
}
// Check for non published items, but allow an exclusion for transmitting hidden file activities // Check for non published items, but allow an exclusion for transmitting hidden file activities
if(intval($target_item['item_unpublished']) || intval($target_item['item_delayed']) || if(intval($target_item['item_unpublished']) || intval($target_item['item_delayed']) ||

View File

@@ -61,13 +61,11 @@ class Onepoll {
if($contact['xchan_network'] === 'rss') { if($contact['xchan_network'] === 'rss') {
logger('onepoll: processing feed ' . $contact['xchan_name'], LOGGER_DEBUG); logger('onepoll: processing feed ' . $contact['xchan_name'], LOGGER_DEBUG);
$alive = handle_feed($importer['channel_id'],$contact_id,$contact['xchan_hash']); handle_feed($importer['channel_id'],$contact_id,$contact['xchan_hash']);
if ($alive) {
q("update abook set abook_connected = '%s' where abook_id = %d", q("update abook set abook_connected = '%s' where abook_id = %d",
dbesc(datetime_convert()), dbesc(datetime_convert()),
intval($contact['abook_id']) intval($contact['abook_id'])
); );
}
return; return;
} }

View File

@@ -47,7 +47,7 @@ class Poller {
$restart = true; $restart = true;
$generation = intval($argv[2]); $generation = intval($argv[2]);
if(! $generation) if(! $generation)
return; killme();
} }
if(($argc > 1) && intval($argv[1])) { if(($argc > 1) && intval($argv[1])) {

View File

@@ -2,12 +2,10 @@
namespace Zotlabs\Lib; namespace Zotlabs\Lib;
use Zotlabs\Access\PermissionLimits;
use Zotlabs\Daemon\Master; use Zotlabs\Daemon\Master;
use Zotlabs\Web\HTTPSig; use Zotlabs\Zot6\HTTPSig;
require_once('include/event.php'); require_once('include/event.php');
require_once('include/html2plain.php');
class Activity { class Activity {
@@ -42,8 +40,6 @@ class Activity {
if($x['type'] === ACTIVITY_OBJ_PHOTO) { if($x['type'] === ACTIVITY_OBJ_PHOTO) {
return self::fetch_image($x); return self::fetch_image($x);
} }
call_hooks('encode_object',$x);
} }
return $x; return $x;
@@ -67,39 +63,19 @@ class Activity {
} }
else { else {
$m = parse_url($url); $m = parse_url($url);
// handle bearcaps
if ($m['scheme'] === 'bear') {
$params = explode('&',$m['query']);
if ($params) {
foreach ($params as $p) {
if (substr($p,0,2) === 'u=') {
$url = substr($p,2);
}
if (substr($p,0,2) === 't=') {
$token = substr($p,2);
}
}
$m = parse_url($url);
}
}
$headers = [ $headers = [
'Accept' => 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"', 'Accept' => 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
'Host' => $m['host'], 'Host' => $m['host'],
'Date' => datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T'), '(request-target)' => 'get ' . get_request_string($url),
'(request-target)' => 'get ' . get_request_string($url) 'Date' => datetime_convert('UTC','UTC','now','D, d M Y H:i:s') . ' UTC'
]; ];
if (isset($token)) {
$headers['Authorization'] = 'Bearer ' . $token;
}
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false); $h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false);
$x = z_fetch_url($url, true, $redirects, [ 'headers' => $h ] ); $x = z_fetch_url($url, true, $redirects, [ 'headers' => $h ] );
} }
if($x['success']) { if($x['success']) {
$y = json_decode($x['body'],true); $y = json_decode($x['body'],true);
logger('returned: ' . json_encode($y,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES), LOGGER_DEBUG); logger('returned: ' . json_encode($y,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES));
return json_decode($x['body'], true); return json_decode($x['body'], true);
} }
else { else {
@@ -175,6 +151,7 @@ class Activity {
static function fetch_image($x) { static function fetch_image($x) {
$ret = [ $ret = [
'type' => 'Image', 'type' => 'Image',
'id' => $x['id'], 'id' => $x['id'],
@@ -202,11 +179,6 @@ class Activity {
$ev = bbtoevent($x['content']); $ev = bbtoevent($x['content']);
if($ev) { if($ev) {
if (! $ev['timezone']) {
$ev['timezone'] = 'UTC';
}
$actor = null; $actor = null;
if(array_key_exists('author',$x) && array_key_exists('link',$x['author'])) { if(array_key_exists('author',$x) && array_key_exists('link',$x['author'])) {
$actor = $x['author']['link'][0]['href']; $actor = $x['author']['link'][0]['href'];
@@ -214,17 +186,16 @@ class Activity {
$y = [ $y = [
'type' => 'Event', 'type' => 'Event',
'id' => z_root() . '/event/' . $ev['event_hash'], 'id' => z_root() . '/event/' . $ev['event_hash'],
'name' => $ev['summary'], 'summary' => bbcode($ev['summary'], [ 'cache' => true ]),
// 'summary' => bbcode($ev['summary'], [ 'cache' => true ]),
// RFC3339 Section 4.3 // RFC3339 Section 4.3
'startTime' => (($ev['adjust']) ? datetime_convert($ev['timezone'],'UTC',$ev['dtstart'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtstart'],'Y-m-d\\TH:i:s-00:00')), 'startTime' => (($ev['adjust']) ? datetime_convert('UTC','UTC',$ev['dtstart'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtstart'],'Y-m-d\\TH:i:s-00:00')),
'content' => bbcode($ev['description'], [ 'cache' => true ]), 'content' => bbcode($ev['description'], [ 'cache' => true ]),
'location' => [ 'type' => 'Place', 'content' => bbcode($ev['location'], [ 'cache' => true ]) ], 'location' => [ 'type' => 'Place', 'content' => bbcode($ev['location'], [ 'cache' => true ]) ],
'source' => [ 'content' => format_event_bbcode($ev), 'mediaType' => 'text/bbcode' ], 'source' => [ 'content' => format_event_bbcode($ev), 'mediaType' => 'text/bbcode' ],
'actor' => $actor, 'actor' => $actor,
]; ];
if(! $ev['nofinish']) { if(! $ev['nofinish']) {
$y['endTime'] = (($ev['adjust']) ? datetime_convert($ev['timezone'],'UTC',$ev['dtend'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtend'],'Y-m-d\\TH:i:s-00:00')); $y['endTime'] = (($ev['adjust']) ? datetime_convert('UTC','UTC',$ev['dtend'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtend'],'Y-m-d\\TH:i:s-00:00'));
} }
// copy attachments from the passed object - these are already formatted for ActivityStreams // copy attachments from the passed object - these are already formatted for ActivityStreams
@@ -304,13 +275,7 @@ class Activity {
$ret = []; $ret = [];
if($i['verb'] === ACTIVITY_FRIEND) {
// Hubzilla 'make-friend' activity, no direct mapping from AS1 to AS2 - make it a note
$objtype = 'Note';
}
else {
$objtype = self::activity_obj_mapper($i['obj_type']); $objtype = self::activity_obj_mapper($i['obj_type']);
}
if(intval($i['item_deleted'])) { if(intval($i['item_deleted'])) {
$ret['type'] = 'Tombstone'; $ret['type'] = 'Tombstone';
@@ -348,21 +313,6 @@ class Activity {
} }
} }
if (intval($i['item_wall']) && $i['mid'] === $i['parent_mid']) {
$ret['commentPolicy'] = map_scope(PermissionLimits::Get($i['uid'],'post_comments'));
}
if (intval($i['item_private']) === 2) {
$ret['directMessage'] = true;
}
if (array_key_exists('comments_closed',$i) && $i['comments_closed'] !== EMPTY_STR && $i['comments_closed'] !== NULL_DATE) {
if($ret['commentPolicy']) {
$ret['commentPolicy'] .= ' ';
}
$ret['commentPolicy'] .= 'until=' . datetime_convert('UTC','UTC',$i['comments_closed'],ATOM_TIME);
}
$ret['attributedTo'] = $i['author']['xchan_url']; $ret['attributedTo'] = $i['author']['xchan_url'];
if($i['id'] != $i['parent']) { if($i['id'] != $i['parent']) {
@@ -401,12 +351,8 @@ class Activity {
$ret = []; $ret = [];
if ($item['tag'] && is_array($item['tag'])) { if($item['tag']) {
$ptr = $item['tag']; foreach($item['tag'] as $t) {
if (! array_key_exists(0,$ptr)) {
$ptr = [ $ptr ];
}
foreach ($ptr as $t) {
if(! array_key_exists('type',$t)) if(! array_key_exists('type',$t))
$t['type'] = 'Hashtag'; $t['type'] = 'Hashtag';
@@ -435,7 +381,6 @@ class Activity {
} }
static function encode_taxonomy($item) { static function encode_taxonomy($item) {
$ret = []; $ret = [];
@@ -444,9 +389,9 @@ class Activity {
foreach($item['term'] as $t) { foreach($item['term'] as $t) {
switch($t['ttype']) { switch($t['ttype']) {
case TERM_HASHTAG: case TERM_HASHTAG:
// href is required so if we don't have a url in the taxonomy, ignore it and keep going. // An id is required so if we don't have a url in the taxonomy, ignore it and keep going.
if($t['url']) { if($t['url']) {
$ret[] = [ 'type' => 'Hashtag', 'href' => $t['url'], 'name' => '#' . $t['term'] ]; $ret[] = [ 'id' => $t['url'], 'name' => '#' . $t['term'] ];
} }
break; break;
@@ -519,12 +464,6 @@ class Activity {
$ret = []; $ret = [];
$reply = false; $reply = false;
if($i['verb'] === ACTIVITY_FRIEND) {
// Hubzilla 'make-friend' activity, no direct mapping from AS1 to AS2 - make it a note
$ret['obj'] = [];
}
if(intval($i['item_deleted'])) { if(intval($i['item_deleted'])) {
$ret['type'] = 'Tombstone'; $ret['type'] = 'Tombstone';
$ret['formerType'] = self::activity_obj_mapper($i['obj_type']); $ret['formerType'] = self::activity_obj_mapper($i['obj_type']);
@@ -537,41 +476,14 @@ class Activity {
return $ret; return $ret;
} }
if($i['verb'] === ACTIVITY_FRIEND) {
// Hubzilla 'make-friend' activity, no direct mapping from AS1 to AS2 - make it a note
$ret['obj_type'] = ACTIVITY_OBJ_NOTE;
$ret['obj'] = [];
}
$ret['type'] = self::activity_mapper($i['verb']); $ret['type'] = self::activity_mapper($i['verb']);
if($ret['type'] === 'emojiReaction') {
// There may not be an object for these items for legacy reasons - it should be the conversation parent.
$p = q("select * from item where mid = '%s' and uid = %d",
dbesc($i['parent_mid']),
intval($i['uid'])
);
if($p) {
xchan_query($p,true);
$p = fetch_post_tags($p,true);
$i['obj'] = self::encode_item($p[0]);
// convert to zot6 emoji reaction encoding which uses the target object to indicate the
// specific emoji instead of overloading the verb or type.
$im = explode('#',$i['verb']);
if($im && count($im) > 1)
$emoji = $im[1];
if(preg_match("/\[img(.*?)\](.*?)\[\/img\]/ism", $i['body'], $match)) {
$ln = $match[2];
}
$i['tgt_type'] = 'Image';
$i['target'] = [
'type' => 'Image',
'name' => $emoji,
'url' => (($ln) ? $ln : z_root() . '/images/emoji/' . $emoji . '.png')
];
}
}
$ret['id'] = ((strpos($i['mid'],'http') === 0) ? $i['mid'] : z_root() . '/activity/' . urlencode($i['mid'])); $ret['id'] = ((strpos($i['mid'],'http') === 0) ? $i['mid'] : z_root() . '/activity/' . urlencode($i['mid']));
@@ -609,14 +521,8 @@ class Activity {
} }
if($i['id'] != $i['parent']) { if($i['id'] != $i['parent']) {
$reply = true;
// inReplyTo needs to be set in the activity for followup actiions (Like, Dislike, Attend, Announce, etc.),
// but *not* for comments, where it should only be present in the object
if (! in_array($ret['type'],[ 'Create','Update' ])) {
$ret['inReplyTo'] = ((strpos($i['thr_parent'],'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_parent'])); $ret['inReplyTo'] = ((strpos($i['thr_parent'],'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_parent']));
} $reply = true;
if($i['item_private']) { if($i['item_private']) {
$d = q("select xchan_url, xchan_addr, xchan_name from item left join xchan on xchan_hash = author_xchan where id = %d limit 1", $d = q("select xchan_url, xchan_addr, xchan_name from item left join xchan on xchan_hash = author_xchan where id = %d limit 1",
@@ -655,7 +561,7 @@ class Activity {
$i['obj'] = json_decode($i['obj'],true); $i['obj'] = json_decode($i['obj'],true);
} }
if($i['obj']['type'] === ACTIVITY_OBJ_PHOTO) { if($i['obj']['type'] === ACTIVITY_OBJ_PHOTO) {
$i['obj']['id'] = $i['mid']; $i['obj']['id'] = $i['id'];
} }
$obj = self::encode_object($i['obj']); $obj = self::encode_object($i['obj']);
@@ -746,24 +652,8 @@ class Activity {
} }
$ret = []; $ret = [];
$c = ((array_key_exists('channel_id',$p)) ? $p : channelx_by_hash($p['xchan_hash']));
$ret['type'] = 'Person'; $ret['type'] = 'Person';
$ret['id'] = $p['xchan_url'];
if ($c) {
$role = get_pconfig($c['channel_id'],'system','permissions_role');
if (strpos($role,'forum') !== false) {
$ret['type'] = 'Group';
}
}
if ($c) {
$ret['id'] = channel_url($c);
}
else {
$ret['id'] = ((strpos($p['xchan_hash'],'http') === 0) ? $p['xchan_hash'] : $p['xchan_url']);
}
if($p['xchan_addr'] && strpos($p['xchan_addr'],'@')) if($p['xchan_addr'] && strpos($p['xchan_addr'],'@'))
$ret['preferredUsername'] = substr($p['xchan_addr'],0,strpos($p['xchan_addr'],'@')); $ret['preferredUsername'] = substr($p['xchan_addr'],0,strpos($p['xchan_addr'],'@'));
$ret['name'] = $p['xchan_name']; $ret['name'] = $p['xchan_name'];
@@ -825,7 +715,6 @@ class Activity {
'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept' 'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept'
]; ];
call_hooks('activity_mapper',$acts);
if(array_key_exists($verb,$acts) && $acts[$verb]) { if(array_key_exists($verb,$acts) && $acts[$verb]) {
return $acts[$verb]; return $acts[$verb];
@@ -838,9 +727,6 @@ class Activity {
if(strpos($verb,ACTIVITY_MOOD) !== false) if(strpos($verb,ACTIVITY_MOOD) !== false)
return 'Create'; return 'Create';
if(strpos($verb,ACTIVITY_FRIEND) !== false)
return 'Create';
if(strpos($verb,ACTIVITY_POKE) !== false) if(strpos($verb,ACTIVITY_POKE) !== false)
return 'Activity'; return 'Activity';
@@ -871,7 +757,6 @@ class Activity {
'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept' 'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept'
]; ];
call_hooks('activity_decode_mapper',$acts);
foreach($acts as $k => $v) { foreach($acts as $k => $v) {
if($verb === $v) { if($verb === $v) {
@@ -905,8 +790,6 @@ class Activity {
]; ];
call_hooks('activity_obj_decode_mapper',$objs);
foreach($objs as $k => $v) { foreach($objs as $k => $v) {
if($obj === $v) { if($obj === $v) {
return $k; return $k;
@@ -944,8 +827,6 @@ class Activity {
]; ];
call_hooks('activity_obj_mapper',$objs);
if(array_key_exists($obj,$objs)) { if(array_key_exists($obj,$objs)) {
return $objs[$obj]; return $objs[$obj];
} }
@@ -1535,11 +1416,6 @@ class Activity {
if($act->recips && (! in_array(ACTIVITY_PUBLIC_INBOX,$act->recips))) if($act->recips && (! in_array(ACTIVITY_PUBLIC_INBOX,$act->recips)))
$s['item_private'] = 1; $s['item_private'] = 1;
if (array_key_exists('directMessage',$act->obj) && intval($act->obj['directMessage'])) {
$s['item_private'] = 2;
}
set_iconfig($s,'activitypub','recips',$act->raw_recips); set_iconfig($s,'activitypub','recips',$act->raw_recips);
if($parent) { if($parent) {
set_iconfig($s,'activitypub','rawmsg',$act->raw,1); set_iconfig($s,'activitypub','rawmsg',$act->raw,1);
@@ -1694,7 +1570,7 @@ class Activity {
$s['verb'] = self::activity_decode_mapper($act->type); $s['verb'] = self::activity_decode_mapper($act->type);
if($act->type === 'Tombstone' || $act->type === 'Delete' || ($act->type === 'Create' && $act->obj['type'] === 'Tombstone')) { if($act->type === 'Tombstone' || ($act->type === 'Create' && $act->obj['type'] === 'Tombstone')) {
$s['item_deleted'] = 1; $s['item_deleted'] = 1;
} }
@@ -1704,12 +1580,11 @@ class Activity {
} }
if($act->obj['type'] === 'Event') { if($act->obj['type'] === 'Event') {
$s['obj'] = []; $s['obj'] = [];
$s['obj']['asld'] = $act->obj; $s['obj']['asld'] = $act->obj;
$s['obj']['type'] = ACTIVITY_OBJ_EVENT; $s['obj']['type'] = ACTIVITY_OBJ_EVENT;
$s['obj']['id'] = $act->obj['id']; $s['obj']['id'] = $act->obj['id'];
$s['obj']['title'] = $act->obj['name']; $s['obj']['title'] = $act->obj['summary'];
if(strpos($act->obj['startTime'],'Z')) if(strpos($act->obj['startTime'],'Z'))
$s['obj']['adjust'] = true; $s['obj']['adjust'] = true;
@@ -1873,14 +1748,14 @@ class Activity {
} }
foreach($ptr as $vurl) { foreach($ptr as $vurl) {
if(strpos($s['body'],$vurl['href']) === false) { if(strpos($s['body'],$vurl['href']) === false) {
$s['body'] .= '[zmg]' . $vurl['href'] . '[/zmg]' . "\n\n" . $s['body']; $s['body'] .= "\n\n" . '[zmg]' . $vurl['href'] . '[/zmg]';
break; break;
} }
} }
} }
elseif(is_string($act->obj['url'])) { elseif(is_string($act->obj['url'])) {
if(strpos($s['body'],$act->obj['url']) === false) { if(strpos($s['body'],$act->obj['url']) === false) {
$s['body'] .= '[zmg]' . $act->obj['url'] . '[/zmg]' . "\n\n" . $s['body']; $s['body'] .= "\n\n" . '[zmg]' . $act->obj['url'] . '[/zmg]';
} }
} }
} }
@@ -1961,301 +1836,15 @@ class Activity {
$s['item_private'] = 1; $s['item_private'] = 1;
set_iconfig($s,'activitypub','recips',$act->raw_recips); set_iconfig($s,'activitypub','recips',$act->raw_recips);
// @FIXME: $parent is not defined
$parent = (($s['parent_mid'] && $s['parent_mid'] === $s['mid']) ? true : false);
if($parent) { if($parent) {
set_iconfig($s,'activitypub','rawmsg',$act->raw,1); set_iconfig($s,'activitypub','rawmsg',$act->raw,1);
} }
$hookinfo = [
'act' => $act,
's' => $s
];
call_hooks('decode_note',$hookinfo);
$s = $hookinfo['s'];
return $s; return $s;
} }
static function store($channel,$observer_hash,$act,$item,$fetch_parents = true) {
$is_sys_channel = is_sys_channel($channel['channel_id']);
// Mastodon only allows visibility in public timelines if the public inbox is listed in the 'to' field.
// They are hidden in the public timeline if the public inbox is listed in the 'cc' field.
// This is not part of the activitypub protocol - we might change this to show all public posts in pubstream at some point.
$pubstream = ((is_array($act->obj) && array_key_exists('to', $act->obj) && in_array(ACTIVITY_PUBLIC_INBOX, $act->obj['to'])) ? true : false);
$is_parent = (($item['parent_mid'] && $item['parent_mid'] === $item['mid']) ? true : false);
if($is_parent && (! perm_is_allowed($channel['channel_id'],$observer_hash,'send_stream') && ! ($is_sys_channel && $pubstream))) {
logger('no permission');
return;
}
if(is_array($act->obj)) {
$content = self::get_content($act->obj);
}
if(! $content) {
logger('no content');
return;
}
$item['aid'] = $channel['channel_account_id'];
$item['uid'] = $channel['channel_id'];
$s['uuid'] = '';
// Friendica sends the diaspora guid in a nonstandard field via AP
if($act->obj['diaspora:guid'])
$s['uuid'] = $act->obj['diaspora:guid'];
if(! ( $item['author_xchan'] && $item['owner_xchan'])) {
logger('owner or author missing.');
return;
}
if($channel['channel_system']) {
if(! MessageFilter::evaluate($item,get_config('system','pubstream_incl'),get_config('system','pubstream_excl'))) {
logger('post is filtered');
return;
}
}
$abook = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1",
dbesc($observer_hash),
intval($channel['channel_id'])
);
if($abook) {
if(! post_is_importable($item,$abook[0])) {
logger('post is filtered');
return;
}
}
if($act->obj['conversation']) {
set_iconfig($item,'ostatus','conversation',$act->obj['conversation'],1);
}
// This isn't perfect but the best we can do for now.
$item['comment_policy'] = 'authenticated';
set_iconfig($item,'activitypub','recips',$act->raw_recips);
if(! $is_parent) {
$p = q("select parent_mid from item where mid = '%s' and uid = %d limit 1",
dbesc($item['parent_mid']),
intval($item['uid'])
);
if(! $p) {
$a = (($fetch_parents) ? self::fetch_and_store_parents($channel,$act,$item) : false);
if($a) {
$p = q("select parent_mid from item where mid = '%s' and uid = %d limit 1",
dbesc($item['parent_mid']),
intval($item['uid'])
);
}
else {
logger('could not fetch parents');
return;
// @TODO we maybe could accept these is we formatted the body correctly with share_bb()
// or at least provided a link to the object
// if(in_array($act->type,[ 'Like','Dislike' ])) {
// return;
// }
// @TODO do we actually want that?
// if no parent was fetched, turn into a top-level post
// turn into a top level post
// $s['parent_mid'] = $s['mid'];
// $s['thr_parent'] = $s['mid'];
}
}
if($p[0]['parent_mid'] !== $item['parent_mid']) {
$item['thr_parent'] = $item['parent_mid'];
}
else {
$item['thr_parent'] = $p[0]['parent_mid'];
}
$item['parent_mid'] = $p[0]['parent_mid'];
}
$r = q("select id, created, edited from item where mid = '%s' and uid = %d limit 1",
dbesc($item['mid']),
intval($item['uid'])
);
if($r) {
if($item['edited'] > $r[0]['edited']) {
$item['id'] = $r[0]['id'];
$x = item_store_update($item);
}
else {
return;
}
}
else {
$x = item_store($item);
}
if(is_array($x) && $x['item_id']) {
if($is_parent) {
if($item['owner_xchan'] === $channel['channel_hash']) {
// We are the owner of this conversation, so send all received comments back downstream
Master::Summon(array('Notifier','comment-import',$x['item_id']));
}
$r = q("select * from item where id = %d limit 1",
intval($x['item_id'])
);
if($r) {
send_status_notifications($x['item_id'],$r[0]);
}
}
sync_an_item($channel['channel_id'],$x['item_id']);
}
}
static public function fetch_and_store_parents($channel,$act,$item) {
logger('fetching parents');
$p = [];
$current_act = $act;
$current_item = $item;
while($current_item['parent_mid'] !== $current_item['mid']) {
$n = ActivityStreams::fetch($current_item['parent_mid'], $channel);
if(! $n) {
break;
}
$a = new ActivityStreams($n);
//logger($a->debug());
if(! $a->is_valid()) {
break;
}
$replies = null;
if(isset($a->obj['replies']['first']['items'])) {
$replies = $a->obj['replies']['first']['items'];
// we already have this one
array_diff($replies, [$current_item['mid']]);
}
$item = null;
switch($a->type) {
case 'Create':
case 'Update':
case 'Like':
case 'Dislike':
case 'Announce':
$item = self::decode_note($a);
break;
default:
break;
}
$hookinfo = [
'a' => $a,
'item' => $item
];
call_hooks('fetch_and_store',$hookinfo);
$item = $hookinfo['item'];
if($item) {
array_unshift($p,[ $a, $item, $replies]);
if($item['parent_mid'] === $item['mid'] || count($p) > 20) {
break;
}
}
$current_act = $a;
$current_item = $item;
}
if($p) {
foreach($p as $pv) {
self::store($channel,$pv[0]->actor['id'],$pv[0],$pv[1],false);
if($pv[2])
self::fetch_and_store_replies($channel, $pv[2]);
}
return true;
}
return false;
}
static public function fetch_and_store_replies($channel, $arr) {
logger('fetching replies');
$p = [];
foreach($arr as $url) {
$n = ActivityStreams::fetch($url, $channel);
if(! $n) {
break;
}
$a = new ActivityStreams($n);
if(! $a->is_valid()) {
break;
}
$item = null;
switch($a->type) {
case 'Create':
case 'Update':
case 'Like':
case 'Dislike':
case 'Announce':
$item = self::decode_note($a);
break;
default:
break;
}
$hookinfo = [
'a' => $a,
'item' => $item
];
call_hooks('fetch_and_store',$hookinfo);
$item = $hookinfo['item'];
if($item) {
array_unshift($p,[ $a, $item ]);
}
}
if($p) {
foreach($p as $pv) {
self::store($channel,$pv[0]->actor['id'],$pv[0],$pv[1],false);
}
}
}
static function announce_note($channel,$observer_hash,$act) { static function announce_note($channel,$observer_hash,$act) {
$s = []; $s = [];
@@ -2376,7 +1965,10 @@ class Activity {
$x = item_store($s); $x = item_store($s);
} }
if(is_array($x) && $x['item_id']) { if(is_array($x) && $x['item_id']) {
// @FIXME: $parent is not defined
if($parent) {
if($s['owner_xchan'] === $channel['channel_hash']) { if($s['owner_xchan'] === $channel['channel_hash']) {
// We are the owner of this conversation, so send all received comments back downstream // We are the owner of this conversation, so send all received comments back downstream
Master::Summon(array('Notifier','comment-import',$x['item_id'])); Master::Summon(array('Notifier','comment-import',$x['item_id']));
@@ -2387,10 +1979,11 @@ class Activity {
if($r) { if($r) {
send_status_notifications($x['item_id'],$r[0]); send_status_notifications($x['item_id'],$r[0]);
} }
}
sync_an_item($channel['channel_id'],$x['item_id']); sync_an_item($channel['channel_id'],$x['item_id']);
} }
} }
static function like_note($channel,$observer_hash,$act) { static function like_note($channel,$observer_hash,$act) {
@@ -2625,12 +2218,7 @@ class Activity {
} }
if($event) { if($event) {
$event['summary'] = $content['name']; $event['summary'] = html2bbcode($content['summary']);
if(! $event['summary']) {
if($content['summary']) {
$event['summary'] = html2plain($content['summary']);
}
}
$event['description'] = html2bbcode($content['content']); $event['description'] = html2bbcode($content['content']);
if($event['summary'] && $event['dtstart']) { if($event['summary'] && $event['dtstart']) {
$content['event'] = $event; $content['event'] = $event;

View File

@@ -11,10 +11,8 @@ class Cache {
$hash = hash('whirlpool',$key); $hash = hash('whirlpool',$key);
$r = q("SELECT v FROM cache WHERE k = '%s' AND updated > %s - INTERVAL %s LIMIT 1", $r = q("SELECT v FROM cache WHERE k = '%s' limit 1",
dbesc($hash), dbesc($hash)
db_utcnow(),
db_quoteinterval(get_config('system','object_cache_days', '30') . ' DAY')
); );
if ($r) if ($r)
@@ -42,5 +40,12 @@ class Cache {
dbesc(datetime_convert())); dbesc(datetime_convert()));
} }
} }
public static function clear() {
q("DELETE FROM cache WHERE updated < '%s'",
dbesc(datetime_convert('UTC','UTC',"now - 30 days")));
}
} }

View File

@@ -807,11 +807,6 @@ class Enotify {
$itemem_text = (($item['item_thread_top']) $itemem_text = (($item['item_thread_top'])
? t('created a new post') ? t('created a new post')
: sprintf( t('commented on %s\'s post'), $item['owner']['xchan_name'])); : sprintf( t('commented on %s\'s post'), $item['owner']['xchan_name']));
if($item['verb'] === ACTIVITY_SHARE) {
$itemem_text = sprintf( t('repeated %s\'s post'), $item['author']['xchan_name']);
}
} }
$edit = false; $edit = false;
@@ -830,14 +825,12 @@ class Enotify {
// convert this logic into a json array just like the system notifications // convert this logic into a json array just like the system notifications
$who = (($item['verb'] === ACTIVITY_SHARE) ? 'owner' : 'author');
$x = array( $x = array(
'notify_link' => $item['llink'], 'notify_link' => $item['llink'],
'name' => $item[$who]['xchan_name'], 'name' => $item['author']['xchan_name'],
'addr' => (($item[$who]['xchan_addr']) ? $item[$who]['xchan_addr'] : $item[$who]['xchan_url']), 'addr' => (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url']),
'url' => $item[$who]['xchan_url'], 'url' => $item['author']['xchan_url'],
'photo' => $item[$who]['xchan_photo_s'], 'photo' => $item['author']['xchan_photo_s'],
'when' => relative_date(($edit)? $item['edited'] : $item['created']), 'when' => relative_date(($edit)? $item['edited'] : $item['created']),
'class' => (intval($item['item_unseen']) ? 'notify-unseen' : 'notify-seen'), 'class' => (intval($item['item_unseen']) ? 'notify-unseen' : 'notify-seen'),
'b64mid' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? 'b64.' . base64url_encode($item['thr_parent']) : 'b64.' . base64url_encode($item['mid'])), 'b64mid' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? 'b64.' . base64url_encode($item['thr_parent']) : 'b64.' . base64url_encode($item['mid'])),
@@ -845,7 +838,7 @@ class Enotify {
'thread_top' => (($item['item_thread_top']) ? true : false), 'thread_top' => (($item['item_thread_top']) ? true : false),
'message' => strip_tags(bbcode($itemem_text)), 'message' => strip_tags(bbcode($itemem_text)),
// these are for the superblock addon // these are for the superblock addon
'hash' => $item[$who]['xchan_hash'], 'hash' => $item['author']['xchan_hash'],
'uid' => local_channel(), 'uid' => local_channel(),
'display' => true 'display' => true
); );

View File

@@ -2,7 +2,7 @@
namespace Zotlabs\Lib; namespace Zotlabs\Lib;
use Zotlabs\Web\HTTPSig; use Zotlabs\Zot6\HTTPSig;
class JSalmon { class JSalmon {

View File

@@ -29,8 +29,8 @@ class LDSignatures {
$options = [ $options = [
'type' => 'RsaSignature2017', 'type' => 'RsaSignature2017',
'nonce' => random_string(64), 'nonce' => random_string(64),
'creator' => z_root() . '/channel/' . $channel['channel_address'], 'creator' => z_root() . '/channel/' . $channel['channel_address'] . '/public_key_pem',
'created' => datetime_convert('UTC','UTC', 'now', 'Y-m-d\TH:i:s\Z') 'created' => datetime_convert('UTC','UTC', 'now', 'Y-m-d\Th:i:s\Z')
]; ];
$ohash = self::hash(self::signable_options($options)); $ohash = self::hash(self::signable_options($options));
@@ -124,7 +124,7 @@ class LDSignatures {
'meDataType' => $data_type, 'meDataType' => $data_type,
'meEncoding' => $encoding, 'meEncoding' => $encoding,
'meAlgorithm' => $algorithm, 'meAlgorithm' => $algorithm,
'meCreator' => z_root() . '/channel/' . $channel['channel_address'], 'meCreator' => z_root() . '/channel/' . $channel['channel_address'] . '/public_key_pem',
'meSignatureValue' => $signature 'meSignatureValue' => $signature
]); ]);

View File

@@ -2,7 +2,7 @@
namespace Zotlabs\Lib; namespace Zotlabs\Lib;
use Zotlabs\Web\HTTPSig; use Zotlabs\Zot6\HTTPSig;
use Zotlabs\Access\Permissions; use Zotlabs\Access\Permissions;
use Zotlabs\Access\PermissionLimits; use Zotlabs\Access\PermissionLimits;
use Zotlabs\Daemon\Master; use Zotlabs\Daemon\Master;
@@ -1223,39 +1223,9 @@ class Libzot {
if($private) { if($private) {
$arr['item_private'] = true; $arr['item_private'] = true;
} }
if ($arr['mid'] === $arr['parent_mid']) {
if (is_array($AS->obj) && array_key_exists('commentPolicy',$AS->obj)) {
$p = strstr($AS->obj['commentPolicy'],'until=');
if($p !== false) {
$arr['comments_closed'] = datetime_convert('UTC','UTC', substr($p,6));
$arr['comment_policy'] = trim(str_replace($p,'',$AS->obj['commentPolicy']));
}
else {
$arr['comment_policy'] = $AS->obj['commentPolicy'];
}
}
}
/// @FIXME - spoofable /// @FIXME - spoofable
if($AS->data['hubloc']) { if($AS->data['hubloc']) {
$arr['item_verified'] = true; $arr['item_verified'] = true;
if (! array_key_exists('comment_policy',$arr)) {
// set comment policy depending on source hub. Unknown or osada is ActivityPub.
// Anything else we'll say is zot - which could have a range of project names
$s = q("select site_project from site where site_url = '%s' limit 1",
dbesc($r[0]['hubloc_url'])
);
if ((! $s) || (in_array($s[0]['site_project'],[ '', 'osada' ]))) {
$arr['comment_policy'] = 'authenticated';
}
else {
$arr['comment_policy'] = 'contacts';
}
}
} }
if($AS->data['signed_data']) { if($AS->data['signed_data']) {
IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false); IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false);
@@ -1764,7 +1734,7 @@ class Libzot {
// if it's a sourced post, call the post_local hooks as if it were // if it's a sourced post, call the post_local hooks as if it were
// posted locally so that crosspost connectors will be triggered. // posted locally so that crosspost connectors will be triggered.
if(check_item_source($arr['uid'], $arr) || ($channel['xchan_pubforum'] == 1)) { if(check_item_source($arr['uid'], $arr)) {
/** /**
* @hooks post_local * @hooks post_local
* Called when an item has been posted on this machine via mod/item.php (also via API). * Called when an item has been posted on this machine via mod/item.php (also via API).
@@ -1849,10 +1819,6 @@ class Libzot {
$ret = []; $ret = [];
$signer = q("select hubloc_hash, hubloc_url from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1",
dbesc($a['signature']['signer'])
);
foreach($a['data']['orderedItems'] as $activity) { foreach($a['data']['orderedItems'] as $activity) {
$AS = new ActivityStreams($activity); $AS = new ActivityStreams($activity);
@@ -1911,23 +1877,6 @@ class Libzot {
if($AS->data['hubloc']) { if($AS->data['hubloc']) {
$arr['item_verified'] = true; $arr['item_verified'] = true;
} }
// set comment policy depending on source hub. Unknown or osada is ActivityPub.
// Anything else we'll say is zot - which could have a range of project names
if ($signer) {
$s = q("select site_project from site where site_url = '%s' limit 1",
dbesc($signer[0]['hubloc_url'])
);
if ((! $s) || (in_array($s[0]['site_project'],[ '', 'osada' ]))) {
$arr['comment_policy'] = 'authenticated';
}
else {
$arr['comment_policy'] = 'contacts';
}
}
if($AS->data['signed_data']) { if($AS->data['signed_data']) {
IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false); IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false);
} }
@@ -2088,7 +2037,7 @@ class Libzot {
$item_found = false; $item_found = false;
$post_id = 0; $post_id = 0;
$r = q("select * from item where ( author_xchan = '%s' or owner_xchan = '%s' or source_xchan = '%s' ) $r = q("select id, author_xchan, owner_xchan, source_xchan, item_deleted from item where ( author_xchan = '%s' or owner_xchan = '%s' or source_xchan = '%s' )
and mid = '%s' and uid = %d limit 1", and mid = '%s' and uid = %d limit 1",
dbesc($sender), dbesc($sender),
dbesc($sender), dbesc($sender),
@@ -2098,12 +2047,10 @@ class Libzot {
); );
if($r) { if($r) {
$stored = $r[0]; if($r[0]['author_xchan'] === $sender || $r[0]['owner_xchan'] === $sender || $r[0]['source_xchan'] === $sender)
if($stored['author_xchan'] === $sender || $stored['owner_xchan'] === $sender || $stored['source_xchan'] === $sender)
$ownership_valid = true; $ownership_valid = true;
$post_id = $stored['id']; $post_id = $r[0]['id'];
$item_found = true; $item_found = true;
} }
else { else {
@@ -2127,27 +2074,8 @@ class Libzot {
return false; return false;
} }
if ($stored['resource_type'] === 'event') {
$i = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1",
dbesc($stored['resource_id']),
intval($uid)
);
if ($i) {
if ($i[0]['event_xchan'] === $sender) {
q("delete from event where event_hash = '%s' and uid = %d",
dbesc($stored['resource_id']),
intval($uid)
);
}
else {
logger('delete linked event: not owner');
return;
}
}
}
if($item_found) { if($item_found) {
if(intval($stored['item_deleted'])) { if(intval($r[0]['item_deleted'])) {
logger('delete_imported_item: item was already deleted'); logger('delete_imported_item: item was already deleted');
if(! $relay) if(! $relay)
return false; return false;
@@ -2159,10 +2087,10 @@ class Libzot {
// back, and we aren't going to (or shouldn't at any rate) delete it again in the future - so losing // back, and we aren't going to (or shouldn't at any rate) delete it again in the future - so losing
// this information from the metadata should have no other discernible impact. // this information from the metadata should have no other discernible impact.
if (($stored['id'] != $stored['parent']) && intval($stored['item_origin'])) { if (($r[0]['id'] != $r[0]['parent']) && intval($r[0]['item_origin'])) {
q("update item set item_origin = 0 where id = %d and uid = %d", q("update item set item_origin = 0 where id = %d and uid = %d",
intval($stored['id']), intval($r[0]['id']),
intval($stored['uid']) intval($r[0]['uid'])
); );
} }
} }

View File

@@ -191,7 +191,7 @@ class NativeWiki {
return array('item' => null, 'success' => false); return array('item' => null, 'success' => false);
} }
else { else {
$drop = drop_item($item['id'], false, DROPITEM_NORMAL); $drop = drop_item($item['id'], false, DROPITEM_NORMAL, true);
} }
info( t('Wiki files deleted successfully')); info( t('Wiki files deleted successfully'));

View File

@@ -250,7 +250,7 @@ class Queue {
$host_crypto = null; $host_crypto = null;
if($channel && $base) { if($channel && $base) {
$h = q("select hubloc_sitekey, site_crypto from hubloc left join site on hubloc_url = site_url where site_url = '%s' and hubloc_sitekey != '' order by hubloc_id desc limit 1", $h = q("select hubloc_sitekey, site_crypto from hubloc left join site on hubloc_url = site_url where site_url = '%s' order by hubloc_id desc limit 1",
dbesc($base) dbesc($base)
); );
if($h) { if($h) {

View File

@@ -1,150 +0,0 @@
<?php
namespace Zotlabs\Lib;
use DomDocument;
/**
* SVGSantiizer
*
* Whitelist-based PHP SVG sanitizer.
*
* @link https://github.com/alister-/SVG-Sanitizer}
* @author Alister Norris
* @copyright Copyright (c) 2013 Alister Norris
* @license http://opensource.org/licenses/mit-license.php The MIT License
* @package svgsanitizer
*/
class SvgSanitizer {
private $xmlDoc; // PHP XML DOMDocument
private $removedattrs = [];
private static $allowed_functions = [ 'matrix', 'url', 'translate', 'rgb' ];
// defines the whitelist of elements and attributes allowed.
private static $whitelist = [
'a' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'href', 'xlink:href', 'xlink:title' ],
'circle' => [ 'class', 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'r', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
'clipPath' => [ 'class', 'clipPathUnits', 'id' ],
'defs' => [ ],
'style' => [ 'type' ],
'desc' => [ ],
'ellipse' => [ 'class', 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
'feGaussianBlur' => [ 'class', 'color-interpolation-filters', 'id', 'requiredFeatures', 'stdDeviation' ],
'filter' => [ 'class', 'color-interpolation-filters', 'filterRes', 'filterUnits', 'height', 'id', 'primitiveUnits', 'requiredFeatures', 'width', 'x', 'xlink:href', 'y' ],
'foreignObject' => [ 'class', 'font-size', 'height', 'id', 'opacity', 'requiredFeatures', 'style', 'transform', 'width', 'x', 'y' ],
'g' => [ 'class', 'clip-path', 'clip-rule', 'id', 'display', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'font-family', 'font-size', 'font-style', 'font-weight', 'text-anchor' ],
'image' => [ 'class', 'clip-path', 'clip-rule', 'filter', 'height', 'id', 'mask', 'opacity', 'requiredFeatures', 'style', 'systemLanguage', 'transform', 'width', 'x', 'xlink:href', 'xlink:title', 'y' ],
'line' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'x1', 'x2', 'y1', 'y2' ],
'linearGradient' => [ 'class', 'id', 'gradientTransform', 'gradientUnits', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'x1', 'x2', 'xlink:href', 'y1', 'y2' ],
'marker' => [ 'id', 'class', 'markerHeight', 'markerUnits', 'markerWidth', 'orient', 'preserveAspectRatio', 'refX', 'refY', 'systemLanguage', 'viewBox' ],
'mask' => [ 'class', 'height', 'id', 'maskContentUnits', 'maskUnits', 'width', 'x', 'y' ],
'metadata' => [ 'class', 'id' ],
'path' => [ 'class', 'clip-path', 'clip-rule', 'd', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
'pattern' => [ 'class', 'height', 'id', 'patternContentUnits', 'patternTransform', 'patternUnits', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xlink:href', 'y' ],
'polygon' => [ 'class', 'clip-path', 'clip-rule', 'id', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'class', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
'polyline' => [ 'class', 'clip-path', 'clip-rule', 'id', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
'radialGradient' => [ 'class', 'cx', 'cy', 'fx', 'fy', 'gradientTransform', 'gradientUnits', 'id', 'r', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'xlink:href' ],
'rect' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'width', 'x', 'y' ],
'stop' => [ 'class', 'id', 'offset', 'requiredFeatures', 'stop-color', 'stop-opacity', 'style', 'systemLanguage' ],
'svg' => [ 'class', 'clip-path', 'clip-rule', 'filter', 'id', 'height', 'mask', 'preserveAspectRatio', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xmlns', 'xmlns:se', 'xmlns:xlink', 'y' ],
'switch' => [ 'class', 'id', 'requiredFeatures', 'systemLanguage' ],
'symbol' => [ 'class', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'opacity', 'preserveAspectRatio', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'viewBox' ],
'text' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'text-anchor', 'transform', 'x', 'xml:space', 'y' ],
'textPath' => [ 'class', 'id', 'method', 'requiredFeatures', 'spacing', 'startOffset', 'style', 'systemLanguage', 'transform', 'xlink:href' ],
'title' => [ ],
'tspan' => [ 'class', 'clip-path', 'clip-rule', 'dx', 'dy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'mask', 'opacity', 'requiredFeatures', 'rotate', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'text-anchor', 'textLength', 'transform', 'x', 'xml:space', 'y' ],
'use' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'id', 'mask', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'transform', 'width', 'x', 'xlink:href', 'y' ],
];
function __construct() {
$this->xmlDoc = new DOMDocument('1.0','UTF-8');
$this->xmlDoc->preserveWhiteSpace = false;
libxml_use_internal_errors(true);
}
// load XML SVG
function load($file) {
$this->xmlDoc->load($file);
}
function loadXML($str) {
if (! $this->xmlDoc->loadXML($str)) {
logger('loadxml: ' . print_r(libxml_get_errors(),true), LOGGER_DEBUG);
return false;
}
return true;
}
function sanitize()
{
// all elements in xml doc
$allElements = $this->xmlDoc->getElementsByTagName('*');
// loop through all elements
for($i = 0; $i < $allElements->length; $i++)
{
$this->removedattrs = [];
$currentNode = $allElements->item($i);
// logger('current_node: ' . print_r($currentNode,true));
// array of allowed attributes in specific element
$whitelist_attr_arr = self::$whitelist[$currentNode->tagName];
// does element exist in whitelist?
if(isset($whitelist_attr_arr)) {
$total = $currentNode->attributes->length;
for($x = 0; $x < $total; $x++) {
// get attributes name
$attrName = $currentNode->attributes->item($x)->nodeName;
// logger('checking: ' . print_r($currentNode->attributes->item($x),true));
$matches = false;
// check if attribute isn't in whitelist
if(! in_array($attrName, $whitelist_attr_arr)) {
$this->removedattrs[] = $attrName;
}
// check for disallowed functions
elseif (preg_match_all('/([a-zA-Z0-9]+)[\s]*\(/',
$currentNode->attributes->item($x)->textContent,$matches,PREG_SET_ORDER)) {
if ($attrName === 'text') {
continue;
}
foreach ($matches as $match) {
if(! in_array($match[1],self::$allowed_functions)) {
logger('queue_remove_function: ' . $match[1],LOGGER_DEBUG);
$this->removedattrs[] = $attrName;
}
}
}
}
if ($this->removedattrs) {
foreach ($this->removedattrs as $attr) {
$currentNode->removeAttribute($attr);
logger('removed: ' . $attr, LOGGER_DEBUG);
}
}
}
// else remove element
else {
logger('remove_node: ' . print_r($currentNode,true));
$currentNode->parentNode->removeChild($currentNode);
}
}
return true;
}
function saveSVG() {
$this->xmlDoc->formatOutput = true;
return($this->xmlDoc->saveXML());
}
}

View File

@@ -98,7 +98,7 @@ class ThreadItem {
$conv = $this->get_conversation(); $conv = $this->get_conversation();
$observer = $conv->get_observer(); $observer = $conv->get_observer();
$lock = (((intval($item['item_private'])) || (($item['uid'] == local_channel()) && (strlen($item['allow_cid']) || strlen($item['allow_gid']) $lock = ((($item['item_private'] == 1) || (($item['uid'] == local_channel()) && (strlen($item['allow_cid']) || strlen($item['allow_gid'])
|| strlen($item['deny_cid']) || strlen($item['deny_gid'])))) || strlen($item['deny_cid']) || strlen($item['deny_gid']))))
? t('Private Message') ? t('Private Message')
: false); : false);
@@ -110,7 +110,7 @@ class ThreadItem {
$shareable = true; $shareable = true;
$privacy_warning = false; $privacy_warning = false;
if(intval($item['item_private']) && ($item['owner']['xchan_network'] === 'activitypub')) { if(($item['item_private'] == 1) && ($item['owner']['xchan_network'] === 'activitypub')) {
$recips = get_iconfig($item['parent'], 'activitypub', 'recips'); $recips = get_iconfig($item['parent'], 'activitypub', 'recips');
if(! in_array($observer['xchan_url'], $recips['to'])) if(! in_array($observer['xchan_url'], $recips['to']))
@@ -778,6 +778,8 @@ class ThreadItem {
call_hooks('comment_buttons',$arr); call_hooks('comment_buttons',$arr);
$comment_buttons = $arr['comment_buttons']; $comment_buttons = $arr['comment_buttons'];
$feature_auto_save_draft = ((feature_enabled($conv->get_profile_owner(), 'auto_save_draft')) ? "true" : "false");
$comment_box = replace_macros($template,array( $comment_box = replace_macros($template,array(
'$return_path' => '', '$return_path' => '',
'$threaded' => $this->is_threaded(), '$threaded' => $this->is_threaded(),
@@ -812,7 +814,8 @@ class ThreadItem {
'$anoncomments' => ((($conv->get_mode() === 'channel' || $conv->get_mode() === 'display') && perm_is_allowed($conv->get_profile_owner(),'','post_comments')) ? true : false), '$anoncomments' => ((($conv->get_mode() === 'channel' || $conv->get_mode() === 'display') && perm_is_allowed($conv->get_profile_owner(),'','post_comments')) ? true : false),
'$anonname' => [ 'anonname', t('Your full name (required)') ], '$anonname' => [ 'anonname', t('Your full name (required)') ],
'$anonmail' => [ 'anonmail', t('Your email address (required)') ], '$anonmail' => [ 'anonmail', t('Your email address (required)') ],
'$anonurl' => [ 'anonurl', t('Your website URL (optional)') ] '$anonurl' => [ 'anonurl', t('Your website URL (optional)') ],
'$auto_save_draft' => $feature_auto_save_draft
)); ));
return $comment_box; return $comment_box;

View File

@@ -2,7 +2,7 @@
namespace Zotlabs\Lib; namespace Zotlabs\Lib;
use Zotlabs\Web\HTTPSig; use Zotlabs\Zot6\HTTPSig;
class ZotURL { class ZotURL {

View File

@@ -2,7 +2,7 @@
namespace Zotlabs\Lib; namespace Zotlabs\Lib;
use Zotlabs\Web\HTTPSig; use Zotlabs\Zot6\HTTPSig;
class Zotfinger { class Zotfinger {

View File

@@ -0,0 +1,42 @@
<?php
$auth_sister_ver = 'Ver.0.3.5.alpha';
/*
===========================================================
■PHP用認証モジュール 
〝妹認証 Auth-sister〟
http://www.okanesuita.org/auth_sister/
■著作権情報
Copyright (C) 2008 菅礼紗(http://www.okanesuita.org/).
■ライセンス
・MIT License (http://www.opensource.org/licenses/mit-license.php)
1.本スクリプトは無償であり、かつ誰でも無制限に使うことができる。
但し、著作権表示および本許諾表示を、すべての複製または重要な部分に記載しなければならない。
2.開発者は、本スクリプトに関して生じる事の一切の責任を負わない。
===========================================================
*/
/* 一般設定 */
$auth_sister_load = 'reiya'; //認証に使う妹パッケージ
$auth_sister_mes_a = '妹「'; //メッセージ先頭に付加する文字列
$auth_sister_mes_b = '」'; //メッセージ最後に付加する文字列
/* フォーム送信設定 */
$auth_sister_method = 0;//メソッド(0=post, 1=get)GETだとエラーになる可能性がある
//$auth_sister_input = 2;
/* セッション設定(etc.php用) */
$ses_name = 'auth_sister_alpha';
//$ses_dir = '';
/* セキュリティ関連設定 */
$auth_sister_len_min = 2; //最小文字数(回答文)
$auth_sister_len_max = 10; //最大文字数(回答文)
$auth_sister_outlen = "$auth_sister_len_min$auth_sister_len_max文字でいれてー";//文字数範囲外のエラー文
//Copyright (C) 2008 菅礼紗(http://www.okanesuita.org/).
?>

View File

@@ -0,0 +1,217 @@
<?php
//Copyright (C) 2008 菅礼紗(http://www.okanesuita.org/).
//妹★関数-----------------------------------------------------------
//セッション初期化
function auth_session_start(){
require('auth_sister/config.inc.php');
if($ses_name) {session_name($ses_name);}
if($ses_dir) {session_save_path($ses_dir);}
session_start();
}
//妹ヘッダを挿入します
function auth_sister_header(){
require('auth_sister/config.inc.php');
require('auth_sister/'.$auth_sister_load.'/config.inc.php');
echo $auth_sister_header;
}
//妹認証の初期化
function auth_sister_load(){
require('auth_sister/config.inc.php');
$loc = 'auth_sister/'.$auth_sister_load.'/words.txt';//辞書ファイル読み込み
//ファイル存在する場合は続行
if(file_exists($loc)){
$lines = file($loc, FILE_IGNORE_NEW_LINES);
$cnt = count($lines); //行数カウント
$cnt--;
$point = mt_rand(0, $cnt); //乱数発生
//質問文 正解メッセージ 不正解メッセージ 正解文 正解文の処理モード 逆処理スイッチ
//↓回答文の処理モード
//未指定・0:入力されたすべての文字列を含む
//1:正規表現による
//2:完全一致
list(
$_SESSION['auth_sister_question'],//質問文
$_SESSION['auth_sister_res_true'],//正解メッセージ
$_SESSION['auth_sister_res_false'],//不正解メッセージ
$_SESSION['auth_sister_answer'],//正解文
$_SESSION['auth_sister_anmode'],//正解文の処理モード
$_SESSION['auth_sister_rebirth']//逆処理スイッチ(0=OFF/1=ON)
)=explode("\t",$lines[$point]);//各変数に読み出し
$_SESSION['auth_sister_ticket'] = true; //画像読込権
$_SESSION['auth_sister_authID'] = uniqid(rand()); //AuthID発行
//以下マクロ処理だよ!
//乱数発生だよ!
$ran = rand(1,9999);
//乱数を平仮名にしちゃうよ!
$ranran = $ran;
$ranran = str_replace("0","れい" ,$ranran);
$ranran = str_replace("1","いち" ,$ranran);
$ranran = str_replace("2","" ,$ranran);
$ranran = str_replace("3","さん" ,$ranran);
$ranran = str_replace("4","よん" ,$ranran);
$ranran = str_replace("5","" ,$ranran);
$ranran = str_replace("6","ろく" ,$ranran);
$ranran = str_replace("7","なな" ,$ranran);
$ranran = str_replace("8","はち" ,$ranran);
$ranran = str_replace("9","きゅう" ,$ranran);
//乱数を漢字にしちゃおうかな!
$kanran = $ran;
$kanran = str_replace("0","" ,$kanran);
$kanran = str_replace("1","" ,$kanran);
$kanran = str_replace("2","" ,$kanran);
$kanran = str_replace("3","" ,$kanran);
$kanran = str_replace("4","" ,$kanran);
$kanran = str_replace("5","" ,$kanran);
$kanran = str_replace("6","" ,$kanran);
$kanran = str_replace("7","" ,$kanran);
$kanran = str_replace("8","" ,$kanran);
$kanran = str_replace("9","" ,$kanran);
//こんどは画数だぞ!
$kankaku = $ran;
$kankaku = str_replace("0","0" ,$kankaku);
$kankaku = str_replace("1","" ,$kankaku);
$kankaku = str_replace("2","" ,$kankaku);
$kankaku = str_replace("3","" ,$kankaku);
$kankaku = str_replace("4","" ,$kankaku);
$kankaku = str_replace("5","" ,$kankaku);
$kankaku = str_replace("6","" ,$kankaku);
$kankaku = str_replace("7","" ,$kankaku);
$kankaku = str_replace("8","" ,$kankaku);
$kankaku = str_replace("9","" ,$kankaku);
//[rand]
$_SESSION['auth_sister_question'] = str_replace("[rand]", $ran, $_SESSION['auth_sister_question']);
$_SESSION['auth_sister_answer'] = str_replace("[rand]", $ran, $_SESSION['auth_sister_answer']);
//[rand_kana]
$_SESSION['auth_sister_question'] = str_replace("[rand_kana]", $ranran, $_SESSION['auth_sister_question']);
$_SESSION['auth_sister_answer'] = str_replace("[rand_kana]", $ranran, $_SESSION['auth_sister_answer']);
//[rand_kan]
$_SESSION['auth_sister_question'] = str_replace("[rand_kan]", $kanran, $_SESSION['auth_sister_question']);
$_SESSION['auth_sister_answer'] = str_replace("[rand_kan]", $kanran, $_SESSION['auth_sister_answer']);
//[rand_kankaku]
$_SESSION['auth_sister_question'] = str_replace("[rand_kankaku]", $kankaku, $_SESSION['auth_sister_question']);
}
}
//妹認証の表示セット 先に初期化しておくこと
function auth_sister_insert(){
require('auth_sister/config.inc.php');
require('auth_sister/'.$auth_sister_load.'/config.inc.php');
$output = str_replace("[authID]", $_SESSION['auth_sister_authID'], $auth_sister_html);//AuthID挿入
echo $output;
}
//auth_sister_auth()は認証成功の場合true、失敗の場合はfalseを返します。
function auth_sister_auth(){
require('auth_sister/config.inc.php');
$auth = false;
$select = false;
$authid= $_SESSION['auth_sister_authID'];
//---メソッド
switch($auth_sister_method):
case 0 :
$select = $_POST[$authid];
break;
case 1 :
$select = $_GET[$authid];
break;
endswitch;
if($select){
$select = mb_convert_encoding($select,"UTF-8","auto");//入力されたもの
$answer = mb_convert_encoding($_SESSION['auth_sister_answer'],"UTF-8","auto");//正解文
$mode = $_SESSION['auth_sister_anmode'];//処理モード
$len = mb_strlen ( $select , "UTF-8");//入力文の文字数
//文字数制限
if(($len>=$auth_sister_len_min)&&($len<=$auth_sister_len_max)){
//処理モード
switch($mode):
case 0://入力されたすべての文字列を含む
if(mb_strstr($answer,$select,0,"UTF-8")) { $auth = true; }
break;
case 1://正規表現による
if(mb_ereg($answer,$select)) { $auth = true; }
break;
case 2://完全一致
if($answer==$select) { $auth = true; }
break;
default://入力されたすべての文字列を含む
if(mb_strstr($answer,$select,0,"UTF-8")) { $auth = true; }
endswitch;
//逆処理
if($_SESSION['auth_sister_rebirth']==1){
if($auth) { $auth = false; }
else { $auth = true; }
}
//認証結果文
if($auth){
$_SESSION['auth_sister_res'] = $_SESSION['auth_sister_res_true'];
} else {
$_SESSION['auth_sister_res'] = $_SESSION['auth_sister_res_false'];
}
//文字数エラー
} else {
$_SESSION['auth_sister_res'] = $auth_sister_outlen;
$auth = false;
}
}
return($auth);
}
//認証成功・失敗メッセージを返します
function auth_sister_res(){
require('auth_sister/config.inc.php');
$res = $auth_sister_mes_a.$_SESSION['auth_sister_res'].$auth_sister_mes_b;
return($res);
}
//イメージ出力-----------------------------------------------------------
$mode = $_GET['mode'];
switch($mode):
case "img":
require('config.inc.php');
if($ses_name) {session_name($ses_name);}
if($ses_dir) {session_save_path($ses_dir);}
session_start();
if($_SESSION['auth_sister_ticket']){
require($auth_sister_load.'/config.inc.php');
putenv('GDFONTPATH=' . realpath($auth_sister_fpath));
header("Content-type: image/png");
$text=$_SESSION['auth_sister_question'];
$text=mb_convert_encoding($text, "UTF-8", "auto");
$img = imagecreatefrompng($auth_sister_load.'/'.$auth_sister_image);
$color = imagecolorallocate($img,0x11,0x11,0x11); //文字色
imagettftext($img, $auth_sister_fsize, 0, $auth_sister_fx, $auth_sister_fy, $color, $auth_sister_font, $text );
//画像形式
if($_GET['type']==".png"){
imagepng($img); }
/*
if($_GET['type']==".jpg"){
imagejpeg($img,NULL,100)
}
*/
imagedestroy($img);
$_SESSION['auth_sister_ticket'] = false;
}else{
echo "Forbidden";
}
break;
endswitch;
?>

View File

@@ -0,0 +1,2 @@
mbstring.internal_encoding = UTF-8;
mbstring.http_output = UTF-8;

View File

@@ -0,0 +1,3 @@
<Files ~ ".(htaccess|htpasswd|txt|php)$">
deny from all
</Files>

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 B

View File

@@ -0,0 +1,27 @@
<?php
$auth_sister_image = 'reiya.png';
$auth_sister_fpath = './reiya';
$auth_sister_font = 'FONT_HERE';
$auth_sister_fsize = 10;
$auth_sister_fx = 100;
$auth_sister_fy = 50;
//妹ヘッダ
$auth_sister_header = '<link rel="stylesheet" type="text/css" href="auth_sister/reiya/style.css" />';
//表示部分
$auth_sister_html = '<div class="reiya">
<div class="reiyareiya">
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td><input name="[authID]" type="text" class="reiya_input" id="[authID]" /></td>
<td><input name="button" type="submit" class="reiya_submit" id="button" value="送信" /></td>
</tr>
</table>
</div>
</div>';
?>

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

View File

@@ -0,0 +1,38 @@
@charset "utf-8";
/* CSS Document */
.reiya {
background-image: url(../core.php?mode=img&type=.png);
background-repeat: no-repeat;
height: 150px;
width: 400px;
}
.reiyareiya{
position:relative;
top:95px;
left:90px;
}
.reiya_input {
padding:0px;
margin:0px;
background-image: url(bg1.png);
background-repeat:repeat-x;
height: 25px;
width: 230px;
border: 1px #000 solid;
font-family:" Pゴシック", Osaka, "ヒラギノ角ゴ Pro W3";
font-size:18px;
font-weight:bold;
}
.reiya_submit {
padding:0px;
margin:0px;
background-image: url(bg2.png);
background-repeat:repeat-x;
height: 27px;
width: 50px;
border: 1px #000 solid;
font-family:" Pゴシック", Osaka, "ヒラギノ角ゴ Pro W3";
font-size:18px;
color:#fff;
}

View File

@@ -0,0 +1,8 @@
れいにゃ大好きって言って(完全一致・新機能) れいにゃもおにーちゃんのこと大好き♪ (怒) れいにゃ大好き 2
おにーちゃん私の煎餅たべたでしょー(部分一致) いいよ、別に♪ 嘘つき! ごめんよごめんねすまんかった悪かったすまなかった俺のプリン食べただろれいにゃ大好き
れいにゃ大好きって言わないで(完全不一致・新) 認証成功だよ 言わないでっていったでしょ れいにゃ大好き 2 1
[rand]を漢字にして(乱数+漢字乱数マクロ・新) よくできたねー 間違ったね [rand_kan] 2
[rand_kan]を数字にして(乱数+漢字乱数マクロ・新) よくできたねー 間違ったね [rand] 2
[rand_kana]を漢字にして(乱数+かな乱数マクロ・新) よくできたねー 間違ったね [rand_kan] 2
[rand]を二回言え!(乱数マクロ・新) よくできたねっ ばーか! [rand][rand] 2
それぞれ「[rand_kankaku]」の画数をかけ0は0。(新) すごいすごーい! ぶっぶー [rand] 2

View File

@@ -0,0 +1,42 @@
<?php
$auth_sister_ver = 'Ver.0.3.5.alpha';
/*
===========================================================
■PHP用認証モジュール 
〝妹認証 Auth-sister〟
http://www.okanesuita.org/auth_sister/
■著作権情報
Copyright (C) 2008 菅礼紗(http://www.okanesuita.org/).
■ライセンス
・MIT License (http://www.opensource.org/licenses/mit-license.php)
1.本スクリプトは無償であり、かつ誰でも無制限に使うことができる。
但し、著作権表示および本許諾表示を、すべての複製または重要な部分に記載しなければならない。
2.開発者は、本スクリプトに関して生じる事の一切の責任を負わない。
===========================================================
*/
/* 一般設定 */
$auth_sister_load = 'reiya'; //認証に使う妹パッケージ
$auth_sister_mes_a = '妹「'; //メッセージ先頭に付加する文字列
$auth_sister_mes_b = '」'; //メッセージ最後に付加する文字列
/* フォーム送信設定 */
$auth_sister_method = 0;//メソッド(0=post, 1=get)GETだとエラーになる可能性がある
//$auth_sister_input = 2;
/* セッション設定(etc.php用) */
$ses_name = 'auth_sister_alpha';
//$ses_dir = '';
/* セキュリティ関連設定 */
$auth_sister_len_min = 2; //最小文字数(回答文)
$auth_sister_len_max = 10; //最大文字数(回答文)
$auth_sister_outlen = "$auth_sister_len_min$auth_sister_len_max文字でいれてー";//文字数範囲外のエラー文
//Copyright (C) 2008 菅礼紗(http://www.okanesuita.org/).
?>

View File

@@ -0,0 +1,217 @@
<?php
//Copyright (C) 2008 菅礼紗(http://www.okanesuita.org/).
//妹★関数-----------------------------------------------------------
//セッション初期化
function auth_session_start(){
require('auth_sister/config.inc.php');
if($ses_name) {session_name($ses_name);}
if($ses_dir) {session_save_path($ses_dir);}
session_start();
}
//妹ヘッダを挿入します
function auth_sister_header(){
require('auth_sister/config.inc.php');
require('auth_sister/'.$auth_sister_load.'/config.inc.php');
echo $auth_sister_header;
}
//妹認証の初期化
function auth_sister_load(){
require('auth_sister/config.inc.php');
$loc = 'auth_sister/'.$auth_sister_load.'/words.txt';//辞書ファイル読み込み
//ファイル存在する場合は続行
if(file_exists($loc)){
$lines = file($loc, FILE_IGNORE_NEW_LINES);
$cnt = count($lines); //行数カウント
$cnt--;
$point = mt_rand(0, $cnt); //乱数発生
//質問文 正解メッセージ 不正解メッセージ 正解文 正解文の処理モード 逆処理スイッチ
//↓回答文の処理モード
//未指定・0:入力されたすべての文字列を含む
//1:正規表現による
//2:完全一致
list(
$_SESSION['auth_sister_question'],//質問文
$_SESSION['auth_sister_res_true'],//正解メッセージ
$_SESSION['auth_sister_res_false'],//不正解メッセージ
$_SESSION['auth_sister_answer'],//正解文
$_SESSION['auth_sister_anmode'],//正解文の処理モード
$_SESSION['auth_sister_rebirth']//逆処理スイッチ(0=OFF/1=ON)
)=explode("\t",$lines[$point]);//各変数に読み出し
$_SESSION['auth_sister_ticket'] = true; //画像読込権
$_SESSION['auth_sister_authID'] = uniqid(rand()); //AuthID発行
//以下マクロ処理だよ!
//乱数発生だよ!
$ran = rand(1,9999);
//乱数を平仮名にしちゃうよ!
$ranran = $ran;
$ranran = str_replace("0","れい" ,$ranran);
$ranran = str_replace("1","いち" ,$ranran);
$ranran = str_replace("2","" ,$ranran);
$ranran = str_replace("3","さん" ,$ranran);
$ranran = str_replace("4","よん" ,$ranran);
$ranran = str_replace("5","" ,$ranran);
$ranran = str_replace("6","ろく" ,$ranran);
$ranran = str_replace("7","なな" ,$ranran);
$ranran = str_replace("8","はち" ,$ranran);
$ranran = str_replace("9","きゅう" ,$ranran);
//乱数を漢字にしちゃおうかな!
$kanran = $ran;
$kanran = str_replace("0","" ,$kanran);
$kanran = str_replace("1","" ,$kanran);
$kanran = str_replace("2","" ,$kanran);
$kanran = str_replace("3","" ,$kanran);
$kanran = str_replace("4","" ,$kanran);
$kanran = str_replace("5","" ,$kanran);
$kanran = str_replace("6","" ,$kanran);
$kanran = str_replace("7","" ,$kanran);
$kanran = str_replace("8","" ,$kanran);
$kanran = str_replace("9","" ,$kanran);
//こんどは画数だぞ!
$kankaku = $ran;
$kankaku = str_replace("0","0" ,$kankaku);
$kankaku = str_replace("1","" ,$kankaku);
$kankaku = str_replace("2","" ,$kankaku);
$kankaku = str_replace("3","" ,$kankaku);
$kankaku = str_replace("4","" ,$kankaku);
$kankaku = str_replace("5","" ,$kankaku);
$kankaku = str_replace("6","" ,$kankaku);
$kankaku = str_replace("7","" ,$kankaku);
$kankaku = str_replace("8","" ,$kankaku);
$kankaku = str_replace("9","" ,$kankaku);
//[rand]
$_SESSION['auth_sister_question'] = str_replace("[rand]", $ran, $_SESSION['auth_sister_question']);
$_SESSION['auth_sister_answer'] = str_replace("[rand]", $ran, $_SESSION['auth_sister_answer']);
//[rand_kana]
$_SESSION['auth_sister_question'] = str_replace("[rand_kana]", $ranran, $_SESSION['auth_sister_question']);
$_SESSION['auth_sister_answer'] = str_replace("[rand_kana]", $ranran, $_SESSION['auth_sister_answer']);
//[rand_kan]
$_SESSION['auth_sister_question'] = str_replace("[rand_kan]", $kanran, $_SESSION['auth_sister_question']);
$_SESSION['auth_sister_answer'] = str_replace("[rand_kan]", $kanran, $_SESSION['auth_sister_answer']);
//[rand_kankaku]
$_SESSION['auth_sister_question'] = str_replace("[rand_kankaku]", $kankaku, $_SESSION['auth_sister_question']);
}
}
//妹認証の表示セット 先に初期化しておくこと
function auth_sister_insert(){
require('auth_sister/config.inc.php');
require('auth_sister/'.$auth_sister_load.'/config.inc.php');
$output = str_replace("[authID]", $_SESSION['auth_sister_authID'], $auth_sister_html);//AuthID挿入
echo $output;
}
//auth_sister_auth()は認証成功の場合true、失敗の場合はfalseを返します。
function auth_sister_auth(){
require('auth_sister/config.inc.php');
$auth = false;
$select = false;
$authid= $_SESSION['auth_sister_authID'];
//---メソッド
switch($auth_sister_method):
case 0 :
$select = $_POST[$authid];
break;
case 1 :
$select = $_GET[$authid];
break;
endswitch;
if($select){
$select = mb_convert_encoding($select,"UTF-8","auto");//入力されたもの
$answer = mb_convert_encoding($_SESSION['auth_sister_answer'],"UTF-8","auto");//正解文
$mode = $_SESSION['auth_sister_anmode'];//処理モード
$len = mb_strlen ( $select , "UTF-8");//入力文の文字数
//文字数制限
if(($len>=$auth_sister_len_min)&&($len<=$auth_sister_len_max)){
//処理モード
switch($mode):
case 0://入力されたすべての文字列を含む
if(mb_strstr($answer,$select,0,"UTF-8")) { $auth = true; }
break;
case 1://正規表現による
if(mb_ereg($answer,$select)) { $auth = true; }
break;
case 2://完全一致
if($answer==$select) { $auth = true; }
break;
default://入力されたすべての文字列を含む
if(mb_strstr($answer,$select,0,"UTF-8")) { $auth = true; }
endswitch;
//逆処理
if($_SESSION['auth_sister_rebirth']==1){
if($auth) { $auth = false; }
else { $auth = true; }
}
//認証結果文
if($auth){
$_SESSION['auth_sister_res'] = $_SESSION['auth_sister_res_true'];
} else {
$_SESSION['auth_sister_res'] = $_SESSION['auth_sister_res_false'];
}
//文字数エラー
} else {
$_SESSION['auth_sister_res'] = $auth_sister_outlen;
$auth = false;
}
}
return($auth);
}
//認証成功・失敗メッセージを返します
function auth_sister_res(){
require('auth_sister/config.inc.php');
$res = $auth_sister_mes_a.$_SESSION['auth_sister_res'].$auth_sister_mes_b;
return($res);
}
//イメージ出力-----------------------------------------------------------
$mode = $_GET['mode'];
switch($mode):
case "img":
require('config.inc.php');
if($ses_name) {session_name($ses_name);}
if($ses_dir) {session_save_path($ses_dir);}
session_start();
if($_SESSION['auth_sister_ticket']){
require($auth_sister_load.'/config.inc.php');
putenv('GDFONTPATH=' . realpath($auth_sister_fpath));
header("Content-type: image/png");
$text=$_SESSION['auth_sister_question'];
$text=mb_convert_encoding($text, "UTF-8", "auto");
$img = imagecreatefrompng($auth_sister_load.'/'.$auth_sister_image);
$color = imagecolorallocate($img,0x11,0x11,0x11); //文字色
imagettftext($img, $auth_sister_fsize, 0, $auth_sister_fx, $auth_sister_fy, $color, $auth_sister_font, $text );
//画像形式
if($_GET['type']==".png"){
imagepng($img); }
/*
if($_GET['type']==".jpg"){
imagejpeg($img,NULL,100)
}
*/
imagedestroy($img);
$_SESSION['auth_sister_ticket'] = false;
}else{
echo "Forbidden";
}
break;
endswitch;
?>

View File

@@ -0,0 +1,2 @@
mbstring.internal_encoding = UTF-8;
mbstring.http_output = UTF-8;

View File

@@ -0,0 +1,3 @@
<Files ~ ".(htaccess|htpasswd|txt|php)$">
deny from all
</Files>

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 B

View File

@@ -0,0 +1,27 @@
<?php
$auth_sister_image = 'reiya.png';
$auth_sister_fpath = './reiya';
$auth_sister_font = 'FONT_HERE';
$auth_sister_fsize = 10;
$auth_sister_fx = 100;
$auth_sister_fy = 50;
//妹ヘッダ
$auth_sister_header = '<link rel="stylesheet" type="text/css" href="auth_sister/reiya/style.css" />';
//表示部分
$auth_sister_html = '<div class="reiya">
<div class="reiyareiya">
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td><input name="[authID]" type="text" class="reiya_input" id="[authID]" /></td>
<td><input name="button" type="submit" class="reiya_submit" id="button" value="送信" /></td>
</tr>
</table>
</div>
</div>';
?>

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

View File

@@ -0,0 +1,38 @@
@charset "utf-8";
/* CSS Document */
.reiya {
background-image: url(../core.php?mode=img&type=.png);
background-repeat: no-repeat;
height: 150px;
width: 400px;
}
.reiyareiya{
position:relative;
top:95px;
left:90px;
}
.reiya_input {
padding:0px;
margin:0px;
background-image: url(bg1.png);
background-repeat:repeat-x;
height: 25px;
width: 230px;
border: 1px #000 solid;
font-family:" Pゴシック", Osaka, "ヒラギノ角ゴ Pro W3";
font-size:18px;
font-weight:bold;
}
.reiya_submit {
padding:0px;
margin:0px;
background-image: url(bg2.png);
background-repeat:repeat-x;
height: 27px;
width: 50px;
border: 1px #000 solid;
font-family:" Pゴシック", Osaka, "ヒラギノ角ゴ Pro W3";
font-size:18px;
color:#fff;
}

View File

@@ -0,0 +1,8 @@
れいにゃ大好きって言って(完全一致・新機能) れいにゃもおにーちゃんのこと大好き♪ (怒) れいにゃ大好き 2
おにーちゃん私の煎餅たべたでしょー(部分一致) いいよ、別に♪ 嘘つき! ごめんよごめんねすまんかった悪かったすまなかった俺のプリン食べただろれいにゃ大好き
れいにゃ大好きって言わないで(完全不一致・新) 認証成功だよ 言わないでっていったでしょ れいにゃ大好き 2 1
[rand]を漢字にして(乱数+漢字乱数マクロ・新) よくできたねー 間違ったね [rand_kan] 2
[rand_kan]を数字にして(乱数+漢字乱数マクロ・新) よくできたねー 間違ったね [rand] 2
[rand_kana]を漢字にして(乱数+かな乱数マクロ・新) よくできたねー 間違ったね [rand_kan] 2
[rand]を二回言え!(乱数マクロ・新) よくできたねっ ばーか! [rand][rand] 2
それぞれ「[rand_kankaku]」の画数をかけ0は0。(新) すごいすごーい! ぶっぶー [rand] 2

View File

@@ -2,7 +2,6 @@
namespace Zotlabs\Module\Admin; namespace Zotlabs\Module\Admin;
use App;
use \Zotlabs\Storage\GitRepo; use \Zotlabs\Storage\GitRepo;
use \Michelf\MarkdownExtra; use \Michelf\MarkdownExtra;
@@ -254,14 +253,14 @@ class Addons {
* Single plugin * Single plugin
*/ */
if (App::$argc == 3){ if (\App::$argc == 3){
$plugin = App::$argv[2]; $plugin = \App::$argv[2];
if (!is_file("addon/$plugin/$plugin.php")){ if (!is_file("addon/$plugin/$plugin.php")){
notice( t("Item not found.") ); notice( t("Item not found.") );
return ''; return '';
} }
$enabled = in_array($plugin,App::$plugins); $enabled = in_array($plugin,\App::$plugins);
$info = get_plugin_info($plugin); $info = get_plugin_info($plugin);
$x = check_plugin_versions($info); $x = check_plugin_versions($info);
@@ -269,11 +268,11 @@ class Addons {
if($enabled && ! $x) { if($enabled && ! $x) {
$enabled = false; $enabled = false;
$idz = array_search($plugin, App::$plugins); $idz = array_search($plugin, \App::$plugins);
if ($idz !== false) { if ($idz !== false) {
unset(App::$plugins[$idz]); unset(\App::$plugins[$idz]);
uninstall_plugin($plugin); uninstall_plugin($plugin);
set_config("system","addon", implode(", ",App::$plugins)); set_config("system","addon", implode(", ",\App::$plugins));
} }
} }
$info['disabled'] = 1-intval($x); $info['disabled'] = 1-intval($x);
@@ -282,19 +281,19 @@ class Addons {
check_form_security_token_redirectOnErr('/admin/addons', 'admin_addons', 't'); check_form_security_token_redirectOnErr('/admin/addons', 'admin_addons', 't');
$pinstalled = false; $pinstalled = false;
// Toggle plugin status // Toggle plugin status
$idx = array_search($plugin, App::$plugins); $idx = array_search($plugin, \App::$plugins);
if ($idx !== false){ if ($idx !== false){
unset(App::$plugins[$idx]); unset(\App::$plugins[$idx]);
uninstall_plugin($plugin); uninstall_plugin($plugin);
$pinstalled = false; $pinstalled = false;
info( sprintf( t("Plugin %s disabled."), $plugin ) ); info( sprintf( t("Plugin %s disabled."), $plugin ) );
} else { } else {
App::$plugins[] = $plugin; \App::$plugins[] = $plugin;
install_plugin($plugin); install_plugin($plugin);
$pinstalled = true; $pinstalled = true;
info( sprintf( t("Plugin %s enabled."), $plugin ) ); info( sprintf( t("Plugin %s enabled."), $plugin ) );
} }
set_config("system","addon", implode(", ",App::$plugins)); set_config("system","addon", implode(", ",\App::$plugins));
if($pinstalled) { if($pinstalled) {
@require_once("addon/$plugin/$plugin.php"); @require_once("addon/$plugin/$plugin.php");
@@ -306,7 +305,7 @@ class Addons {
// display plugin details // display plugin details
if (in_array($plugin, App::$plugins)){ if (in_array($plugin, \App::$plugins)){
$status = 'on'; $status = 'on';
$action = t('Disable'); $action = t('Disable');
} else { } else {
@@ -381,18 +380,18 @@ class Addons {
list($tmp, $id) = array_map('trim', explode('/', $file)); list($tmp, $id) = array_map('trim', explode('/', $file));
$info = get_plugin_info($id); $info = get_plugin_info($id);
$enabled = in_array($id,App::$plugins); $enabled = in_array($id,\App::$plugins);
$x = check_plugin_versions($info); $x = check_plugin_versions($info);
// disable plugins which are installed but incompatible versions // disable plugins which are installed but incompatible versions
if($enabled && ! $x) { if($enabled && ! $x) {
$enabled = false; $enabled = false;
$idz = array_search($id, App::$plugins); $idz = array_search($id, \App::$plugins);
if ($idz !== false) { if ($idz !== false) {
unset(App::$plugins[$idz]); unset(\App::$plugins[$idz]);
uninstall_plugin($id); uninstall_plugin($id);
set_config("system","addon", implode(", ",App::$plugins)); set_config("system","addon", implode(", ",\App::$plugins));
} }
} }
$info['disabled'] = 1-intval($x); $info['disabled'] = 1-intval($x);

View File

@@ -44,12 +44,6 @@ class Security {
$be = $this->trim_array_elems(explode("\n",$_POST['embed_deny'])); $be = $this->trim_array_elems(explode("\n",$_POST['embed_deny']));
set_config('system','embed_deny',$be); set_config('system','embed_deny',$be);
$thumbnail_security = ((x($_POST,'thumbnail_security')) ? intval($_POST['thumbnail_security']) : 0);
set_config('system', 'thumbnail_security' , $thumbnail_security);
$inline_pdf = ((x($_POST,'inline_pdf')) ? intval($_POST['inline_pdf']) : 0);
set_config('system', 'inline_pdf' , $inline_pdf);
$ts = ((x($_POST,'transport_security')) ? True : False); $ts = ((x($_POST,'transport_security')) ? True : False);
set_config('system','transport_security_header',$ts); set_config('system','transport_security_header',$ts);
@@ -112,8 +106,6 @@ class Security {
'$embed_sslonly' => array('embed_sslonly',t('Only allow embeds from secure (SSL) websites and links.'), intval(get_config('system','embed_sslonly')),''), '$embed_sslonly' => array('embed_sslonly',t('Only allow embeds from secure (SSL) websites and links.'), intval(get_config('system','embed_sslonly')),''),
'$embed_allow' => array('embed_allow', t('Allow unfiltered embedded HTML content only from these domains'), $whiteembeds_str, t('One site per line. By default embedded content is filtered.')), '$embed_allow' => array('embed_allow', t('Allow unfiltered embedded HTML content only from these domains'), $whiteembeds_str, t('One site per line. By default embedded content is filtered.')),
'$embed_deny' => array('embed_deny', t('Block embedded HTML from these domains'), $blackembeds_str, ''), '$embed_deny' => array('embed_deny', t('Block embedded HTML from these domains'), $blackembeds_str, ''),
'$thumbnail_security' => [ 'thumbnail_security', t("Allow SVG thumbnails in file browser"), get_config('system','thumbnail_security',0), t("WARNING: SVG images may contain malicious code.") ],
'$inline_pdf' => [ 'inline_pdf', t("Allow embedded (inline) PDF files"), get_config('system','inline_pdf',0), '' ],
// '$embed_coop' => array('embed_coop', t('Cooperative embed security'), $embed_coop, t('Enable to share embed security with other compatible sites/hubs')), // '$embed_coop' => array('embed_coop', t('Cooperative embed security'), $embed_coop, t('Enable to share embed security with other compatible sites/hubs')),

View File

@@ -73,6 +73,7 @@ class Site {
$feed_contacts = ((x($_POST,'feed_contacts')) ? intval($_POST['feed_contacts']) : 0); $feed_contacts = ((x($_POST,'feed_contacts')) ? intval($_POST['feed_contacts']) : 0);
$verify_email = ((x($_POST,'verify_email')) ? 1 : 0); $verify_email = ((x($_POST,'verify_email')) ? 1 : 0);
$imagick_path = ((x($_POST,'imagick_path')) ? trim($_POST['imagick_path']) : ''); $imagick_path = ((x($_POST,'imagick_path')) ? trim($_POST['imagick_path']) : '');
$thumbnail_security = ((x($_POST,'thumbnail_security')) ? intval($_POST['thumbnail_security']) : 0);
$force_queue = ((intval($_POST['force_queue']) > 0) ? intval($_POST['force_queue']) : 3000); $force_queue = ((intval($_POST['force_queue']) > 0) ? intval($_POST['force_queue']) : 3000);
$pub_incl = escape_tags(trim($_POST['pub_incl'])); $pub_incl = escape_tags(trim($_POST['pub_incl']));
$pub_excl = escape_tags(trim($_POST['pub_excl'])); $pub_excl = escape_tags(trim($_POST['pub_excl']));
@@ -99,6 +100,7 @@ class Site {
set_config('system', 'from_email', $from_email); set_config('system', 'from_email', $from_email);
set_config('system', 'from_email_name' , $from_email_name); set_config('system', 'from_email_name' , $from_email_name);
set_config('system', 'imagick_convert_path' , $imagick_path); set_config('system', 'imagick_convert_path' , $imagick_path);
set_config('system', 'thumbnail_security' , $thumbnail_security);
set_config('system', 'default_permissions_role', $permissions_role); set_config('system', 'default_permissions_role', $permissions_role);
set_config('system', 'pubstream_incl',$pub_incl); set_config('system', 'pubstream_incl',$pub_incl);
set_config('system', 'pubstream_excl',$pub_excl); set_config('system', 'pubstream_excl',$pub_excl);
@@ -339,6 +341,7 @@ class Site {
'$force_queue' => array('force_queue', t("Queue Threshold"), get_config('system','force_queue_threshold',3000), t("Always defer immediate delivery if queue contains more than this number of entries.")), '$force_queue' => array('force_queue', t("Queue Threshold"), get_config('system','force_queue_threshold',3000), t("Always defer immediate delivery if queue contains more than this number of entries.")),
'$poll_interval' => array('poll_interval', t("Poll interval"), (x(get_config('system','poll_interval'))?get_config('system','poll_interval'):2), t("Delay background polling processes by this many seconds to reduce system load. If 0, use delivery interval.")), '$poll_interval' => array('poll_interval', t("Poll interval"), (x(get_config('system','poll_interval'))?get_config('system','poll_interval'):2), t("Delay background polling processes by this many seconds to reduce system load. If 0, use delivery interval.")),
'$imagick_path' => array('imagick_path', t("Path to ImageMagick convert program"), get_config('system','imagick_convert_path'), t("If set, use this program to generate photo thumbnails for huge images ( > 4000 pixels in either dimension), otherwise memory exhaustion may occur. Example: /usr/bin/convert")), '$imagick_path' => array('imagick_path', t("Path to ImageMagick convert program"), get_config('system','imagick_convert_path'), t("If set, use this program to generate photo thumbnails for huge images ( > 4000 pixels in either dimension), otherwise memory exhaustion may occur. Example: /usr/bin/convert")),
'$thumbnail_security' => array('thumbnail_security', t("Allow SVG thumbnails in file browser"), get_config('system','thumbnail_security',0), t("WARNING: SVG images may contain malicious code.")),
'$maxloadavg' => array('maxloadavg', t("Maximum Load Average"), ((intval(get_config('system','maxloadavg')) > 0)?get_config('system','maxloadavg'):50), t("Maximum system load before delivery and poll processes are deferred - default 50.")), '$maxloadavg' => array('maxloadavg', t("Maximum Load Average"), ((intval(get_config('system','maxloadavg')) > 0)?get_config('system','maxloadavg'):50), t("Maximum system load before delivery and poll processes are deferred - default 50.")),
'$default_expire_days' => array('default_expire_days', t('Expiration period in days for imported (grid/network) content'), intval(get_config('system','default_expire_days')), t('0 for no expiration of imported content')), '$default_expire_days' => array('default_expire_days', t('Expiration period in days for imported (grid/network) content'), intval(get_config('system','default_expire_days')), t('0 for no expiration of imported content')),
'$active_expire_days' => array('active_expire_days', t('Do not expire any posts which have comments less than this many days ago'), intval(get_config('system','active_expire_days',7)), ''), '$active_expire_days' => array('active_expire_days', t('Do not expire any posts which have comments less than this many days ago'), intval(get_config('system','active_expire_days',7)), ''),

View File

@@ -28,7 +28,6 @@ class Apschema extends \Zotlabs\Web\Controller {
'nomadicHubs' => 'zot:nomadicHubs', 'nomadicHubs' => 'zot:nomadicHubs',
'emojiReaction' => 'zot:emojiReaction', 'emojiReaction' => 'zot:emojiReaction',
'expires' => 'zot:expires', 'expires' => 'zot:expires',
'directMessage' => 'zot:directMessage',
'magicEnv' => [ 'magicEnv' => [
'@id' => 'zot:magicEnv', '@id' => 'zot:magicEnv',
@@ -41,12 +40,7 @@ class Apschema extends \Zotlabs\Web\Controller {
], ],
'ostatus' => 'http://ostatus.org#', 'ostatus' => 'http://ostatus.org#',
'conversation' => 'ostatus:conversation', 'conversation' => 'ostatus:conversation'
'diaspora' => 'https://diasporafoundation.org/ns/',
'guid' => 'diaspora:guid',
'Hashtag' => 'as:Hashtag'
] ]
]; ];

View File

@@ -85,9 +85,10 @@ class Article_edit extends \Zotlabs\Web\Controller {
$mimetype = $itm[0]['mimetype']; $mimetype = $itm[0]['mimetype'];
$summary = (($itm[0]['summary']) ? '[summary]' . $itm[0]['summary'] . '[/summary]' . "\r\n" : '');
$content = $itm[0]['body']; $content = $itm[0]['body'];
$rp = 'articles/' . $channel['channel_address']; $rp = 'articles/' . $channel['channel_address'];
$x = array( $x = array(
@@ -109,7 +110,7 @@ class Article_edit extends \Zotlabs\Web\Controller {
'ptyp' => $itm[0]['type'], 'ptyp' => $itm[0]['type'],
'mimeselect' => false, 'mimeselect' => false,
'mimetype' => $itm[0]['mimetype'], 'mimetype' => $itm[0]['mimetype'],
'body' => $summary . undo_post_tagging($content), 'body' => undo_post_tagging($content),
'post_id' => $post_id, 'post_id' => $post_id,
'visitor' => true, 'visitor' => true,
'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'), 'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'),

View File

@@ -9,7 +9,6 @@ use Zotlabs\Lib\PermissionDescription;
require_once('include/channel.php'); require_once('include/channel.php');
require_once('include/conversation.php'); require_once('include/conversation.php');
require_once('include/acl_selectors.php'); require_once('include/acl_selectors.php');
require_once('include/opengraph.php');
class Articles extends Controller { class Articles extends Controller {
@@ -193,7 +192,7 @@ class Articles extends Controller {
$parents_str = ids_to_querystr($r,'id'); $parents_str = ids_to_querystr($r,'id');
$r = q("SELECT item.*, item.id AS item_id $items = q("SELECT item.*, item.id AS item_id
FROM item FROM item
WHERE item.uid = %d $item_normal WHERE item.uid = %d $item_normal
AND item.parent IN ( %s ) AND item.parent IN ( %s )
@@ -201,18 +200,15 @@ class Articles extends Controller {
intval(App::$profile['profile_uid']), intval(App::$profile['profile_uid']),
dbesc($parents_str) dbesc($parents_str)
); );
if($r) { if($items) {
xchan_query($r); xchan_query($items);
$items = fetch_post_tags($r, true); $items = fetch_post_tags($items, true);
$items = conv_sort($items,'updated'); $items = conv_sort($items,'updated');
} }
else else
$items = []; $items = [];
} }
// Add Opengraph markup
opengraph_add_meta((! empty($items) ? $r[0] : []), $channel);
$mode = 'articles'; $mode = 'articles';
if(get_pconfig(local_channel(),'system','articles_list_mode') && (! $selected_card)) if(get_pconfig(local_channel(),'system','articles_list_mode') && (! $selected_card))

View File

@@ -1,10 +1,6 @@
<?php <?php
namespace Zotlabs\Module; namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
require_once('include/conversation.php'); require_once('include/conversation.php');
require_once('include/bbcode.php'); require_once('include/bbcode.php');
require_once('include/datetime.php'); require_once('include/datetime.php');
@@ -13,13 +9,15 @@ require_once('include/items.php');
require_once('include/html2plain.php'); require_once('include/html2plain.php');
class Cal extends Controller { class Cal extends \Zotlabs\Web\Controller {
function init() { function init() {
if(observer_prohibited()) { if(observer_prohibited()) {
return; return;
} }
$o = '';
if(argc() > 1) { if(argc() > 1) {
$nick = argv(1); $nick = argv(1);
@@ -27,21 +25,19 @@ class Cal extends Controller {
$channelx = channelx_by_nick($nick); $channelx = channelx_by_nick($nick);
if(! $channelx) { if(! $channelx)
notice( t('Channel not found.') . EOL);
return; return;
}
App::$data['channel'] = $channelx; \App::$data['channel'] = $channelx;
$observer = App::get_observer(); $observer = \App::get_observer();
App::$data['observer'] = $observer; \App::$data['observer'] = $observer;
$observer_xchan = (($observer) ? $observer['xchan_hash'] : ''); $observer_xchan = (($observer) ? $observer['xchan_hash'] : '');
head_set_icon(App::$data['channel']['xchan_photo_s']); head_set_icon(\App::$data['channel']['xchan_photo_s']);
App::$page['htmlhead'] .= "<script> var profile_uid = " . ((App::$data['channel']) ? App::$data['channel']['channel_id'] : 0) . "; </script>" ; \App::$page['htmlhead'] .= "<script> var profile_uid = " . ((\App::$data['channel']) ? \App::$data['channel']['channel_id'] : 0) . "; </script>" ;
} }
@@ -56,7 +52,17 @@ class Cal extends Controller {
return; return;
} }
$channel = App::$data['channel']; $channel = null;
if(argc() > 1) {
$channel = channelx_by_nick(argv(1));
}
if(! $channel) {
notice( t('Channel not found.') . EOL);
return;
}
// since we don't currently have an event permission - use the stream permission // since we don't currently have an event permission - use the stream permission
@@ -67,23 +73,132 @@ class Cal extends Controller {
nav_set_selected('Calendar'); nav_set_selected('Calendar');
head_add_css('/library/fullcalendar/packages/core/main.min.css');
head_add_css('/library/fullcalendar/packages/daygrid/main.min.css');
head_add_css('cdav_calendar.css');
head_add_js('/library/fullcalendar/packages/core/main.min.js');
head_add_js('/library/fullcalendar/packages/daygrid/main.min.js');
$sql_extra = permissions_sql($channel['channel_id'],get_observer_hash(),'event'); $sql_extra = permissions_sql($channel['channel_id'],get_observer_hash(),'event');
if(! perm_is_allowed($channel['channel_id'], get_observer_hash(), 'view_contacts') || App::$profile['hide_friends']) $first_day = feature_enabled($channel['channel_id'], 'events_cal_first_day');
$sql_extra .= " and etype != 'birthday' ";
$first_day = feature_enabled($channel['channel_id'], 'cal_first_day');
$first_day = (($first_day) ? $first_day : 0); $first_day = (($first_day) ? $first_day : 0);
$start = ''; $htpl = get_markup_template('event_head.tpl');
$finish = ''; \App::$page['htmlhead'] .= replace_macros($htpl,array(
'$baseurl' => z_root(),
'$module_url' => '/cal/' . $channel['channel_address'],
'$modparams' => 2,
'$lang' => \App::$language,
'$timezone' => date_default_timezone_get(),
'$first_day' => $first_day
));
$o = '';
$mode = 'view';
$y = 0;
$m = 0;
$ignored = ((x($_REQUEST,'ignored')) ? " and dismissed = " . intval($_REQUEST['ignored']) . " " : '');
// logger('args: ' . print_r(\App::$argv,true));
if(argc() > 3 && intval(argv(2)) && intval(argv(3))) {
$mode = 'view';
$y = intval(argv(2));
$m = intval(argv(3));
}
if(argc() <= 3) {
$mode = 'view';
$event_id = argv(2);
}
if($mode == 'view') {
/* edit/create form */
if($event_id) {
$r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1",
dbesc($event_id),
intval($channel['channel_id'])
);
if(count($r))
$orig_event = $r[0];
}
// Passed parameters overrides anything found in the DB
if(!x($orig_event))
$orig_event = array();
$tz = date_default_timezone_get();
if(x($orig_event))
$tz = (($orig_event['adjust']) ? date_default_timezone_get() : 'UTC');
$syear = datetime_convert('UTC', $tz, $sdt, 'Y');
$smonth = datetime_convert('UTC', $tz, $sdt, 'm');
$sday = datetime_convert('UTC', $tz, $sdt, 'd');
$shour = datetime_convert('UTC', $tz, $sdt, 'H');
$sminute = datetime_convert('UTC', $tz, $sdt, 'i');
$stext = datetime_convert('UTC',$tz,$sdt);
$stext = substr($stext,0,14) . "00:00";
$fyear = datetime_convert('UTC', $tz, $fdt, 'Y');
$fmonth = datetime_convert('UTC', $tz, $fdt, 'm');
$fday = datetime_convert('UTC', $tz, $fdt, 'd');
$fhour = datetime_convert('UTC', $tz, $fdt, 'H');
$fminute = datetime_convert('UTC', $tz, $fdt, 'i');
$ftext = datetime_convert('UTC',$tz,$fdt);
$ftext = substr($ftext,0,14) . "00:00";
$type = ((x($orig_event)) ? $orig_event['etype'] : 'event');
$f = get_config('system','event_input_format');
if(! $f)
$f = 'ymd';
$catsenabled = feature_enabled($channel['channel_id'],'categories');
$show_bd = perm_is_allowed($channel['channel_id'], get_observer_hash(), 'view_contacts');
if(! $show_bd) {
$sql_extra .= " and event.etype != 'birthday' ";
}
$category = '';
$thisyear = datetime_convert('UTC',date_default_timezone_get(),'now','Y');
$thismonth = datetime_convert('UTC',date_default_timezone_get(),'now','m');
if(! $y)
$y = intval($thisyear);
if(! $m)
$m = intval($thismonth);
// Put some limits on dates. The PHP date functions don't seem to do so well before 1900.
// An upper limit was chosen to keep search engines from exploring links millions of years in the future.
if($y < 1901)
$y = 1900;
if($y > 2099)
$y = 2100;
$nextyear = $y;
$nextmonth = $m + 1;
if($nextmonth > 12) {
$nextmonth = 1;
$nextyear ++;
}
$prevyear = $y;
if($m > 1)
$prevmonth = $m - 1;
else {
$prevmonth = 12;
$prevyear --;
}
$dim = get_dim($y,$m);
$start = sprintf('%d-%d-%d %d:%d:%d',$y,$m,1,0,0,0);
$finish = sprintf('%d-%d-%d %d:%d:%d',$y,$m,$dim,23,59,59);
if (argv(2) === 'json'){ if (argv(2) === 'json'){
if (x($_GET,'start')) $start = $_GET['start']; if (x($_GET,'start')) $start = $_GET['start'];
@@ -92,13 +207,17 @@ class Cal extends Controller {
$start = datetime_convert('UTC','UTC',$start); $start = datetime_convert('UTC','UTC',$start);
$finish = datetime_convert('UTC','UTC',$finish); $finish = datetime_convert('UTC','UTC',$finish);
$adjust_start = datetime_convert('UTC', date_default_timezone_get(), $start); $adjust_start = datetime_convert('UTC', date_default_timezone_get(), $start);
$adjust_finish = datetime_convert('UTC', date_default_timezone_get(), $finish); $adjust_finish = datetime_convert('UTC', date_default_timezone_get(), $finish);
if(! perm_is_allowed(\App::$profile['uid'],get_observer_hash(),'view_contacts'))
$sql_extra .= " and etype != 'birthday' ";
if (x($_GET,'id')){ if (x($_GET,'id')){
$r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan, item.id as item_id $r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan, item.id as item_id
from event left join item on item.resource_id = event.event_hash from event left join item on resource_id = event_hash where resource_type = 'event' and event.uid = %d and event.id = %d $sql_extra limit 1",
where item.resource_type = 'event' and event.uid = %d and event.id = %d $sql_extra limit 1",
intval($channel['channel_id']), intval($channel['channel_id']),
intval($_GET['id']) intval($_GET['id'])
); );
@@ -108,36 +227,58 @@ class Cal extends Controller {
// There's still an issue if the finish date crosses the end of month. // There's still an issue if the finish date crosses the end of month.
// Noting this for now - it will need to be fixed here and in Friendica. // Noting this for now - it will need to be fixed here and in Friendica.
// Ultimately the finish date shouldn't be involved in the query. // Ultimately the finish date shouldn't be involved in the query.
$r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan, item.id as item_id $r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan, item.id as item_id
from event left join item on event.event_hash = item.resource_id from event left join item on event.event_hash = item.resource_id
where item.resource_type = 'event' and event.uid = %d and event.uid = item.uid where item.resource_type = 'event' and event.uid = %d and event.uid = item.uid $ignored
AND (( event.adjust = 0 AND ( event.dtend >= '%s' or event.nofinish = 1 ) AND event.dtstart <= '%s' ) AND (( event.adjust = 0 AND ( event.dtend >= '%s' or event.nofinish = 1 ) AND event.dtstart <= '%s' )
OR ( event.adjust = 1 AND ( event.dtend >= '%s' or event.nofinish = 1 ) AND event.dtstart <= '%s' )) OR ( event.adjust = 1 AND ( event.dtend >= '%s' or event.nofinish = 1 ) AND event.dtstart <= '%s' )) ",
$sql_extra", intval(local_channel()),
intval($channel['channel_id']),
dbesc($start), dbesc($start),
dbesc($finish), dbesc($finish),
dbesc($adjust_start), dbesc($adjust_start),
dbesc($adjust_finish) dbesc($adjust_finish)
); );
} }
$links = array();
if($r) { if($r) {
xchan_query($r); xchan_query($r);
$r = fetch_post_tags($r,true); $r = fetch_post_tags($r,true);
$r = sort_by_date($r); $r = sort_by_date($r);
} }
$events = []; if($r) {
foreach($r as $rr) {
$j = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtstart'], 'j') : datetime_convert('UTC','UTC',$rr['dtstart'],'j'));
if(! x($links,$j))
$links[$j] = z_root() . '/' . \App::$cmd . '#link-' . $j;
}
}
$events=array();
$last_date = '';
$fmt = t('l, F j');
if($r) { if($r) {
foreach($r as $rr) { foreach($r as $rr) {
$tz = get_iconfig($rr, 'event', 'timezone'); $tz = get_iconfig($rr, 'event', 'timezone');
if(! $tz) if(! $tz)
$tz = 'UTC'; $tz = 'UTC';
$rr['timezone'] = $tz;
$j = (($rr['adjust']) ? datetime_convert($tz,date_default_timezone_get(),$rr['dtstart'], 'j') : datetime_convert('UTC','UTC',$rr['dtstart'],'j'));
$d = (($rr['adjust']) ? datetime_convert($tz,date_default_timezone_get(),$rr['dtstart'], $fmt) : datetime_convert('UTC','UTC',$rr['dtstart'],$fmt));
$d = day_translate($d);
$start = (($rr['adjust']) ? datetime_convert($tz,date_default_timezone_get(),$rr['dtstart'], 'c') : datetime_convert('UTC','UTC',$rr['dtstart'],'c')); $start = (($rr['adjust']) ? datetime_convert($tz,date_default_timezone_get(),$rr['dtstart'], 'c') : datetime_convert('UTC','UTC',$rr['dtstart'],'c'));
if ($rr['nofinish']){ if ($rr['nofinish']){
$end = null; $end = null;
@@ -145,73 +286,81 @@ class Cal extends Controller {
$end = (($rr['adjust']) ? datetime_convert($tz,date_default_timezone_get(),$rr['dtend'], 'c') : datetime_convert('UTC','UTC',$rr['dtend'],'c')); $end = (($rr['adjust']) ? datetime_convert($tz,date_default_timezone_get(),$rr['dtend'], 'c') : datetime_convert('UTC','UTC',$rr['dtend'],'c'));
} }
$html = '';
if (x($_GET,'id')) {
$rr['timezone'] = $tz;
$html = format_event_html($rr);
}
$is_first = ($d !== $last_date);
$last_date = $d;
$edit = false;
$drop = false;
$title = strip_tags(html_entity_decode(bbcode($rr['summary']),ENT_QUOTES,'UTF-8'));
if(! $title) {
list($title, $_trash) = explode("<br",bbcode($rr['desc']),2);
$title = strip_tags(html_entity_decode($title,ENT_QUOTES,'UTF-8'));
}
$html = format_event_html($rr);
$rr['desc'] = zidify_links(smilies(bbcode($rr['desc'])));
$rr['description'] = htmlentities(html2plain(bbcode($rr['description'])),ENT_COMPAT,'UTF-8',false);
$rr['location'] = zidify_links(smilies(bbcode($rr['location'])));
$events[] = array( $events[] = array(
'calendar_id' => 'channel_calendar',
'rw' => true,
'id'=>$rr['id'], 'id'=>$rr['id'],
'uri' => $rr['event_hash'], 'hash' => $rr['event_hash'],
'timezone' => $tz,
'start'=> $start, 'start'=> $start,
'end' => $end, 'end' => $end,
'drop' => $drop, 'drop' => $drop,
'allDay' => (($rr['adjust']) ? 0 : 1), 'allDay' => (($rr['adjust']) ? 0 : 1),
'title' => html_entity_decode($rr['summary'], ENT_COMPAT, 'UTF-8'), 'title' => $title,
'editable' => $edit ? true : false,
'j' => $j,
'd' => $d,
'edit' => $edit,
'is_first'=>$is_first,
'item'=>$rr, 'item'=>$rr,
'plink' => [$rr['plink'], t('Link to source')], 'html'=>$html,
'description' => html_entity_decode($rr['description'], ENT_COMPAT, 'UTF-8'), 'plink' => array($rr['plink'],t('Link to Source'),'',''),
'location' => html_entity_decode($rr['location'], ENT_COMPAT, 'UTF-8'),
'allow_cid' => expand_acl($rr['allow_cid']),
'allow_gid' => expand_acl($rr['allow_gid']),
'deny_cid' => expand_acl($rr['deny_cid']),
'deny_gid' => expand_acl($rr['deny_gid']),
'html' => $html
); );
} }
} }
if (argv(2) === 'json'){ if (argv(2) === 'json'){
echo json_encode($events); echo json_encode($events); killme();
killme();
} }
// links: array('href', 'text', 'extra css classes', 'title')
if (x($_GET,'id')){ if (x($_GET,'id')){
$o = replace_macros(get_markup_template("cal_event.tpl"), [ $tpl = get_markup_template("event_cal.tpl");
'$events' => $events }
]); else {
echo $o; $tpl = get_markup_template("events_cal-js.tpl");
killme();
} }
$nick = $channel['channel_address']; $nick = $channel['channel_address'];
$sources = '{ $o = replace_macros($tpl, array(
id: \'channel_calendar\', '$baseurl' => z_root(),
url: \'/cal/' . $nick . '/json/\', '$new_event' => array(z_root().'/cal',(($event_id) ? t('Edit Event') : t('Create Event')),'',''),
color: \'#3a87ad\' '$previus' => array(z_root()."/cal/$nick/$prevyear/$prevmonth",t('Previous'),'',''),
}'; '$next' => array(z_root()."/cal/$nick/$nextyear/$nextmonth",t('Next'),'',''),
'$export' => array(z_root()."/cal/$nick/$y/$m/export",t('Export'),'',''),
$o = replace_macros(get_markup_template("cal_calendar.tpl"), [ '$calendar' => cal($y,$m,$links, ' eventcal'),
'$sources' => $sources, '$events' => $events,
'$lang' => App::$language, '$upload' => t('Import'),
'$timezone' => date_default_timezone_get(), '$submit' => t('Submit'),
'$first_day' => $first_day,
'$prev' => t('Previous'), '$prev' => t('Previous'),
'$next' => t('Next'), '$next' => t('Next'),
'$today' => t('Today'), '$today' => t('Today'),
'$title' => $title, '$form' => $form,
'$dtstart' => $dtstart, '$expandform' => ((x($_GET,'expandform')) ? true : false)
'$dtend' => $dtend, ));
'$nick' => $nick
]); if (x($_GET,'id')){ echo $o; killme(); }
return $o; return $o;
}
} }

View File

@@ -4,7 +4,6 @@ namespace Zotlabs\Module;
use App; use App;
use Zotlabs\Lib\Apps; use Zotlabs\Lib\Apps;
use Zotlabs\Web\Controller; use Zotlabs\Web\Controller;
use Zotlabs\Web\HTTPSig;
require_once('include/event.php'); require_once('include/event.php');
@@ -42,7 +41,7 @@ class Cdav extends Controller {
continue; continue;
} }
$sigblock = HTTPSig::parse_sigheader($_SERVER[$head]); $sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]);
if($sigblock) { if($sigblock) {
$keyId = str_replace('acct:','',$sigblock['keyId']); $keyId = str_replace('acct:','',$sigblock['keyId']);
if($keyId) { if($keyId) {
@@ -65,7 +64,7 @@ class Cdav extends Controller {
continue; continue;
if($record) { if($record) {
$verified = HTTPSig::verify('',$record['channel']['channel_pubkey']); $verified = \Zotlabs\Web\HTTPSig::verify('',$record['channel']['channel_pubkey']);
if(! ($verified && $verified['header_signed'] && $verified['header_valid'])) { if(! ($verified && $verified['header_signed'] && $verified['header_valid'])) {
$record = null; $record = null;
} }
@@ -278,11 +277,11 @@ class Cdav extends Controller {
$allday = $_REQUEST['allday']; $allday = $_REQUEST['allday'];
$title = $_REQUEST['title']; $title = $_REQUEST['title'];
$start = datetime_convert('UTC', 'UTC', $_REQUEST['dtstart']); $start = datetime_convert($tz, 'UTC', $_REQUEST['dtstart']);
$dtstart = new \DateTime($start); $dtstart = new \DateTime($start);
if($_REQUEST['dtend']) { if($_REQUEST['dtend']) {
$end = datetime_convert('UTC', 'UTC', $_REQUEST['dtend']); $end = datetime_convert($tz, 'UTC', $_REQUEST['dtend']);
$dtend = new \DateTime($end); $dtend = new \DateTime($end);
} }
$description = $_REQUEST['description']; $description = $_REQUEST['description'];
@@ -369,10 +368,10 @@ class Cdav extends Controller {
$uri = $_REQUEST['uri']; $uri = $_REQUEST['uri'];
$title = $_REQUEST['title']; $title = $_REQUEST['title'];
$start = datetime_convert('UTC', 'UTC', $_REQUEST['dtstart']); $start = datetime_convert($tz, 'UTC', $_REQUEST['dtstart']);
$dtstart = new \DateTime($start); $dtstart = new \DateTime($start);
if($_REQUEST['dtend']) { if($_REQUEST['dtend']) {
$end = datetime_convert('UTC', 'UTC', $_REQUEST['dtend']); $end = datetime_convert($tz, 'UTC', $_REQUEST['dtend']);
$dtend = new \DateTime($end); $dtend = new \DateTime($end);
} }
$description = $_REQUEST['description']; $description = $_REQUEST['description'];
@@ -442,10 +441,10 @@ class Cdav extends Controller {
$allday = $_REQUEST['allday']; $allday = $_REQUEST['allday'];
$uri = $_REQUEST['uri']; $uri = $_REQUEST['uri'];
$start = datetime_convert('UTC', 'UTC', $_REQUEST['dtstart']); $start = datetime_convert($tz, 'UTC', $_REQUEST['dtstart']);
$dtstart = new \DateTime($start); $dtstart = new \DateTime($start);
if($_REQUEST['dtend']) { if($_REQUEST['dtend']) {
$end = datetime_convert('UTC', 'UTC', $_REQUEST['dtend']); $end = datetime_convert($tz, 'UTC', $_REQUEST['dtend']);
$dtend = new \DateTime($end); $dtend = new \DateTime($end);
} }
@@ -910,6 +909,8 @@ class Cdav extends Controller {
require_once 'vendor/autoload.php'; require_once 'vendor/autoload.php';
head_add_css('cdav.css');
if(!cdav_principal($principalUri)) { if(!cdav_principal($principalUri)) {
$this->activate($pdo, $channel); $this->activate($pdo, $channel);
if(!cdav_principal($principalUri)) { if(!cdav_principal($principalUri)) {

View File

@@ -6,14 +6,13 @@ namespace Zotlabs\Module;
use App; use App;
use Zotlabs\Web\Controller; use Zotlabs\Web\Controller;
use Zotlabs\Lib\PermissionDescription; use Zotlabs\Lib\PermissionDescription;
use Zotlabs\Web\HTTPSig; use Zotlabs\Zot6\HTTPSig;
use Zotlabs\Lib\Libzot; use Zotlabs\Lib\Libzot;
require_once('include/items.php'); require_once('include/items.php');
require_once('include/security.php'); require_once('include/security.php');
require_once('include/conversation.php'); require_once('include/conversation.php');
require_once('include/acl_selectors.php'); require_once('include/acl_selectors.php');
require_once('include/opengraph.php');
/** /**
@@ -110,20 +109,8 @@ class Channel extends Controller {
// Run profile_load() here to make sure the theme is set before // Run profile_load() here to make sure the theme is set before
// we start loading content // we start loading content
profile_load($which,$profile); profile_load($which,$profile);
// Add Opengraph markup
$mid = ((x($_REQUEST,'mid')) ? $_REQUEST['mid'] : '');
if(strpos($mid,'b64.') === 0)
$mid = @base64url_decode(substr($mid,4));
if($mid)
$r = q("SELECT * FROM item WHERE mid = '%s' AND uid = %d AND item_private = 0 LIMIT 1",
dbesc($mid),
intval($channel['channel_id'])
);
opengraph_add_meta($r ? $r[0] : [], $channel);
} }
function get($update = 0, $load = false) { function get($update = 0, $load = false) {
@@ -364,7 +351,7 @@ class Channel extends Controller {
$parents_str = ids_to_querystr($r,'item_id'); $parents_str = ids_to_querystr($r,'item_id');
$r = q("SELECT item.*, item.id AS item_id $items = q("SELECT item.*, item.id AS item_id
FROM item FROM item
WHERE item.uid = %d $item_normal WHERE item.uid = %d $item_normal
AND item.parent IN ( %s ) AND item.parent IN ( %s )
@@ -373,8 +360,8 @@ class Channel extends Controller {
dbesc($parents_str) dbesc($parents_str)
); );
xchan_query($r); xchan_query($items);
$items = fetch_post_tags($r, true); $items = fetch_post_tags($items, true);
$items = conv_sort($items,$ordering); $items = conv_sort($items,$ordering);
if($load && $mid && (! count($items))) { if($load && $mid && (! count($items))) {

View File

@@ -34,8 +34,8 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
$adjust = intval($_POST['adjust']); $adjust = intval($_POST['adjust']);
$start = datetime_convert('UTC', 'UTC', escape_tags($_REQUEST['dtstart'])); $start = (($adjust) ? datetime_convert($tz, 'UTC', escape_tags($_REQUEST['dtstart'])) : datetime_convert('UTC', 'UTC', escape_tags($_REQUEST['dtstart'])));
$finish = datetime_convert('UTC', 'UTC', escape_tags($_REQUEST['dtend'])); $finish = (($adjust) ? datetime_convert($tz, 'UTC', escape_tags($_REQUEST['dtend'])) : datetime_convert('UTC', 'UTC', escape_tags($_REQUEST['dtend'])));
$summary = escape_tags(trim($_POST['summary'])); $summary = escape_tags(trim($_POST['summary']));
$desc = escape_tags(trim($_POST['desc'])); $desc = escape_tags(trim($_POST['desc']));
@@ -381,12 +381,12 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
'end' => $end, 'end' => $end,
'drop' => $drop, 'drop' => $drop,
'allDay' => (($rr['adjust']) ? 0 : 1), 'allDay' => (($rr['adjust']) ? 0 : 1),
'title' => html_entity_decode($rr['summary'], ENT_COMPAT, 'UTF-8'), 'title' => htmlentities($rr['summary'], ENT_COMPAT, 'UTF-8', false),
'editable' => $edit ? true : false, 'editable' => $edit ? true : false,
'item' => $rr, 'item' => $rr,
'plink' => [$rr['plink'], t('Link to source')], 'plink' => [$rr['plink'], t('Link to source')],
'description' => html_entity_decode($rr['description'], ENT_COMPAT, 'UTF-8'), 'description' => htmlentities($rr['description'], ENT_COMPAT, 'UTF-8', false),
'location' => html_entity_decode($rr['location'], ENT_COMPAT, 'UTF-8'), 'location' => htmlentities($rr['location'], ENT_COMPAT, 'UTF-8', false),
'allow_cid' => expand_acl($rr['allow_cid']), 'allow_cid' => expand_acl($rr['allow_cid']),
'allow_gid' => expand_acl($rr['allow_gid']), 'allow_gid' => expand_acl($rr['allow_gid']),
'deny_cid' => expand_acl($rr['deny_cid']), 'deny_cid' => expand_acl($rr['deny_cid']),
@@ -422,67 +422,13 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
dbesc($event_id), dbesc($event_id),
intval(local_channel()) intval(local_channel())
); );
if($r) { if($r) {
$r = q("update item set resource_type = '', resource_id = '' where resource_type = 'event' and resource_id = '%s' and uid = %d",
$sync_event['event_deleted'] = 1;
build_sync_packet(0,array('event' => array($sync_event)));
$i = q("select * from item where resource_type = 'event' and resource_id = '%s' and uid = %d",
dbesc($event_id), dbesc($event_id),
intval(local_channel()) intval(local_channel())
); );
$sync_event['event_deleted'] = 1;
if ($i) { build_sync_packet(0,array('event' => array($sync_event)));
$can_delete = false;
$local_delete = true;
$ob_hash = get_observer_hash();
if($ob_hash && ($ob_hash === $i[0]['author_xchan'] || $ob_hash === $i[0]['owner_xchan'] || $ob_hash === $i[0]['source_xchan'])) {
$can_delete = true;
}
// The site admin can delete any post/item on the site.
// If the item originated on this site+channel the deletion will propagate downstream.
// Otherwise just the local copy is removed.
if(is_site_admin()) {
$local_delete = true;
if(intval($i[0]['item_origin']))
$can_delete = true;
}
if($can_delete || $local_delete) {
// if this is a different page type or it's just a local delete
// but not by the item author or owner, do a simple deletion
$complex = false;
if(intval($i[0]['item_type']) || ($local_delete && (! $can_delete))) {
drop_item($i[0]['id']);
}
else {
// complex deletion that needs to propagate and be performed in phases
drop_item($i[0]['id'],true,DROPITEM_PHASE1);
$complex = true;
}
$ii = q("select * from item where id = %d",
intval($i[0]['id'])
);
if($ii) {
xchan_query($ii);
$sync_item = fetch_post_tags($ii);
build_sync_packet($i[0]['uid'],array('item' => array(encode_item($sync_item[0],true))));
}
if($complex) {
tag_deliver($i[0]['uid'],$i[0]['id']);
}
}
}
killme(); killme();
} }
notice( t('Failed to remove event' ) . EOL); notice( t('Failed to remove event' ) . EOL);

View File

@@ -35,6 +35,13 @@ class Cloud extends \Zotlabs\Web\Controller {
if (argc() > 1) if (argc() > 1)
$which = argv(1); $which = argv(1);
if (argc() < 2 && intval(get_config('system','cloud_disable_siteroot'))) {
notice( t('Permission denied.') . EOL);
construct_page();
killme();
}
$profile = 0; $profile = 0;
if ($which) if ($which)

View File

@@ -322,10 +322,7 @@ class Connections extends \Zotlabs\Web\Controller {
'ignore' => ((! $rr['abook_ignored']) ? t('Ignore') : false), 'ignore' => ((! $rr['abook_ignored']) ? t('Ignore') : false),
'recent_label' => t('Recent activity'), 'recent_label' => t('Recent activity'),
'recentlink' => z_root() . '/network/?f=&cid=' . intval($rr['abook_id']) . '&name=' . $rr['xchan_name'], 'recentlink' => z_root() . '/network/?f=&cid=' . intval($rr['abook_id']) . '&name=' . $rr['xchan_name'],
'oneway' => $oneway, 'oneway' => $oneway
'connect' => (intval($rr['abook_not_here']) ? t('Connect') : ''),
'follow' => z_root() . '/follow/?f=&url=' . urlencode($rr['xchan_hash']) . '&interactive=0',
'connect_hover' => t('Connect at this location')
); );
} }
} }

View File

@@ -8,9 +8,8 @@
namespace Zotlabs\Module; namespace Zotlabs\Module;
use Sabre\DAV as SDAV; use \Sabre\DAV as SDAV;
use Zotlabs\Storage; use \Zotlabs\Storage;
use Zotlabs\Web\HTTPSig;
require_once('include/attach.php'); require_once('include/attach.php');
require_once('include/auth.php'); require_once('include/auth.php');
@@ -47,7 +46,7 @@ class Dav extends \Zotlabs\Web\Controller {
continue; continue;
} }
$sigblock = HTTPSig::parse_sigheader($_SERVER[$head]); $sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]);
if($sigblock) { if($sigblock) {
$keyId = str_replace('acct:','',$sigblock['keyId']); $keyId = str_replace('acct:','',$sigblock['keyId']);
if($keyId) { if($keyId) {
@@ -70,7 +69,7 @@ class Dav extends \Zotlabs\Web\Controller {
continue; continue;
if($record) { if($record) {
$verified = HTTPSig::verify('',$record['channel']['channel_pubkey']); $verified = \Zotlabs\Web\HTTPSig::verify('',$record['channel']['channel_pubkey']);
if(! ($verified && $verified['header_signed'] && $verified['header_valid'])) { if(! ($verified && $verified['header_signed'] && $verified['header_valid'])) {
$record = null; $record = null;
} }
@@ -95,8 +94,6 @@ class Dav extends \Zotlabs\Web\Controller {
$auth = new \Zotlabs\Storage\BasicAuth(); $auth = new \Zotlabs\Storage\BasicAuth();
$auth->observer = get_observer_hash();
$auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . ' ' . 'WebDAV'); $auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . ' ' . 'WebDAV');
$rootDirectory = new \Zotlabs\Storage\Directory('/', $auth); $rootDirectory = new \Zotlabs\Storage\Directory('/', $auth);

View File

@@ -287,7 +287,7 @@ class Directory extends \Zotlabs\Web\Controller {
$hometown = ((x($profile,'hometown') == 1) ? $profile['hometown'] : False); $hometown = ((x($profile,'hometown') == 1) ? $profile['hometown'] : False);
$about = ((x($profile,'about') == 1) ? zidify_links(bbcode($profile['about'], ['tryoembed' => false])) : False); $about = ((x($profile,'about') == 1) ? zidify_links(bbcode($profile['about'])) : False);
$keywords = ((x($profile,'keywords')) ? $profile['keywords'] : ''); $keywords = ((x($profile,'keywords')) ? $profile['keywords'] : '');
@@ -345,7 +345,7 @@ class Directory extends \Zotlabs\Web\Controller {
'pdesc_label' => t('Description:'), 'pdesc_label' => t('Description:'),
'marital' => $marital, 'marital' => $marital,
'homepage' => $homepage, 'homepage' => $homepage,
'homepageurl' => linkify($homepageurl, true), 'homepageurl' => linkify($homepageurl),
'hometown' => $hometown, 'hometown' => $hometown,
'hometown_label' => t('Hometown:'), 'hometown_label' => t('Hometown:'),
'about' => $about, 'about' => $about,

View File

@@ -394,7 +394,7 @@ class Dirsearch extends \Zotlabs\Web\Controller {
$quoted_string = false; $quoted_string = false;
} }
else else
$curr['value'] .= ' ' . trim($q); $curr['value'] .= ' ' . trim(q);
} }
} }
} }

View File

@@ -12,9 +12,6 @@ class Events extends \Zotlabs\Web\Controller {
function post() { function post() {
// this module is deprecated
return;
logger('post: ' . print_r($_REQUEST,true), LOGGER_DATA); logger('post: ' . print_r($_REQUEST,true), LOGGER_DATA);
if(! local_channel()) if(! local_channel())
@@ -249,9 +246,6 @@ class Events extends \Zotlabs\Web\Controller {
function get() { function get() {
// this module is deprecated
return;
if(argc() > 2 && argv(1) == 'ical') { if(argc() > 2 && argv(1) == 'ical') {
$event_id = argv(2); $event_id = argv(2);
@@ -668,7 +662,6 @@ class Events extends \Zotlabs\Web\Controller {
'html'=>$html, 'html'=>$html,
'plink' => array($rr['plink'],t('Link to Source'),'',''), 'plink' => array($rr['plink'],t('Link to Source'),'',''),
); );
} }
} }

View File

@@ -1,8 +1,6 @@
<?php <?php
namespace Zotlabs\Module; namespace Zotlabs\Module;
use Zotlabs\Web\HTTPSig;
/** /**
* module: getfile * module: getfile
* *
@@ -48,7 +46,7 @@ class Getfile extends \Zotlabs\Web\Controller {
continue; continue;
} }
$sigblock = HTTPSig::parse_sigheader($_SERVER[$head]); $sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]);
if($sigblock) { if($sigblock) {
$keyId = $sigblock['keyId']; $keyId = $sigblock['keyId'];
@@ -59,7 +57,7 @@ class Getfile extends \Zotlabs\Web\Controller {
); );
if($r) { if($r) {
$hubloc = $r[0]; $hubloc = $r[0];
$verified = HTTPSig::verify('',$hubloc['xchan_pubkey']); $verified = \Zotlabs\Web\HTTPSig::verify('',$hubloc['xchan_pubkey']);
if($verified && $verified['header_signed'] && $verified['header_valid'] && $hash == $hubloc['hubloc_hash']) { if($verified && $verified['header_signed'] && $verified['header_valid'] && $hash == $hubloc['hubloc_hash']) {
$header_verified = true; $header_verified = true;
} }

View File

@@ -177,7 +177,7 @@ class Group extends Controller {
if($r) if($r)
$result = group_rmv(local_channel(),$r[0]['gname']); $result = group_rmv(local_channel(),$r[0]['gname']);
if($result) { if($result) {
$hookinfo = [ 'pgrp_extras' => '', 'group' => argv(2) ]; $hookinfo = [ 'pgrp_extras' => '', 'group'=>$argv(2) ];
call_hooks ('privacygroup_extras_drop',$hookinfo); call_hooks ('privacygroup_extras_drop',$hookinfo);
info( t('Privacy group removed.') . EOL); info( t('Privacy group removed.') . EOL);
} }

View File

@@ -12,7 +12,7 @@ namespace Zotlabs\Module;
use Zotlabs\Lib\Activity; use Zotlabs\Lib\Activity;
use Zotlabs\Lib\ActivityStreams; use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\LDSignatures; use Zotlabs\Lib\LDSignatures;
use Zotlabs\Web\HTTPSig; use Zotlabs\Zot6\HTTPSig;
use Zotlabs\Web\Controller; use Zotlabs\Web\Controller;
use Zotlabs\Lib\Libzot; use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\ThreadListener; use Zotlabs\Lib\ThreadListener;

View File

@@ -9,7 +9,7 @@ use Zotlabs\Daemon\Master;
use Zotlabs\Lib\Activity; use Zotlabs\Lib\Activity;
use Zotlabs\Lib\ActivityStreams; use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\LDSignatures; use Zotlabs\Lib\LDSignatures;
use Zotlabs\Web\HTTPSig; use Zotlabs\Zot6\HTTPSig;
use Zotlabs\Lib\Libzot; use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\ThreadListener; use Zotlabs\Lib\ThreadListener;
use App; use App;
@@ -96,12 +96,11 @@ class Item extends Controller {
} }
// if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access // if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access
// with a bias towards those items owned by channels on this site (item_wall = 1)
$sql_extra = item_permissions_sql(0); $sql_extra = item_permissions_sql(0);
if (! $i) { if (! $i) {
$i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1", $i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra limit 1",
dbesc($r[0]['parent_mid']) dbesc($r[0]['parent_mid'])
); );
} }
@@ -193,25 +192,6 @@ class Item extends Controller {
killme(); killme();
} }
if(argc() > 1 && argv(1) !== 'drop') {
$x = q("select uid, item_wall, llink, mid from item where mid = '%s' ",
dbesc(z_root() . '/item/' . argv(1))
);
if($x) {
foreach($x as $xv) {
if (intval($xv['item_wall'])) {
$c = channelx_by_n($xv['uid']);
if ($c) {
goaway($c['xchan_url'] . '?mid=' . gen_link_id($xv['mid']));
}
}
}
goaway($x[0]['llink']);
}
http_status_exit(404, 'Not found');
}
} }
@@ -571,9 +551,9 @@ class Item extends Controller {
$private = $orig_post['item_private']; $private = $orig_post['item_private'];
} }
if($public_policy || $acl->is_private()) { if($private || $public_policy || $acl->is_private())
$private = (($private) ? $private : 1); $private = 1;
}
$location = $orig_post['location']; $location = $orig_post['location'];
$coord = $orig_post['coord']; $coord = $orig_post['coord'];
@@ -650,11 +630,12 @@ class Item extends Controller {
$allow_empty = ((array_key_exists('allow_empty',$_REQUEST)) ? intval($_REQUEST['allow_empty']) : 0); $allow_empty = ((array_key_exists('allow_empty',$_REQUEST)) ? intval($_REQUEST['allow_empty']) : 0);
$private = (($private) ? $private : intval($acl->is_private() || ($public_policy))); $private = intval($acl->is_private() || ($public_policy));
// If this is a comment, set the permissions from the parent. // If this is a comment, set the permissions from the parent.
if($parent_item) { if($parent_item) {
$private = 0;
$acl->set($parent_item); $acl->set($parent_item);
$private = intval($acl->is_private() || $parent_item['item_private']); $private = intval($acl->is_private() || $parent_item['item_private']);
$public_policy = $parent_item['public_policy']; $public_policy = $parent_item['public_policy'];
@@ -761,11 +742,6 @@ class Item extends Controller {
} }
} }
if(($str_contact_allow) && (! $str_group_allow)) {
// direct message - private between individual channels but not groups
$private = 2;
}
/** /**
* *
@@ -817,6 +793,11 @@ class Item extends Controller {
'revision' => $r['data']['revision'] 'revision' => $r['data']['revision']
); );
} }
$ext = substr($r['data']['filename'],strrpos($r['data']['filename'],'.'));
if(strpos($r['data']['filetype'],'audio/') !== false)
$attach_link = '[audio]' . z_root() . '/attach/' . $r['data']['hash'] . '/' . $r['data']['revision'] . (($ext) ? $ext : '') . '[/audio]';
elseif(strpos($r['data']['filetype'],'video/') !== false)
$attach_link = '[video]' . z_root() . '/attach/' . $r['data']['hash'] . '/' . $r['data']['revision'] . (($ext) ? $ext : '') . '[/video]';
$body = str_replace($match[1][$i],$attach_link,$body); $body = str_replace($match[1][$i],$attach_link,$body);
$i++; $i++;
} }
@@ -1227,7 +1208,13 @@ class Item extends Controller {
killme(); killme();
} }
if(($parent == $post_id) || ($datarray['item_private'] == 1)) { if(($parent) && ($parent != $post_id)) {
// Store the comment signature information in case we need to relay to Diaspora
//$ditem = $datarray;
//$ditem['author'] = $observer;
//store_diaspora_comment_sig($ditem,$channel,$parent_item, $post_id, (($walltowall_comment) ? 1 : 0));
}
else {
$r = q("select * from item where id = %d", $r = q("select * from item where id = %d",
intval($post_id) intval($post_id)
); );

View File

@@ -2,6 +2,9 @@
namespace Zotlabs\Module; namespace Zotlabs\Module;
class Linkinfo extends \Zotlabs\Web\Controller { class Linkinfo extends \Zotlabs\Web\Controller {
function get() { function get() {
@@ -46,21 +49,6 @@ class Linkinfo extends \Zotlabs\Web\Controller {
logger('linkinfo: ' . $url); logger('linkinfo: ' . $url);
// Replace plink URL with 'share' tag if possible
preg_match("/(mid=b64\.|display\/|posts\/)([\w\-]+)(&.+)?$/", $url, $mid);
if (!empty($mid) && $mid[1] == 'mid=b64.')
$mid[2] = base64_decode($mid[2]);
$r = q("SELECT id FROM item WHERE mid = '%s' AND uid = %d AND item_private = 0 LIMIT 1",
dbesc((empty($mid) ? $url : $mid[2])),
intval(local_channel())
);
if ($r) {
echo "[share=" . $r[0]['id'] . "][/share]";
killme();
}
$result = z_fetch_url($url,false,0,array('novalidate' => true, 'nobody' => true)); $result = z_fetch_url($url,false,0,array('novalidate' => true, 'nobody' => true));
if($result['success']) { if($result['success']) {
$hdrs=array(); $hdrs=array();
@@ -287,7 +275,7 @@ class Linkinfo extends \Zotlabs\Web\Controller {
// Check codepage in HTTP headers or HTML if not exist // Check codepage in HTTP headers or HTML if not exist
$cp = (preg_match('/Content-Type: text\/html; charset=(.+)\r\n/i', $header, $o) ? $o[1] : ''); $cp = (preg_match('/Content-Type: text\/html; charset=(.+)\r\n/i', $header, $o) ? $o[1] : '');
if(empty($cp)) if(empty($cp))
$cp = (preg_match('/meta.+content=["\']text\/html; charset=([^"\']+)/i', $body, $o) ? $o[1] : 'AUTO'); $cp = (preg_match('/meta.+content=["|\']text\/html; charset=([^"|\']+)/i', $body, $o) ? $o[1] : 'AUTO');
$body = mb_convert_encoding($body, 'UTF-8', $cp); $body = mb_convert_encoding($body, 'UTF-8', $cp);
$body = mb_convert_encoding($body, 'HTML-ENTITIES', "UTF-8"); $body = mb_convert_encoding($body, 'HTML-ENTITIES', "UTF-8");
@@ -457,8 +445,7 @@ class Linkinfo extends \Zotlabs\Web\Controller {
while (strpos($text, " ")) while (strpos($text, " "))
$text = trim(str_replace(" ", " ", $text)); $text = trim(str_replace(" ", " ", $text));
$text = substr(html_entity_decode($text, ENT_QUOTES, "UTF-8"), 0, 350); $siteinfo["text"] = html_entity_decode(substr($text,0,350), ENT_QUOTES, "UTF-8").'...';
$siteinfo["text"] = rtrim(substr($text, 0, strrpos($text, " ")), "?.,:;!-") . '...';
} }
} }

View File

@@ -76,7 +76,7 @@ class Lockview extends \Zotlabs\Web\Controller {
killme(); killme();
} }
if(intval($item['item_private']) && (! strlen($item['allow_cid'])) && (! strlen($item['allow_gid'])) if(($item['item_private'] == 1) && (! strlen($item['allow_cid'])) && (! strlen($item['allow_gid']))
&& (! strlen($item['deny_cid'])) && (! strlen($item['deny_gid']))) { && (! strlen($item['deny_cid'])) && (! strlen($item['deny_gid']))) {
// if the post is private, but public_policy is blank ("visible to the internet"), and there aren't any // if the post is private, but public_policy is blank ("visible to the internet"), and there aren't any

View File

@@ -1,8 +1,6 @@
<?php <?php
namespace Zotlabs\Module; namespace Zotlabs\Module;
use Zotlabs\Web\HTTPSig;
@require_once('include/zot.php'); @require_once('include/zot.php');
@@ -154,9 +152,10 @@ class Magic extends \Zotlabs\Web\Controller {
$headers['Accept'] = 'application/x-zot+json' ; $headers['Accept'] = 'application/x-zot+json' ;
$headers['X-Open-Web-Auth'] = random_string(); $headers['X-Open-Web-Auth'] = random_string();
$headers['Host'] = $parsed['host']; $headers['Host'] = $parsed['host'];
$headers['Digest'] = HTTPSig::generate_digest_header($data); $headers['Digest'] = 'SHA-256=' . \Zotlabs\Web\HTTPSig::generate_digest($data,false);
$headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'], 'acct:' . channel_reddress($channel),true,'sha512'); $headers = \Zotlabs\Web\HTTPSig::create_sig('',$headers,$channel['channel_prvkey'],
'acct:' . $channel['channel_address'] . '@' . \App::get_hostname(),false,true,'sha512');
$x = z_post_url($basepath . '/owa',$data,$redirects,[ 'headers' => $headers ]); $x = z_post_url($basepath . '/owa',$data,$redirects,[ 'headers' => $headers ]);
if($x['success']) { if($x['success']) {

View File

@@ -26,10 +26,6 @@ class Mail extends \Zotlabs\Web\Controller {
$raw = ((x($_REQUEST,'raw')) ? intval($_REQUEST['raw']) : 0); $raw = ((x($_REQUEST,'raw')) ? intval($_REQUEST['raw']) : 0);
$mimetype = ((x($_REQUEST,'mimetype')) ? notags(trim($_REQUEST['mimetype'])) : 'text/bbcode'); $mimetype = ((x($_REQUEST,'mimetype')) ? notags(trim($_REQUEST['mimetype'])) : 'text/bbcode');
$sig = ((x($_REQUEST,'signature')) ? trim($_REQUEST['signature']) : '');
if(strpos($sig,'b64.') === 0)
$sig = base64_decode(str_replace('b64.', '', $sig));
if($preview) { if($preview) {
if($raw) { if($raw) {
@@ -127,7 +123,7 @@ class Mail extends \Zotlabs\Web\Controller {
// We have a local_channel, let send_message use the session channel and save a lookup // We have a local_channel, let send_message use the session channel and save a lookup
$ret = send_message(0, $recipient, $body, $subject, $replyto, $expires, $mimetype, $raw, $sig); $ret = send_message(0, $recipient, $body, $subject, $replyto, $expires, $mimetype, $raw);
if($ret['success']) { if($ret['success']) {
xchan_mail_query($ret['mail']); xchan_mail_query($ret['mail']);
@@ -400,7 +396,6 @@ class Mail extends \Zotlabs\Web\Controller {
'can_recall' => ($channel['channel_hash'] == $message['from_xchan']), 'can_recall' => ($channel['channel_hash'] == $message['from_xchan']),
'is_recalled' => (intval($message['mail_recalled']) ? t('Message has been recalled.') : ''), 'is_recalled' => (intval($message['mail_recalled']) ? t('Message has been recalled.') : ''),
'date' => datetime_convert('UTC',date_default_timezone_get(),$message['created'], 'c'), 'date' => datetime_convert('UTC',date_default_timezone_get(),$message['created'], 'c'),
'sig' => base64_encode($message['sig'])
); );
$seen = $message['seen']; $seen = $message['seen'];

View File

@@ -54,10 +54,9 @@ class Menu extends \Zotlabs\Web\Controller {
if($_REQUEST['menu_system']) if($_REQUEST['menu_system'])
$_REQUEST['menu_flags'] |= MENU_SYSTEM; $_REQUEST['menu_flags'] |= MENU_SYSTEM;
$menu_id = ((argc() > 2) ? intval(argv(2)) : 0); $menu_id = ((argc() > 1) ? intval(argv(1)) : 0);
if($menu_id) { if($menu_id) {
$_REQUEST['menu_id'] = $menu_id; $_REQUEST['menu_id'] = intval(argv(1));
$r = menu_edit($_REQUEST); $r = menu_edit($_REQUEST);
if($r) { if($r) {
menu_sync_packet($uid,get_observer_hash(),$menu_id); menu_sync_packet($uid,get_observer_hash(),$menu_id);

View File

@@ -2,8 +2,6 @@
namespace Zotlabs\Module; namespace Zotlabs\Module;
use Zotlabs\Web\HTTPSig;
/** /**
* OpenWebAuth verifier and token generator * OpenWebAuth verifier and token generator
* See https://macgirvin.com/wiki/mike/OpenWebAuth/Home * See https://macgirvin.com/wiki/mike/OpenWebAuth/Home
@@ -27,7 +25,7 @@ class Owa extends \Zotlabs\Web\Controller {
continue; continue;
} }
$sigblock = HTTPSig::parse_sigheader($_SERVER[$head]); $sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]);
if($sigblock) { if($sigblock) {
$keyId = $sigblock['keyId']; $keyId = $sigblock['keyId'];
@@ -67,7 +65,7 @@ class Owa extends \Zotlabs\Web\Controller {
if ($r) { if ($r) {
foreach($r as $hubloc) { foreach($r as $hubloc) {
$verified = HTTPSig::verify(file_get_contents('php://input'),$hubloc['xchan_pubkey']); $verified = \Zotlabs\Web\HTTPSig::verify(file_get_contents('php://input'),$hubloc['xchan_pubkey']);
if($verified && $verified['header_signed'] && $verified['header_valid']) { if($verified && $verified['header_signed'] && $verified['header_valid']) {
logger('OWA header: ' . print_r($verified,true),LOGGER_DATA); logger('OWA header: ' . print_r($verified,true),LOGGER_DATA);
logger('OWA success: ' . $hubloc['hubloc_addr'],LOGGER_DATA); logger('OWA success: ' . $hubloc['hubloc_addr'],LOGGER_DATA);

View File

@@ -31,7 +31,12 @@ class Photo extends \Zotlabs\Web\Controller {
// NOTREACHED // NOTREACHED
} }
$cache_mode = [ 'on' => false, 'age' => 86400, 'exp' => true, 'leak' => false ]; $cache_mode = array(
'on' => false,
'age' => 86400,
'exp' => true,
'leak' => false
);
call_hooks('cache_mode_hook', $cache_mode); call_hooks('cache_mode_hook', $cache_mode);
$observer_xchan = get_observer_hash(); $observer_xchan = get_observer_hash();
@@ -139,7 +144,7 @@ class Photo extends \Zotlabs\Web\Controller {
$resolution = 1; $resolution = 1;
} }
$r = q("SELECT * FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1", $r = q("SELECT uid, photo_usage, display_path FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1",
dbesc($photo), dbesc($photo),
intval($resolution) intval($resolution)
); );
@@ -158,10 +163,13 @@ class Photo extends \Zotlabs\Web\Controller {
if($u === PHOTO_CACHE) { if($u === PHOTO_CACHE) {
// Validate cache // Validate cache
if($cache_mode['on']) { if($cache_mode['on']) {
$cache = [ 'status' => false, 'item' => $r[0] ]; $cache = array(
'resid' => $photo,
'status' => false
);
call_hooks('cache_url_hook', $cache); call_hooks('cache_url_hook', $cache);
if(! $cache['status']) { if(! $cache['status']) {
$url = html_entity_decode($cache['item']['display_path'], ENT_QUOTES); $url = htmlspecialchars_decode($r[0]['display_path']);
// SSLify if needed // SSLify if needed
if(strpos(z_root(),'https:') !== false && strpos($url,'https:') === false) if(strpos(z_root(),'https:') !== false && strpos($url,'https:') === false)
$url = z_root() . '/sslify/' . $filename . '?f=&url=' . urlencode($url); $url = z_root() . '/sslify/' . $filename . '?f=&url=' . urlencode($url);
@@ -214,14 +222,14 @@ class Photo extends \Zotlabs\Web\Controller {
if(! $data) if(! $data)
killme(); killme();
$etag = '"' . md5($data . $modified) . '"'; $etag = md5($data . $modified);
if($modified == 0) if($modified == 0)
$modified = time(); $modified = time();
header_remove('Pragma'); header_remove('Pragma');
if((isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] === $etag) || (!isset($_SERVER['HTTP_IF_NONE_MATCH']) && isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $_SERVER['HTTP_IF_MODIFIED_SINCE'] === gmdate("D, d M Y H:i:s", $modified) . " GMT")) { if($_SERVER['HTTP_IF_NONE_MATCH'] === $etag || $_SERVER['HTTP_IF_MODIFIED_SINCE'] === gmdate("D, d M Y H:i:s", $modified) . " GMT") {
header_remove('Expires'); header_remove('Expires');
header_remove('Cache-Control'); header_remove('Cache-Control');
header_remove('Set-Cookie'); header_remove('Set-Cookie');
@@ -264,12 +272,7 @@ class Photo extends \Zotlabs\Web\Controller {
$maxage = $expires - time(); $maxage = $expires - time();
header("Expires: " . gmdate("D, d M Y H:i:s", $expires) . " GMT"); header("Expires: " . gmdate("D, d M Y H:i:s", $expires) . " GMT");
header("Cache-Control: max-age=" . $maxage . $cachecontrol);
// set CDN/Infrastructure caching much lower than maxage
// in the event that infrastructure caching is present.
$smaxage = intval($maxage/12);
header("Cache-Control: s-maxage=" . $smaxage . ", max-age=" . $maxage . $cachecontrol);
} }

View File

@@ -1080,6 +1080,7 @@ class Photos extends \Zotlabs\Web\Controller {
$comments = ''; $comments = '';
if(! $r) { if(! $r) {
if($observer && ($can_post || $can_comment)) { if($observer && ($can_post || $can_comment)) {
$feature_auto_save_draft = ((feature_enabled($owner_uid, 'auto_save_draft')) ? "true" : "false");
$commentbox = replace_macros($cmnt_tpl,array( $commentbox = replace_macros($cmnt_tpl,array(
'$return_path' => '', '$return_path' => '',
'$mode' => 'photos', '$mode' => 'photos',
@@ -1095,7 +1096,8 @@ class Photos extends \Zotlabs\Web\Controller {
'$submit' => t('Submit'), '$submit' => t('Submit'),
'$preview' => t('Preview'), '$preview' => t('Preview'),
'$ww' => '', '$ww' => '',
'$feature_encrypt' => false '$feature_encrypt' => false,
'$auto_save_draft' => $feature_auto_save_draft
)); ));
} }
} }

View File

@@ -282,8 +282,8 @@ class Ping extends \Zotlabs\Web\Controller {
if(strpos($message, $tt['xname']) === 0) if(strpos($message, $tt['xname']) === 0)
$message = substr($message, strlen($tt['xname']) + 1); $message = substr($message, strlen($tt['xname']) + 1);
$mid = basename($tt['link']); $mid = basename($tt['link']);
$mid = ((strpos($mid, 'b64.') === 0) ? @base64url_decode(substr($mid, 4)) : $mid);
if(in_array($tt['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) { if(in_array($tt['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) {
// we need the thread parent // we need the thread parent
@@ -291,6 +291,7 @@ class Ping extends \Zotlabs\Web\Controller {
dbesc($mid), dbesc($mid),
intval(local_channel()) intval(local_channel())
); );
$b64mid = ((strpos($r[0]['thr_parent'], 'b64.') === 0) ? $r[0]['thr_parent'] : 'b64.' . base64url_encode($r[0]['thr_parent'])); $b64mid = ((strpos($r[0]['thr_parent'], 'b64.') === 0) ? $r[0]['thr_parent'] : 'b64.' . base64url_encode($r[0]['thr_parent']));
} }
else { else {

View File

@@ -106,7 +106,7 @@ class Share extends \Zotlabs\Web\Controller {
$arr['owner_xchan'] = $item['author_xchan']; $arr['owner_xchan'] = $item['author_xchan'];
$arr['obj'] = Activity::encode_item($item); $arr['obj'] = Activity::encode_item($item);
$arr['obj_type'] = $item['obj_type']; $arr['obj_type'] = $item['obj_type'];
$arr['verb'] = ACTIVITY_SHARE; $arr['verb'] = 'Announce';
$post = item_store($arr); $post = item_store($arr);

View File

@@ -111,22 +111,7 @@ class Wall_attach extends \Zotlabs\Web\Controller {
} }
if(strpos($r['data']['filetype'],'audio') === 0) { if(strpos($r['data']['filetype'],'audio') === 0) {
$url = z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['data']['display_path']; $url = z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['data']['display_path'];
$s = "\n\n" . '[zaudio]' . $url . '[/zaudio]' . "\n\n"; echo "\n\n" . '[zaudio]' . $url . '[/zaudio]' . "\n\n";
}
if ($r['data']['filetype'] === 'image/svg+xml') {
$x = @file_get_contents('store/' . $channel['channel_address'] . '/' . $r['data']['os_path']);
if ($x) {
$bb = svg2bb($x);
if ($bb) {
$s .= "\n\n" . $bb;
}
else {
logger('empty return from svgbb');
}
}
else {
logger('unable to read svg data file: ' . 'store/' . $channel['channel_address'] . '/' . $r['data']['os_path']);
}
} }
$s .= "\n\n" . '[attachment]' . $r['data']['hash'] . ',' . $r['data']['revision'] . '[/attachment]' . "\n"; $s .= "\n\n" . '[attachment]' . $r['data']['hash'] . ',' . $r['data']['revision'] . '[/attachment]' . "\n";

View File

@@ -64,18 +64,6 @@ class Well_known extends \Zotlabs\Web\Controller {
echo file_get_contents('doc/dnt-policy.txt'); echo file_get_contents('doc/dnt-policy.txt');
killme(); killme();
case 'caldav':
if ($_SERVER['REQUEST_METHOD'] == 'PROPFIND') {
http_status('301', 'moved permanently');
goaway(z_root() . '/cdav');
};
case 'carddav':
if ($_SERVER['REQUEST_METHOD'] == 'PROPFIND') {
http_status('301', 'moved permanently');
goaway(z_root() . '/cdav');
};
default: default:
if(file_exists(\App::$cmd)) { if(file_exists(\App::$cmd)) {
echo file_get_contents(\App::$cmd); echo file_get_contents(\App::$cmd);

View File

@@ -1,7 +1,6 @@
<?php <?php
namespace Zotlabs\Module; namespace Zotlabs\Module;
use Zotlabs\Web\HTTPSig;
class Zfinger extends \Zotlabs\Web\Controller { class Zfinger extends \Zotlabs\Web\Controller {
@@ -24,9 +23,10 @@ class Zfinger extends \Zotlabs\Web\Controller {
$ret = json_encode($x); $ret = json_encode($x);
if($chan) { if($chan) {
$headers['Digest'] = HTTPSig::generate_digest_header($ret); $hash = \Zotlabs\Web\HTTPSig::generate_digest($ret,false);
$h = HTTPSig::create_sig($headers,$chan['channel_prvkey'],'acct:' . channel_reddress($chan)); $headers['Digest'] = 'SHA-256=' . $hash;
HTTPSig::set_headers($h); \Zotlabs\Web\HTTPSig::create_sig('',$headers,$chan['channel_prvkey'],
'acct:' . $chan['channel_address'] . '@' . \App::get_hostname(),true);
} }
else { else {
foreach($headers as $k => $v) { foreach($headers as $k => $v) {

View File

@@ -3,7 +3,7 @@
namespace Zotlabs\Module; namespace Zotlabs\Module;
use Zotlabs\Lib\Zotfinger; use Zotlabs\Lib\Zotfinger;
use Zotlabs\Web\HTTPSig; use Zotlabs\Zot6\HTTPSig;
class Zot_probe extends \Zotlabs\Web\Controller { class Zot_probe extends \Zotlabs\Web\Controller {

View File

@@ -42,7 +42,7 @@ class Zotfeed extends \Zotlabs\Web\Controller {
} }
logger('zotfeed request: ' . $r[0]['channel_name'], LOGGER_DEBUG); logger('zotfeed request: ' . $r[0]['channel_name'], LOGGER_DEBUG);
$result['project'] = 'Hubzilla';
$result['messages'] = zot_feed($r[0]['channel_id'],$observer['xchan_hash'],array('mindate' => $mindate)); $result['messages'] = zot_feed($r[0]['channel_id'],$observer['xchan_hash'],array('mindate' => $mindate));
$result['success'] = true; $result['success'] = true;
json_return_and_die($result); json_return_and_die($result);

View File

@@ -0,0 +1,42 @@
<?php
$auth_sister_ver = 'Ver.0.3.5.alpha';
/*
===========================================================
■PHP用認証モジュール 
〝妹認証 Auth-sister〟
http://www.okanesuita.org/auth_sister/
■著作権情報
Copyright (C) 2008 菅礼紗(http://www.okanesuita.org/).
■ライセンス
・MIT License (http://www.opensource.org/licenses/mit-license.php)
1.本スクリプトは無償であり、かつ誰でも無制限に使うことができる。
但し、著作権表示および本許諾表示を、すべての複製または重要な部分に記載しなければならない。
2.開発者は、本スクリプトに関して生じる事の一切の責任を負わない。
===========================================================
*/
/* 一般設定 */
$auth_sister_load = 'reiya'; //認証に使う妹パッケージ
$auth_sister_mes_a = '妹「'; //メッセージ先頭に付加する文字列
$auth_sister_mes_b = '」'; //メッセージ最後に付加する文字列
/* フォーム送信設定 */
$auth_sister_method = 0;//メソッド(0=post, 1=get)GETだとエラーになる可能性がある
//$auth_sister_input = 2;
/* セッション設定(etc.php用) */
$ses_name = 'テストセッション';
//$ses_dir = '';
/* セキュリティ関連設定 */
$auth_sister_len_min = 2; //最小文字数(回答文)
$auth_sister_len_max = 10; //最大文字数(回答文)
$auth_sister_outlen = "$auth_sister_len_min$auth_sister_len_max文字でいれてー";//文字数範囲外のエラー文
//Copyright (C) 2008 菅礼紗(http://www.okanesuita.org/).
?>

View File

@@ -0,0 +1,217 @@
<?php
//Copyright (C) 2008 菅礼紗(http://www.okanesuita.org/).
//妹★関数-----------------------------------------------------------
//セッション初期化
function auth_session_start(){
require('auth_sister/config.inc.php');
if($ses_name) {session_name($ses_name);}
if($ses_dir) {session_save_path($ses_dir);}
session_start();
}
//妹ヘッダを挿入します
function auth_sister_header(){
require('auth_sister/config.inc.php');
require('auth_sister/'.$auth_sister_load.'/config.inc.php');
echo $auth_sister_header;
}
//妹認証の初期化
function auth_sister_load(){
require('auth_sister/config.inc.php');
$loc = 'auth_sister/'.$auth_sister_load.'/words.txt';//辞書ファイル読み込み
//ファイル存在する場合は続行
if(file_exists($loc)){
$lines = file($loc, FILE_IGNORE_NEW_LINES);
$cnt = count($lines); //行数カウント
$cnt--;
$point = mt_rand(0, $cnt); //乱数発生
//質問文 正解メッセージ 不正解メッセージ 正解文 正解文の処理モード 逆処理スイッチ
//↓回答文の処理モード
//未指定・0:入力されたすべての文字列を含む
//1:正規表現による
//2:完全一致
list(
$_SESSION['auth_sister_question'],//質問文
$_SESSION['auth_sister_res_true'],//正解メッセージ
$_SESSION['auth_sister_res_false'],//不正解メッセージ
$_SESSION['auth_sister_answer'],//正解文
$_SESSION['auth_sister_anmode'],//正解文の処理モード
$_SESSION['auth_sister_rebirth']//逆処理スイッチ(0=OFF/1=ON)
)=explode("\t",$lines[$point]);//各変数に読み出し
$_SESSION['auth_sister_ticket'] = true; //画像読込権
$_SESSION['auth_sister_authID'] = uniqid(rand()); //AuthID発行
//以下マクロ処理だよ!
//乱数発生だよ!
$ran = rand(1,9999);
//乱数を平仮名にしちゃうよ!
$ranran = $ran;
$ranran = str_replace("0","れい" ,$ranran);
$ranran = str_replace("1","いち" ,$ranran);
$ranran = str_replace("2","" ,$ranran);
$ranran = str_replace("3","さん" ,$ranran);
$ranran = str_replace("4","よん" ,$ranran);
$ranran = str_replace("5","" ,$ranran);
$ranran = str_replace("6","ろく" ,$ranran);
$ranran = str_replace("7","なな" ,$ranran);
$ranran = str_replace("8","はち" ,$ranran);
$ranran = str_replace("9","きゅう" ,$ranran);
//乱数を漢字にしちゃおうかな!
$kanran = $ran;
$kanran = str_replace("0","" ,$kanran);
$kanran = str_replace("1","" ,$kanran);
$kanran = str_replace("2","" ,$kanran);
$kanran = str_replace("3","" ,$kanran);
$kanran = str_replace("4","" ,$kanran);
$kanran = str_replace("5","" ,$kanran);
$kanran = str_replace("6","" ,$kanran);
$kanran = str_replace("7","" ,$kanran);
$kanran = str_replace("8","" ,$kanran);
$kanran = str_replace("9","" ,$kanran);
//こんどは画数だぞ!
$kankaku = $ran;
$kankaku = str_replace("0","0" ,$kankaku);
$kankaku = str_replace("1","" ,$kankaku);
$kankaku = str_replace("2","" ,$kankaku);
$kankaku = str_replace("3","" ,$kankaku);
$kankaku = str_replace("4","" ,$kankaku);
$kankaku = str_replace("5","" ,$kankaku);
$kankaku = str_replace("6","" ,$kankaku);
$kankaku = str_replace("7","" ,$kankaku);
$kankaku = str_replace("8","" ,$kankaku);
$kankaku = str_replace("9","" ,$kankaku);
//[rand]
$_SESSION['auth_sister_question'] = str_replace("[rand]", $ran, $_SESSION['auth_sister_question']);
$_SESSION['auth_sister_answer'] = str_replace("[rand]", $ran, $_SESSION['auth_sister_answer']);
//[rand_kana]
$_SESSION['auth_sister_question'] = str_replace("[rand_kana]", $ranran, $_SESSION['auth_sister_question']);
$_SESSION['auth_sister_answer'] = str_replace("[rand_kana]", $ranran, $_SESSION['auth_sister_answer']);
//[rand_kan]
$_SESSION['auth_sister_question'] = str_replace("[rand_kan]", $kanran, $_SESSION['auth_sister_question']);
$_SESSION['auth_sister_answer'] = str_replace("[rand_kan]", $kanran, $_SESSION['auth_sister_answer']);
//[rand_kankaku]
$_SESSION['auth_sister_question'] = str_replace("[rand_kankaku]", $kankaku, $_SESSION['auth_sister_question']);
}
}
//妹認証の表示セット 先に初期化しておくこと
function auth_sister_insert(){
require('auth_sister/config.inc.php');
require('auth_sister/'.$auth_sister_load.'/config.inc.php');
$output = str_replace("[authID]", $_SESSION['auth_sister_authID'], $auth_sister_html);//AuthID挿入
echo $output;
}
//auth_sister_auth()は認証成功の場合true、失敗の場合はfalseを返します。
function auth_sister_auth(){
require('auth_sister/config.inc.php');
$auth = false;
$select = false;
$authid= $_SESSION['auth_sister_authID'];
//---メソッド
switch($auth_sister_method):
case 0 :
$select = $_POST[$authid];
break;
case 1 :
$select = $_GET[$authid];
break;
endswitch;
if($select){
$select = mb_convert_encoding($select,"UTF-8","auto");//入力されたもの
$answer = mb_convert_encoding($_SESSION['auth_sister_answer'],"UTF-8","auto");//正解文
$mode = $_SESSION['auth_sister_anmode'];//処理モード
$len = mb_strlen ( $select , "UTF-8");//入力文の文字数
//文字数制限
if(($len>=$auth_sister_len_min)&&($len<=$auth_sister_len_max)){
//処理モード
switch($mode):
case 0://入力されたすべての文字列を含む
if(mb_strstr($answer,$select,0,"UTF-8")) { $auth = true; }
break;
case 1://正規表現による
if(mb_ereg($answer,$select)) { $auth = true; }
break;
case 2://完全一致
if($answer==$select) { $auth = true; }
break;
default://入力されたすべての文字列を含む
if(mb_strstr($answer,$select,0,"UTF-8")) { $auth = true; }
endswitch;
//逆処理
if($_SESSION['auth_sister_rebirth']==1){
if($auth) { $auth = false; }
else { $auth = true; }
}
//認証結果文
if($auth){
$_SESSION['auth_sister_res'] = $_SESSION['auth_sister_res_true'];
} else {
$_SESSION['auth_sister_res'] = $_SESSION['auth_sister_res_false'];
}
//文字数エラー
} else {
$_SESSION['auth_sister_res'] = $auth_sister_outlen;
$auth = false;
}
}
return($auth);
}
//認証成功・失敗メッセージを返します
function auth_sister_res(){
require('auth_sister/config.inc.php');
$res = $auth_sister_mes_a.$_SESSION['auth_sister_res'].$auth_sister_mes_b;
return($res);
}
//イメージ出力-----------------------------------------------------------
$mode = $_GET['mode'];
switch($mode):
case "img":
require('config.inc.php');
if($ses_name) {session_name($ses_name);}
if($ses_dir) {session_save_path($ses_dir);}
session_start();
if($_SESSION['auth_sister_ticket']){
require($auth_sister_load.'/config.inc.php');
putenv('GDFONTPATH=' . realpath($auth_sister_fpath));
header("Content-type: image/png");
$text=$_SESSION['auth_sister_question'];
$text=mb_convert_encoding($text, "UTF-8", "auto");
$img = imagecreatefrompng($auth_sister_load.'/'.$auth_sister_image);
$color = imagecolorallocate($img,0x11,0x11,0x11); //文字色
imagettftext($img, $auth_sister_fsize, 0, $auth_sister_fx, $auth_sister_fy, $color, $auth_sister_font, $text );
//画像形式
if($_GET['type']==".png"){
imagepng($img); }
/*
if($_GET['type']==".jpg"){
imagejpeg($img,NULL,100)
}
*/
imagedestroy($img);
$_SESSION['auth_sister_ticket'] = false;
}else{
echo "Forbidden";
}
break;
endswitch;
?>

View File

@@ -0,0 +1,2 @@
mbstring.internal_encoding = UTF-8;
mbstring.http_output = UTF-8;

View File

@@ -0,0 +1,3 @@
<Files ~ ".(htaccess|htpasswd|txt|php)$">
deny from all
</Files>

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 B

View File

@@ -0,0 +1,27 @@
<?php
$auth_sister_image = 'reiya.png';
$auth_sister_fpath = './reiya';
$auth_sister_font = 'HiraginoSans-W0';
$auth_sister_fsize = 10;
$auth_sister_fx = 100;
$auth_sister_fy = 50;
//妹ヘッダ
$auth_sister_header = '<link rel="stylesheet" type="text/css" href="auth_sister/reiya/style.css" />';
//表示部分
$auth_sister_html = '<div class="reiya">
<div class="reiyareiya">
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td><input name="[authID]" type="text" class="reiya_input" id="[authID]" /></td>
<td><input name="button" type="submit" class="reiya_submit" id="button" value="送信" /></td>
</tr>
</table>
</div>
</div>';
?>

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

View File

@@ -0,0 +1,38 @@
@charset "utf-8";
/* CSS Document */
.reiya {
background-image: url(../core.php?mode=img&type=.png);
background-repeat: no-repeat;
height: 150px;
width: 400px;
}
.reiyareiya{
position:relative;
top:95px;
left:90px;
}
.reiya_input {
padding:0px;
margin:0px;
background-image: url(bg1.png);
background-repeat:repeat-x;
height: 25px;
width: 230px;
border: 1px #000 solid;
font-family:" Pゴシック", Osaka, "ヒラギノ角ゴ Pro W3";
font-size:18px;
font-weight:bold;
}
.reiya_submit {
padding:0px;
margin:0px;
background-image: url(bg2.png);
background-repeat:repeat-x;
height: 27px;
width: 50px;
border: 1px #000 solid;
font-family:" Pゴシック", Osaka, "ヒラギノ角ゴ Pro W3";
font-size:18px;
color:#fff;
}

View File

@@ -0,0 +1,8 @@
れいにゃ大好きって言って(完全一致・新機能) れいにゃもおにーちゃんのこと大好き♪ (怒) れいにゃ大好き 2
おにーちゃん私の煎餅たべたでしょー(部分一致) いいよ、別に♪ 嘘つき! ごめんよごめんねすまんかった悪かったすまなかった俺のプリン食べただろれいにゃ大好き
れいにゃ大好きって言わないで(完全不一致・新) 認証成功だよ 言わないでっていったでしょ れいにゃ大好き 2 1
[rand]を漢字にして(乱数+漢字乱数マクロ・新) よくできたねー 間違ったね [rand_kan] 2
[rand_kan]を数字にして(乱数+漢字乱数マクロ・新) よくできたねー 間違ったね [rand] 2
[rand_kana]を漢字にして(乱数+かな乱数マクロ・新) よくできたねー 間違ったね [rand_kan] 2
[rand]を二回言え!(乱数マクロ・新) よくできたねっ ばーか! [rand][rand] 2
それぞれ「[rand_kankaku]」の画数をかけ0は0。(新) すごいすごーい! ぶっぶー [rand] 2

View File

@@ -502,17 +502,13 @@ abstract class PhotoDriver {
* *
* @param array $arr * @param array $arr
* @param scale int * @param scale int
* @return boolean * @return boolean|array
*/ */
public function storeThumbnail($arr, $scale = 0) { public function storeThumbnail($arr, $scale = 0) {
// We only process thumbnails here
if($scale == 0)
return false;
$arr['imgscale'] = $scale; $arr['imgscale'] = $scale;
if(boolval(get_config('system','filesystem_storage_thumbnails', 0))) { if(boolval(get_config('system','filesystem_storage_thumbnails', 0)) && $scale > 0) {
$channel = channelx_by_n($arr['uid']); $channel = channelx_by_n($arr['uid']);
$arr['os_storage'] = 1; $arr['os_storage'] = 1;
$arr['os_syspath'] = 'store/' . $channel['channel_address'] . '/' . $arr['os_path'] . '-' . $scale; $arr['os_syspath'] = 'store/' . $channel['channel_address'] . '/' . $arr['os_path'] . '-' . $scale;

View File

@@ -720,11 +720,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
* @return array Directory[] * @return array Directory[]
*/ */
function ChannelList(&$auth) { function ChannelList(&$auth) {
$ret = []; $ret = array();
if (intval(get_config('system','cloud_disable_siteroot'))) {
return $ret;
}
$r = q("SELECT channel_id, channel_address, profile.publish FROM channel left join profile on profile.uid = channel.channel_id WHERE channel_removed = 0 AND channel_system = 0 AND (channel_pageflags & %d) = 0", $r = q("SELECT channel_id, channel_address, profile.publish FROM channel left join profile on profile.uid = channel.channel_id WHERE channel_removed = 0 AND channel_system = 0 AND (channel_pageflags & %d) = 0",
intval(PAGE_HIDDEN) intval(PAGE_HIDDEN)
@@ -734,7 +730,8 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
foreach ($r as $rr) { foreach ($r as $rr) {
if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage') && $rr['publish']) { if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage') && $rr['publish']) {
logger('found channel: /cloud/' . $rr['channel_address'], LOGGER_DATA); logger('found channel: /cloud/' . $rr['channel_address'], LOGGER_DATA);
$ret[] = new Directory($rr['channel_address'], $auth); // @todo can't we drop '/cloud'? It gets stripped off anyway in RedDirectory
$ret[] = new Directory('/cloud/' . $rr['channel_address'], $auth);
} }
} }
} }

View File

@@ -2,17 +2,11 @@
namespace Zotlabs\Web; namespace Zotlabs\Web;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\Webfinger;
use Zotlabs\Web\HTTPHeaders;
use Zotlabs\Lib\Libzot;
/** /**
* @brief Implements HTTP Signatures per draft-cavage-http-signatures-10. * @brief Implements HTTP Signatures per draft-cavage-http-signatures-07.
* *
* @see https://tools.ietf.org/html/draft-cavage-http-signatures-10 * @see https://tools.ietf.org/html/draft-cavage-http-signatures-07
*/ */
class HTTPSig { class HTTPSig {
/** /**
@@ -21,32 +15,41 @@ class HTTPSig {
* @see https://tools.ietf.org/html/rfc5843 * @see https://tools.ietf.org/html/rfc5843
* *
* @param string $body The value to create the digest for * @param string $body The value to create the digest for
* @param string $alg hash algorithm (one of 'sha256','sha512') * @param boolean $set (optional, default true)
* @return string The generated digest header string for $body * If set send a Digest HTTP header
* @return string The generated digest of $body
*/ */
static function generate_digest($body, $set = true) {
$digest = base64_encode(hash('sha256', $body, true));
static function generate_digest_header($body,$alg = 'sha256') { if($set) {
header('Digest: SHA-256=' . $digest);
$digest = base64_encode(hash($alg, $body, true));
switch($alg) {
case 'sha512':
return 'SHA-512=' . $digest;
case 'sha256':
default:
return 'SHA-256=' . $digest;
break;
} }
return $digest;
} }
static function find_headers($data,&$body) { // See draft-cavage-http-signatures-08
static function verify($data,$key = '') {
$body = $data;
$headers = null;
$spoofable = false;
$result = [
'signer' => '',
'header_signed' => false,
'header_valid' => false,
'content_signed' => false,
'content_valid' => false
];
// decide if $data arrived via controller submission or curl // decide if $data arrived via controller submission or curl
if(is_array($data) && $data['header']) { if(is_array($data) && $data['header']) {
if(! $data['success']) if(! $data['success'])
return []; return $result;
$h = new HTTPHeaders($data['header']); $h = new \Zotlabs\Web\HTTPHeaders($data['header']);
$headers = $h->fetcharr(); $headers = $h->fetcharr();
$body = $data['body']; $body = $data['body'];
$headers['(request-target)'] = $data['request_target']; $headers['(request-target)'] = $data['request_target'];
@@ -54,7 +57,9 @@ class HTTPSig {
else { else {
$headers = []; $headers = [];
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI']; $headers['(request-target)'] =
strtolower($_SERVER['REQUEST_METHOD']) . ' ' .
$_SERVER['REQUEST_URI'];
$headers['content-type'] = $_SERVER['CONTENT_TYPE']; $headers['content-type'] = $_SERVER['CONTENT_TYPE'];
$headers['content-length'] = $_SERVER['CONTENT_LENGTH']; $headers['content-length'] = $_SERVER['CONTENT_LENGTH'];
@@ -70,32 +75,6 @@ class HTTPSig {
// logger('headers: ' . print_r($headers,true), LOGGER_ALL); // logger('headers: ' . print_r($headers,true), LOGGER_ALL);
return $headers;
}
// See draft-cavage-http-signatures-10
static function verify($data,$key = '') {
$body = $data;
$headers = null;
$result = [
'signer' => '',
'portable_id' => '',
'header_signed' => false,
'header_valid' => false,
'content_signed' => false,
'content_valid' => false
];
$headers = self::find_headers($data,$body);
if(! $headers)
return $result;
$sig_block = null; $sig_block = null;
if(array_key_exists('signature',$headers)) { if(array_key_exists('signature',$headers)) {
@@ -106,7 +85,7 @@ class HTTPSig {
} }
if(! $sig_block) { if(! $sig_block) {
logger('no signature provided.', LOGGER_DEBUG); logger('no signature provided.');
return $result; return $result;
} }
@@ -124,6 +103,9 @@ class HTTPSig {
if(array_key_exists($h,$headers)) { if(array_key_exists($h,$headers)) {
$signed_data .= $h . ': ' . $headers[$h] . "\n"; $signed_data .= $h . ': ' . $headers[$h] . "\n";
} }
if(strpos($h,'.')) {
$spoofable = true;
}
if($h === 'date') { if($h === 'date') {
$d = new \DateTime($headers[$h]); $d = new \DateTime($headers[$h]);
$d->setTimeZone(new \DateTimeZone('UTC')); $d->setTimeZone(new \DateTimeZone('UTC'));
@@ -146,89 +128,63 @@ class HTTPSig {
$algorithm = 'sha512'; $algorithm = 'sha512';
} }
if(! array_key_exists('keyId',$sig_block)) if($key && function_exists($key)) {
return $result;
$result['signer'] = $sig_block['keyId']; $result['signer'] = $sig_block['keyId'];
$key = $key($sig_block['keyId']);
$key = self::get_key($key,$result['signer']);
if(! ($key && $key['public_key'])) {
return $result;
} }
$x = rsa_verify($signed_data,$sig_block['signature'],$key['public_key'],$algorithm); if(! $key) {
$result['signer'] = $sig_block['keyId'];
$key = self::get_activitypub_key($sig_block['keyId']);
}
if(! $key)
return $result;
$x = rsa_verify($signed_data,$sig_block['signature'],$key,$algorithm);
logger('verified: ' . $x, LOGGER_DEBUG); logger('verified: ' . $x, LOGGER_DEBUG);
if(! $x) { if(! $x)
logger('verify failed for ' . $result['signer'] . ' alg=' . $algorithm . (($key['public_key']) ? '' : ' no key'));
$sig_block['signature'] = base64_encode($sig_block['signature']);
logger('affected sigblock: ' . print_r($sig_block,true));
logger('signed_data: ' . print_r($signed_data,true));
logger('headers: ' . print_r($headers,true));
logger('server: ' . print_r($_SERVER,true));
return $result; return $result;
}
$result['portable_id'] = $key['portable_id']; if(! $spoofable)
$result['header_valid'] = true; $result['header_valid'] = true;
if(in_array('digest',$signed_headers)) { if(in_array('digest',$signed_headers)) {
$result['content_signed'] = true; $result['content_signed'] = true;
$digest = explode('=', $headers['digest'], 2); $digest = explode('=', $headers['digest']);
if($digest[0] === 'SHA-256') if($digest[0] === 'SHA-256')
$hashalg = 'sha256'; $hashalg = 'sha256';
if($digest[0] === 'SHA-512') if($digest[0] === 'SHA-512')
$hashalg = 'sha512'; $hashalg = 'sha512';
if(base64_encode(hash($hashalg,$body,true)) === $digest[1]) { // The explode operation will have stripped the '=' padding, so compare against unpadded base64
if(rtrim(base64_encode(hash($hashalg,$body,true)),'=') === $digest[1]) {
$result['content_valid'] = true; $result['content_valid'] = true;
} }
}
if(in_array('x-zot-digest',$signed_headers)) {
$result['content_signed'] = true;
$digest = explode('=', $headers['x-zot-digest']);
if($digest[0] === 'SHA-256')
$hashalg = 'sha256';
if($digest[0] === 'SHA-512')
$hashalg = 'sha512';
// The explode operation will have stripped the '=' padding, so compare against unpadded base64
if(rtrim(base64_encode(hash($hashalg,$_POST['data'],true)),'=') === $digest[1]) {
$result['content_valid'] = true;
}
}
logger('Content_Valid: ' . (($result['content_valid']) ? 'true' : 'false')); logger('Content_Valid: ' . (($result['content_valid']) ? 'true' : 'false'));
}
return $result; return $result;
} }
static function get_key($key,$id) {
if($key) {
if(function_exists($key)) {
return $key($id);
}
return [ 'public_key' => $key ];
}
if(strpos($id,'#') === false) {
$key = self::get_webfinger_key($id);
}
if(! $key) {
$key = self::get_activitystreams_key($id);
}
return $key;
}
function convertKey($key) {
if(strstr($key,'RSA ')) {
return rsatopem($key);
}
elseif(substr($key,0,5) === 'data:') {
return convert_salmon_key($key);
}
else {
return $key;
}
}
/** /**
* @brief * @brief
* *
@@ -236,131 +192,57 @@ class HTTPSig {
* @return boolean|string * @return boolean|string
* false if no pub key found, otherwise return the pub key * false if no pub key found, otherwise return the pub key
*/ */
function get_activitypub_key($id) {
function get_activitystreams_key($id) { if(strpos($id,'acct:') === 0) {
$x = q("select xchan_pubkey from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' limit 1",
// remove fragment dbesc(str_replace('acct:','',$id))
);
$url = ((strpos($id,'#')) ? substr($id,0,strpos($id,'#')) : $id); }
else {
$x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s' limit 1", $x = q("select xchan_pubkey from xchan where xchan_hash = '%s' and xchan_network = 'activitypub' ",
dbesc(str_replace('acct:','',$url)), dbesc($id)
dbesc($url)
); );
if($x && $x[0]['xchan_pubkey']) {
return [ 'portable_id' => $x[0]['xchan_hash'], 'public_key' => $x[0]['xchan_pubkey'] , 'hubloc' => $x[0] ];
} }
$r = ActivityStreams::fetch($id); if($x && $x[0]['xchan_pubkey']) {
return ($x[0]['xchan_pubkey']);
}
if(function_exists('as_fetch'))
$r = as_fetch($id);
if($r) { if($r) {
if(array_key_exists('publicKey',$r) && array_key_exists('publicKeyPem',$r['publicKey']) && array_key_exists('id',$r['publicKey'])) { $j = json_decode($r,true);
if($r['publicKey']['id'] === $id || $r['id'] === $id) {
$portable_id = ((array_key_exists('owner',$r['publicKey'])) ? $r['publicKey']['owner'] : EMPTY_STR); if(array_key_exists('publicKey',$j) && array_key_exists('publicKeyPem',$j['publicKey'])) {
return [ 'public_key' => self::convertKey($r['publicKey']['publicKeyPem']), 'portable_id' => $portable_id, 'hubloc' => [] ]; if((array_key_exists('id',$j['publicKey']) && $j['publicKey']['id'] !== $id) && $j['id'] !== $id)
} return false;
return($j['publicKey']['publicKeyPem']);
} }
} }
return false; return false;
} }
function get_webfinger_key($id) {
$x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s' limit 1",
dbesc(str_replace('acct:','',$id)),
dbesc($id)
);
if($x && $x[0]['xchan_pubkey']) {
return [ 'portable_id' => $x[0]['xchan_hash'], 'public_key' => $x[0]['xchan_pubkey'] , 'hubloc' => $x[0] ];
}
$wf = Webfinger::exec($id);
$key = [ 'portable_id' => '', 'public_key' => '', 'hubloc' => [] ];
if($wf) {
if(array_key_exists('properties',$wf) && array_key_exists('https://w3id.org/security/v1#publicKeyPem',$wf['properties'])) {
$key['public_key'] = self::convertKey($wf['properties']['https://w3id.org/security/v1#publicKeyPem']);
}
if(array_key_exists('links', $wf) && is_array($wf['links'])) {
foreach($wf['links'] as $l) {
if(! (is_array($l) && array_key_exists('rel',$l))) {
continue;
}
if($l['rel'] === 'magic-public-key' && array_key_exists('href',$l) && $key['public_key'] === EMPTY_STR) {
$key['public_key'] = self::convertKey($l['href']);
}
}
}
}
return (($key['public_key']) ? $key : false);
}
function get_zotfinger_key($id) {
$x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s' limit 1",
dbesc(str_replace('acct:','',$id)),
dbesc($id)
);
if($x && $x[0]['xchan_pubkey']) {
return [ 'portable_id' => $x[0]['xchan_hash'], 'public_key' => $x[0]['xchan_pubkey'] , 'hubloc' => $x[0] ];
}
$wf = Webfinger::exec($id);
$key = [ 'portable_id' => '', 'public_key' => '', 'hubloc' => [] ];
if($wf) {
if(array_key_exists('properties',$wf) && array_key_exists('https://w3id.org/security/v1#publicKeyPem',$wf['properties'])) {
$key['public_key'] = self::convertKey($wf['properties']['https://w3id.org/security/v1#publicKeyPem']);
}
if(array_key_exists('links', $wf) && is_array($wf['links'])) {
foreach($wf['links'] as $l) {
if(! (is_array($l) && array_key_exists('rel',$l))) {
continue;
}
if($l['rel'] === 'http://purl.org/zot/protocol/6.0' && array_key_exists('href',$l) && $l['href'] !== EMPTY_STR) {
$z = \Zotlabs\Lib\Zotfinger::exec($l['href']);
if($z) {
$i = Libzot::import_xchan($z['data']);
if($i['success']) {
$key['portable_id'] = $i['hash'];
$x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_id_url = '%s' limit 1",
dbesc($l['href'])
);
if($x) {
$key['hubloc'] = $x[0];
}
}
}
}
if($l['rel'] === 'magic-public-key' && array_key_exists('href',$l) && $key['public_key'] === EMPTY_STR) {
$key['public_key'] = self::convertKey($l['href']);
}
}
}
}
return (($key['public_key']) ? $key : false);
}
/** /**
* @brief * @brief
* *
* @param string $request
* @param array $head * @param array $head
* @param string $prvkey * @param string $prvkey
* @param string $keyid (optional, default '') * @param string $keyid (optional, default 'Key')
* @param boolean $send_headers (optional, default false)
* If set send a HTTP header
* @param boolean $auth (optional, default false) * @param boolean $auth (optional, default false)
* @param string $alg (optional, default 'sha256') * @param string $alg (optional, default 'sha256')
* @param array $encryption [ 'key', 'algorithm' ] or false * @param string $crypt_key (optional, default null)
* @param string $crypt_algo (optional, default 'aes256ctr')
* @return array * @return array
*/ */
static function create_sig($head, $prvkey, $keyid = EMPTY_STR, $auth = false, $alg = 'sha256', $encryption = false ) { static function create_sig($request, $head, $prvkey, $keyid = 'Key', $send_headers = false, $auth = false,
$alg = 'sha256', $crypt_key = null, $crypt_algo = 'aes256ctr') {
$return_headers = []; $return_headers = [];
@@ -371,16 +253,15 @@ class HTTPSig {
$algorithm = 'rsa-sha512'; $algorithm = 'rsa-sha512';
} }
$x = self::sign($head,$prvkey,$alg); $x = self::sign($request,$head,$prvkey,$alg);
$headerval = 'keyId="' . $keyid . '",algorithm="' . $algorithm . '",headers="' . $x['headers'] . '",signature="' . $x['signature'] . '"'; $headerval = 'keyId="' . $keyid . '",algorithm="' . $algorithm
. '",headers="' . $x['headers'] . '",signature="' . $x['signature'] . '"';
if($encryption) { if($crypt_key) {
$x = crypto_encapsulate($headerval,$encryption['key'],$encryption['algorithm']); $x = crypto_encapsulate($headerval,$crypt_key,$crypt_algo);
if(is_array($x)) {
$headerval = 'iv="' . $x['iv'] . '",key="' . $x['key'] . '",alg="' . $x['alg'] . '",data="' . $x['data'] . '"'; $headerval = 'iv="' . $x['iv'] . '",key="' . $x['key'] . '",alg="' . $x['alg'] . '",data="' . $x['data'] . '"';
} }
}
if($auth) { if($auth) {
$sighead = 'Authorization: Signature ' . $headerval; $sighead = 'Authorization: Signature ' . $headerval;
@@ -391,52 +272,43 @@ class HTTPSig {
if($head) { if($head) {
foreach($head as $k => $v) { foreach($head as $k => $v) {
// strip the request-target virtual header from the output headers if($send_headers) {
if($k === '(request-target)') { header($k . ': ' . $v);
continue;
} }
else {
$return_headers[] = $k . ': ' . $v; $return_headers[] = $k . ': ' . $v;
} }
} }
}
if($send_headers) {
header($sighead);
}
else {
$return_headers[] = $sighead; $return_headers[] = $sighead;
}
return $return_headers; return $return_headers;
} }
/**
* @brief set headers
*
* @param array $headers
* @return void
*/
static function set_headers($headers) {
if($headers && is_array($headers)) {
foreach($headers as $h) {
header($h);
}
}
}
/** /**
* @brief * @brief
* *
* @param string $request
* @param array $head * @param array $head
* @param string $prvkey * @param string $prvkey
* @param string $alg (optional) default 'sha256' * @param string $alg (optional) default 'sha256'
* @return array * @return array
*/ */
static function sign($request, $head, $prvkey, $alg = 'sha256') {
static function sign($head, $prvkey, $alg = 'sha256') {
$ret = []; $ret = [];
$headers = ''; $headers = '';
$fields = ''; $fields = '';
if($request) {
logger('signing: ' . print_r($head,true), LOGGER_DATA); $headers = '(request-target)' . ': ' . trim($request) . "\n";
$fields = '(request-target)';
}
if($head) { if($head) {
foreach($head as $k => $v) { foreach($head as $k => $v) {
@@ -468,9 +340,12 @@ class HTTPSig {
* - \e array \b headers * - \e array \b headers
* - \e string \b signature * - \e string \b signature
*/ */
static function parse_sigheader($header) { static function parse_sigheader($header) {
if(is_array($header)) {
btlogger('is_array: ' . print_r($header,true));
}
$ret = []; $ret = [];
$matches = []; $matches = [];
@@ -506,7 +381,6 @@ class HTTPSig {
* - \e string \b alg * - \e string \b alg
* - \e string \b data * - \e string \b data
*/ */
static function decrypt_sigheader($header, $prvkey = null) { static function decrypt_sigheader($header, $prvkey = null) {
$iv = $key = $alg = $data = null; $iv = $key = $alg = $data = null;

View File

@@ -56,7 +56,7 @@ class Router {
$routes = Route::get(); $routes = Route::get();
if($routes) { if($routes) {
foreach($routes as $route) { foreach($routes as $route) {
if(is_array($route) && file_exists($route[0]) && strtolower($route[1]) === $module) { if(is_array($route) && strtolower($route[1]) === $module) {
include_once($route[0]); include_once($route[0]);
if(class_exists($modname)) { if(class_exists($modname)) {
$this->controller = new $modname; $this->controller = new $modname;

View File

@@ -38,15 +38,10 @@ class SessionHandler implements \SessionHandlerInterface {
function write ($id, $data) { function write ($id, $data) {
// Pretend everything is hunky-dory, even though it isn't.
// There probably isn't anything we can do about it in any event.
// See: https://stackoverflow.com/a/43636110
if(! $id || ! $data) { if(! $id || ! $data) {
return true; return false;
} }
// Unless we authenticate somehow, only keep a session for 5 minutes // Unless we authenticate somehow, only keep a session for 5 minutes
// The viewer can extend this by performing any web action using the // The viewer can extend this by performing any web action using the
// original cookie, but this allows us to cleanup the hundreds or // original cookie, but this allows us to cleanup the hundreds or

View File

@@ -2,8 +2,6 @@
namespace Zotlabs\Zot; namespace Zotlabs\Zot;
use Zotlabs\Web\HTTPSig;
/** /**
* @brief Finger * @brief Finger
* *
@@ -97,7 +95,8 @@ class Finger {
$headers['X-Zot-Nonce'] = random_string(); $headers['X-Zot-Nonce'] = random_string();
$headers['Host'] = $parsed_host; $headers['Host'] = $parsed_host;
$xhead = HTTPSig::create_sig($headers,$channel['channel_prvkey'],'acct:' . channel_reddress($channel)); $xhead = \Zotlabs\Web\HTTPSig::create_sig('',$headers,$channel['channel_prvkey'],
'acct:' . $channel['channel_address'] . '@' . \App::get_hostname(),false);
$retries = 0; $retries = 0;
@@ -130,7 +129,7 @@ class Finger {
$x = json_decode($result['body'], true); $x = json_decode($result['body'], true);
$verify = HTTPSig::verify($result,(($x) ? $x['key'] : '')); $verify = \Zotlabs\Web\HTTPSig::verify($result,(($x) ? $x['key'] : ''));
if($x && (! $verify['header_valid'])) { if($x && (! $verify['header_valid'])) {
$signed_token = ((is_array($x) && array_key_exists('signed_token', $x)) ? $x['signed_token'] : null); $signed_token = ((is_array($x) && array_key_exists('signed_token', $x)) ? $x['signed_token'] : null);

View File

@@ -88,7 +88,8 @@ class Finger {
$headers = []; $headers = [];
$headers['X-Zot-Channel'] = $channel['channel_address'] . '@' . \App::get_hostname(); $headers['X-Zot-Channel'] = $channel['channel_address'] . '@' . \App::get_hostname();
$headers['X-Zot-Nonce'] = random_string(); $headers['X-Zot-Nonce'] = random_string();
$xhead = HTTPSig::create_sig($headers,$channel['channel_prvkey'],'acct:' . channel_reddress($channel)); $xhead = \Zotlabs\Web\HTTPSig::create_sig('',$headers,$channel['channel_prvkey'],
'acct:' . $channel['channel_address'] . '@' . \App::get_hostname(),false);
$retries = 0; $retries = 0;
@@ -121,7 +122,7 @@ class Finger {
$x = json_decode($result['body'], true); $x = json_decode($result['body'], true);
$verify = HTTPSig::verify($result,(($x) ? $x['key'] : '')); $verify = \Zotlabs\Web\HTTPSig::verify($result,(($x) ? $x['key'] : ''));
if($x && (! $verify['header_valid'])) { if($x && (! $verify['header_valid'])) {
$signed_token = ((is_array($x) && array_key_exists('signed_token', $x)) ? $x['signed_token'] : null); $signed_token = ((is_array($x) && array_key_exists('signed_token', $x)) ? $x['signed_token'] : null);

536
Zotlabs/Zot6/HTTPSig.php Normal file
View File

@@ -0,0 +1,536 @@
<?php
namespace Zotlabs\Zot6;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\Webfinger;
use Zotlabs\Web\HTTPHeaders;
use Zotlabs\Lib\Libzot;
/**
* @brief Implements HTTP Signatures per draft-cavage-http-signatures-10.
*
* @see https://tools.ietf.org/html/draft-cavage-http-signatures-10
*/
class HTTPSig {
/**
* @brief RFC5843
*
* @see https://tools.ietf.org/html/rfc5843
*
* @param string $body The value to create the digest for
* @param string $alg hash algorithm (one of 'sha256','sha512')
* @return string The generated digest header string for $body
*/
static function generate_digest_header($body,$alg = 'sha256') {
$digest = base64_encode(hash($alg, $body, true));
switch($alg) {
case 'sha512':
return 'SHA-512=' . $digest;
case 'sha256':
default:
return 'SHA-256=' . $digest;
break;
}
}
static function find_headers($data,&$body) {
// decide if $data arrived via controller submission or curl
if(is_array($data) && $data['header']) {
if(! $data['success'])
return [];
$h = new HTTPHeaders($data['header']);
$headers = $h->fetcharr();
$body = $data['body'];
$headers['(request-target)'] = $data['request_target'];
}
else {
$headers = [];
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
$headers['content-type'] = $_SERVER['CONTENT_TYPE'];
$headers['content-length'] = $_SERVER['CONTENT_LENGTH'];
foreach($_SERVER as $k => $v) {
if(strpos($k,'HTTP_') === 0) {
$field = str_replace('_','-',strtolower(substr($k,5)));
$headers[$field] = $v;
}
}
}
//logger('SERVER: ' . print_r($_SERVER,true), LOGGER_ALL);
//logger('headers: ' . print_r($headers,true), LOGGER_ALL);
return $headers;
}
// See draft-cavage-http-signatures-10
static function verify($data,$key = '') {
$body = $data;
$headers = null;
$result = [
'signer' => '',
'portable_id' => '',
'header_signed' => false,
'header_valid' => false,
'content_signed' => false,
'content_valid' => false
];
$headers = self::find_headers($data,$body);
if(! $headers)
return $result;
$sig_block = null;
if(array_key_exists('signature',$headers)) {
$sig_block = self::parse_sigheader($headers['signature']);
}
elseif(array_key_exists('authorization',$headers)) {
$sig_block = self::parse_sigheader($headers['authorization']);
}
if(! $sig_block) {
logger('no signature provided.', LOGGER_DEBUG);
return $result;
}
// Warning: This log statement includes binary data
// logger('sig_block: ' . print_r($sig_block,true), LOGGER_DATA);
$result['header_signed'] = true;
$signed_headers = $sig_block['headers'];
if(! $signed_headers)
$signed_headers = [ 'date' ];
$signed_data = '';
foreach($signed_headers as $h) {
if(array_key_exists($h,$headers)) {
$signed_data .= $h . ': ' . $headers[$h] . "\n";
}
if($h === 'date') {
$d = new \DateTime($headers[$h]);
$d->setTimeZone(new \DateTimeZone('UTC'));
$dplus = datetime_convert('UTC','UTC','now + 1 day');
$dminus = datetime_convert('UTC','UTC','now - 1 day');
$c = $d->format('Y-m-d H:i:s');
if($c > $dplus || $c < $dminus) {
logger('bad time: ' . $c);
return $result;
}
}
}
$signed_data = rtrim($signed_data,"\n");
$algorithm = null;
if($sig_block['algorithm'] === 'rsa-sha256') {
$algorithm = 'sha256';
}
if($sig_block['algorithm'] === 'rsa-sha512') {
$algorithm = 'sha512';
}
if(! array_key_exists('keyId',$sig_block))
return $result;
$result['signer'] = $sig_block['keyId'];
$key = self::get_key($key,$result['signer']);
if(! ($key && $key['public_key'])) {
return $result;
}
$x = rsa_verify($signed_data,$sig_block['signature'],$key['public_key'],$algorithm);
logger('verified: ' . $x, LOGGER_DEBUG);
if(! $x) {
logger('verify failed for ' . $result['signer'] . ' alg=' . $algorithm . (($key['public_key']) ? '' : ' no key'));
$sig_block['signature'] = base64_encode($sig_block['signature']);
logger('affected sigblock: ' . print_r($sig_block,true));
logger('signed_data: ' . print_r($signed_data,true));
logger('headers: ' . print_r($headers,true));
logger('server: ' . print_r($_SERVER,true));
return $result;
}
$result['portable_id'] = $key['portable_id'];
$result['header_valid'] = true;
if(in_array('digest',$signed_headers)) {
$result['content_signed'] = true;
$digest = explode('=', $headers['digest'], 2);
if($digest[0] === 'SHA-256')
$hashalg = 'sha256';
if($digest[0] === 'SHA-512')
$hashalg = 'sha512';
if(base64_encode(hash($hashalg,$body,true)) === $digest[1]) {
$result['content_valid'] = true;
}
logger('Content_Valid: ' . (($result['content_valid']) ? 'true' : 'false'));
}
return $result;
}
static function get_key($key,$id) {
if($key) {
if(function_exists($key)) {
return $key($id);
}
return [ 'public_key' => $key ];
}
if(strpos($id,'#') === false) {
$key = self::get_webfinger_key($id);
}
if(! $key) {
$key = self::get_activitystreams_key($id);
}
return $key;
}
function convertKey($key) {
if(strstr($key,'RSA ')) {
return rsatopem($key);
}
elseif(substr($key,0,5) === 'data:') {
return convert_salmon_key($key);
}
else {
return $key;
}
}
/**
* @brief
*
* @param string $id
* @return boolean|string
* false if no pub key found, otherwise return the pub key
*/
function get_activitystreams_key($id) {
// remove fragment
$url = ((strpos($id,'#')) ? substr($id,0,strpos($id,'#')) : $id);
$x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s' limit 1",
dbesc(str_replace('acct:','',$url)),
dbesc($url)
);
if($x && $x[0]['xchan_pubkey']) {
return [ 'portable_id' => $x[0]['xchan_hash'], 'public_key' => $x[0]['xchan_pubkey'] , 'hubloc' => $x[0] ];
}
$r = ActivityStreams::fetch($id);
if($r) {
if(array_key_exists('publicKey',$r) && array_key_exists('publicKeyPem',$r['publicKey']) && array_key_exists('id',$r['publicKey'])) {
if($r['publicKey']['id'] === $id || $r['id'] === $id) {
$portable_id = ((array_key_exists('owner',$r['publicKey'])) ? $r['publicKey']['owner'] : EMPTY_STR);
return [ 'public_key' => self::convertKey($r['publicKey']['publicKeyPem']), 'portable_id' => $portable_id, 'hubloc' => [] ];
}
}
}
return false;
}
function get_webfinger_key($id) {
$x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s' limit 1",
dbesc(str_replace('acct:','',$id)),
dbesc($id)
);
if($x && $x[0]['xchan_pubkey']) {
return [ 'portable_id' => $x[0]['xchan_hash'], 'public_key' => $x[0]['xchan_pubkey'] , 'hubloc' => $x[0] ];
}
$wf = Webfinger::exec($id);
$key = [ 'portable_id' => '', 'public_key' => '', 'hubloc' => [] ];
if($wf) {
if(array_key_exists('properties',$wf) && array_key_exists('https://w3id.org/security/v1#publicKeyPem',$wf['properties'])) {
$key['public_key'] = self::convertKey($wf['properties']['https://w3id.org/security/v1#publicKeyPem']);
}
if(array_key_exists('links', $wf) && is_array($wf['links'])) {
foreach($wf['links'] as $l) {
if(! (is_array($l) && array_key_exists('rel',$l))) {
continue;
}
if($l['rel'] === 'magic-public-key' && array_key_exists('href',$l) && $key['public_key'] === EMPTY_STR) {
$key['public_key'] = self::convertKey($l['href']);
}
}
}
}
return (($key['public_key']) ? $key : false);
}
function get_zotfinger_key($id) {
$x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s' limit 1",
dbesc(str_replace('acct:','',$id)),
dbesc($id)
);
if($x && $x[0]['xchan_pubkey']) {
return [ 'portable_id' => $x[0]['xchan_hash'], 'public_key' => $x[0]['xchan_pubkey'] , 'hubloc' => $x[0] ];
}
$wf = Webfinger::exec($id);
$key = [ 'portable_id' => '', 'public_key' => '', 'hubloc' => [] ];
if($wf) {
if(array_key_exists('properties',$wf) && array_key_exists('https://w3id.org/security/v1#publicKeyPem',$wf['properties'])) {
$key['public_key'] = self::convertKey($wf['properties']['https://w3id.org/security/v1#publicKeyPem']);
}
if(array_key_exists('links', $wf) && is_array($wf['links'])) {
foreach($wf['links'] as $l) {
if(! (is_array($l) && array_key_exists('rel',$l))) {
continue;
}
if($l['rel'] === 'http://purl.org/zot/protocol/6.0' && array_key_exists('href',$l) && $l['href'] !== EMPTY_STR) {
$z = \Zotlabs\Lib\Zotfinger::exec($l['href']);
if($z) {
$i = Libzot::import_xchan($z['data']);
if($i['success']) {
$key['portable_id'] = $i['hash'];
$x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_id_url = '%s' limit 1",
dbesc($l['href'])
);
if($x) {
$key['hubloc'] = $x[0];
}
}
}
}
if($l['rel'] === 'magic-public-key' && array_key_exists('href',$l) && $key['public_key'] === EMPTY_STR) {
$key['public_key'] = self::convertKey($l['href']);
}
}
}
}
return (($key['public_key']) ? $key : false);
}
/**
* @brief
*
* @param array $head
* @param string $prvkey
* @param string $keyid (optional, default '')
* @param boolean $auth (optional, default false)
* @param string $alg (optional, default 'sha256')
* @param array $encryption [ 'key', 'algorithm' ] or false
* @return array
*/
static function create_sig($head, $prvkey, $keyid = EMPTY_STR, $auth = false, $alg = 'sha256', $encryption = false ) {
$return_headers = [];
if($alg === 'sha256') {
$algorithm = 'rsa-sha256';
}
if($alg === 'sha512') {
$algorithm = 'rsa-sha512';
}
$x = self::sign($head,$prvkey,$alg);
$headerval = 'keyId="' . $keyid . '",algorithm="' . $algorithm . '",headers="' . $x['headers'] . '",signature="' . $x['signature'] . '"';
if($encryption) {
$x = crypto_encapsulate($headerval,$encryption['key'],$encryption['algorithm']);
if(is_array($x)) {
$headerval = 'iv="' . $x['iv'] . '",key="' . $x['key'] . '",alg="' . $x['alg'] . '",data="' . $x['data'] . '"';
}
}
if($auth) {
$sighead = 'Authorization: Signature ' . $headerval;
}
else {
$sighead = 'Signature: ' . $headerval;
}
if($head) {
foreach($head as $k => $v) {
// strip the request-target virtual header from the output headers
if($k === '(request-target)') {
continue;
}
$return_headers[] = $k . ': ' . $v;
}
}
$return_headers[] = $sighead;
return $return_headers;
}
/**
* @brief set headers
*
* @param array $headers
* @return void
*/
static function set_headers($headers) {
if($headers && is_array($headers)) {
foreach($headers as $h) {
header($h);
}
}
}
/**
* @brief
*
* @param array $head
* @param string $prvkey
* @param string $alg (optional) default 'sha256'
* @return array
*/
static function sign($head, $prvkey, $alg = 'sha256') {
$ret = [];
$headers = '';
$fields = '';
logger('signing: ' . print_r($head,true), LOGGER_DATA);
if($head) {
foreach($head as $k => $v) {
$headers .= strtolower($k) . ': ' . trim($v) . "\n";
if($fields)
$fields .= ' ';
$fields .= strtolower($k);
}
// strip the trailing linefeed
$headers = rtrim($headers,"\n");
}
$sig = base64_encode(rsa_sign($headers,$prvkey,$alg));
$ret['headers'] = $fields;
$ret['signature'] = $sig;
return $ret;
}
/**
* @brief
*
* @param string $header
* @return array associate array with
* - \e string \b keyID
* - \e string \b algorithm
* - \e array \b headers
* - \e string \b signature
*/
static function parse_sigheader($header) {
$ret = [];
$matches = [];
// if the header is encrypted, decrypt with (default) site private key and continue
if(preg_match('/iv="(.*?)"/ism',$header,$matches))
$header = self::decrypt_sigheader($header);
if(preg_match('/keyId="(.*?)"/ism',$header,$matches))
$ret['keyId'] = $matches[1];
if(preg_match('/algorithm="(.*?)"/ism',$header,$matches))
$ret['algorithm'] = $matches[1];
if(preg_match('/headers="(.*?)"/ism',$header,$matches))
$ret['headers'] = explode(' ', $matches[1]);
if(preg_match('/signature="(.*?)"/ism',$header,$matches))
$ret['signature'] = base64_decode(preg_replace('/\s+/','',$matches[1]));
if(($ret['signature']) && ($ret['algorithm']) && (! $ret['headers']))
$ret['headers'] = [ 'date' ];
return $ret;
}
/**
* @brief
*
* @param string $header
* @param string $prvkey (optional), if not set use site private key
* @return array|string associative array, empty string if failue
* - \e string \b iv
* - \e string \b key
* - \e string \b alg
* - \e string \b data
*/
static function decrypt_sigheader($header, $prvkey = null) {
$iv = $key = $alg = $data = null;
if(! $prvkey) {
$prvkey = get_config('system', 'prvkey');
}
$matches = [];
if(preg_match('/iv="(.*?)"/ism',$header,$matches))
$iv = $matches[1];
if(preg_match('/key="(.*?)"/ism',$header,$matches))
$key = $matches[1];
if(preg_match('/alg="(.*?)"/ism',$header,$matches))
$alg = $matches[1];
if(preg_match('/data="(.*?)"/ism',$header,$matches))
$data = $matches[1];
if($iv && $key && $alg && $data) {
return crypto_unencapsulate([ 'encrypted' => true, 'iv' => $iv, 'key' => $key, 'alg' => $alg, 'data' => $data ] , $prvkey);
}
return '';
}
}

View File

@@ -4,7 +4,6 @@ namespace Zotlabs\Zot6;
use Zotlabs\Lib\Config; use Zotlabs\Lib\Config;
use Zotlabs\Lib\Libzot; use Zotlabs\Lib\Libzot;
use Zotlabs\Web\HTTPSig;
class Receiver { class Receiver {
@@ -194,9 +193,7 @@ class Receiver {
case 'response': // upstream message case 'response': // upstream message
case 'sync': case 'sync':
default: default:
if ($this->sender) {
$this->response = $this->handler->Notify($this->data,$this->hub); $this->response = $this->handler->Notify($this->data,$this->hub);
}
break; break;
} }

View File

@@ -50,7 +50,7 @@ require_once('include/attach.php');
require_once('include/bbcode.php'); require_once('include/bbcode.php');
define ( 'PLATFORM_NAME', 'hubzilla' ); define ( 'PLATFORM_NAME', 'hubzilla' );
define ( 'STD_VERSION', '4.6' ); define ( 'STD_VERSION', '4.2' );
define ( 'ZOT_REVISION', '6.0a' ); define ( 'ZOT_REVISION', '6.0a' );
define ( 'DB_UPDATE_VERSION', 1234 ); define ( 'DB_UPDATE_VERSION', 1234 );
@@ -80,12 +80,12 @@ define ( 'DIRECTORY_MODE_STANDALONE', 0x0100); // A detached (off the grid) hub
// point to go out and find the rest of the world. // point to go out and find the rest of the world.
define ( 'DIRECTORY_REALM', 'RED_GLOBAL'); define ( 'DIRECTORY_REALM', 'RED_GLOBAL');
define ( 'DIRECTORY_FALLBACK_MASTER', 'https://hub.netzgemeinde.eu'); define ( 'DIRECTORY_FALLBACK_MASTER', 'https://zotadel.net');
$DIRECTORY_FALLBACK_SERVERS = array( $DIRECTORY_FALLBACK_SERVERS = array(
'https://hub.netzgemeinde.eu', 'https://zotadel.net',
'https://zotsite.net', 'https://zotsite.net',
'https://hub.libranet.de' 'https://hub.netzgemeinde.eu'
); );
@@ -468,7 +468,7 @@ define ( 'NAMESPACE_YMEDIA', 'http://search.yahoo.com/mrss/' );
define ( 'ACTIVITYSTREAMS_JSONLD_REV', 'https://www.w3.org/ns/activitystreams' ); define ( 'ACTIVITYSTREAMS_JSONLD_REV', 'https://www.w3.org/ns/activitystreams' );
define ( 'ZOT_APSCHEMA_REV', '/apschema/v1.8' ); define ( 'ZOT_APSCHEMA_REV', '/apschema/v1.5' );
/** /**
* activity stream defines * activity stream defines
*/ */
@@ -896,49 +896,6 @@ class App {
if(x($_GET,'q')) if(x($_GET,'q'))
self::$cmd = escape_tags(trim($_GET['q'],'/\\')); self::$cmd = escape_tags(trim($_GET['q'],'/\\'));
// Serve raw files from the file system in certain cases.
$filext = pathinfo(self::$cmd, PATHINFO_EXTENSION);
$serve_rawfiles=[
'jpg'=>'image/jpeg',
'jpeg'=>'image/jpeg',
'gif'=>'image/gif',
'png'=>'image/png',
'ico'=>'image/vnd.microsoft.icon',
'css'=>'text/css',
'js'=>'text/javascript',
'htm'=>'text/html',
'html'=>'text/html',
'map'=>'application/octet-stream',
'ttf'=>'font/ttf',
'woff'=>'font/woff',
'woff2'=>'font/woff2',
'svg'=>'image/svg+xml'];
if (array_key_exists($filext, $serve_rawfiles) && file_exists(self::$cmd)) {
$staticfilecwd = getcwd();
$staticfilerealpath = realpath(self::$cmd);
if(strpos($staticfilerealpath,$staticfilecwd) !== 0) {
http_status_exit(404,'not found');
}
$staticfileetag = '"'.md5($staticfilerealpath.filemtime(self::$cmd)).'"';
header("ETag: ".$staticfileetag);
header("Cache-control: max-age=2592000");
if(isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
// If HTTP_IF_NONE_MATCH is same as the generated ETag => content is the same as browser cache
// So send a 304 Not Modified response header and exit
if($_SERVER['HTTP_IF_NONE_MATCH'] == $staticfileetag) {
http_status_exit(304,'not modified');
}
}
header("Content-type: ".$serve_rawfiles[$filext]);
$handle = fopen(self::$cmd, "rb");
fpassthru($handle);
fclose($handle);
killme();
}
// unix style "homedir" // unix style "homedir"
if((substr(self::$cmd, 0, 1) === '~') || (substr(self::$cmd, 0, 1) === '@')) if((substr(self::$cmd, 0, 1) === '~') || (substr(self::$cmd, 0, 1) === '@'))
@@ -1205,8 +1162,7 @@ class App {
'$linkrel' => head_get_links(), '$linkrel' => head_get_links(),
'$js_strings' => js_strings(), '$js_strings' => js_strings(),
'$zid' => get_my_address(), '$zid' => get_my_address(),
'$channel_id' => self::$profile['uid'], '$channel_id' => self::$profile['uid']
'$auto_save_draft' => ((feature_enabled(self::$profile['uid'], 'auto_save_draft')) ? "true" : "false")
] ]
) . self::$page['htmlhead']; ) . self::$page['htmlhead'];

View File

@@ -28,19 +28,19 @@
"ext-mbstring" : "*", "ext-mbstring" : "*",
"ext-xml" : "*", "ext-xml" : "*",
"ext-openssl" : "*", "ext-openssl" : "*",
"sabre/dav" : "^4.0", "sabre/dav" : "~3.2",
"michelf/php-markdown" : "^1.7", "michelf/php-markdown" : "^1.7",
"bshaffer/oauth2-server-php": "^1.9", "bshaffer/oauth2-server-php": "^1.9",
"ezyang/htmlpurifier": "^4.9", "ezyang/htmlpurifier": "^4.9",
"simplepie/simplepie": "~1.5", "simplepie/simplepie": "~1.5",
"league/html-to-markdown": "^4.4", "league/html-to-markdown": "^4.4",
"pear/text_languagedetect": "^1.0", "pear/text_languagedetect": "^1.0",
"commerceguys/intl": "~1.0.5", "commerceguys/intl": "~0.7",
"lukasreschke/id3parser": "^0.0.3", "lukasreschke/id3parser": "^0.0.1",
"smarty/smarty": "~3.1", "smarty/smarty": "~3.1",
"ramsey/uuid": "^3.8", "ramsey/uuid": "^3.8",
"twbs/bootstrap": "^4.3.1", "twbs/bootstrap": "^4.3.1",
"blueimp/jquery-file-upload": "^10.3", "blueimp/jquery-file-upload": "^9.25",
"desandro/imagesloaded": "^4.1" "desandro/imagesloaded": "^4.1"
}, },
"require-dev" : { "require-dev" : {

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