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
1901 changed files with 517100 additions and 190168 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
- 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).
# Step-by-Step Overwiew
## Preconditions
Hardware
@@ -15,10 +55,10 @@ Hardware
Software
+ Fresh installation of Debian 10 (Stretch)
+ Fresh installation of Debian 9 (Stretch)
+ 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)
+ Log on to your fresh Debian
@@ -36,6 +76,13 @@ Software
- ... wait, wait, wait until the script is finised
+ 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
In Admin settings of hubzilla or via terminal
@@ -43,61 +90,17 @@ In Admin settings of hubzilla or via terminal
cd /var/www/html
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
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
Follow the installation instruction there.
## Configure your Router
@@ -133,7 +136,7 @@ The cost is 1,50 € per month (2019).
## 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...
@@ -143,5 +146,12 @@ to boot the Rapsi to the client console.
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

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

@@ -26,15 +26,16 @@
# - install
# * apache webserer,
# * php,
# * mariadb - the database for hubzilla,
# * adminer,
# * git to download and update addons
# * mysql - the database for hubzilla,
# * phpmyadmin,
# * git to download and update hubzilla addon
# - download hubzilla core and addons
# - configure cron
# * "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
# * run command to keep the IP up-to-date > DynDNS provided by selfHOST.de or freedns.afraid.org
# * backup hubzillas database and files (rsync)
# - run letsencrypt to create, register and use a certifacte for https
# - letsencrypt
#
#
# Discussion
@@ -43,6 +44,11 @@
# Security - password is the same for mysql-server, phpmyadmin and hubzilla db
# - The script runs into installation errors for phpmyadmin if it uses
# 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
# --------------------------
@@ -55,7 +61,7 @@
# - creates a daily cron that runs the hubzilla-daily.sh
#
# 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
# - /etc/letsencrypt/ > certificates
#
@@ -67,6 +73,8 @@
# The script is based on Thomas Willinghams script "debian-setup.sh"
# 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
# https://www.gnu.org/software/bash/manual/bash.html
#
@@ -86,9 +94,9 @@ function check_sanity {
then
die "Debian is supported only"
fi
if ! grep -q 'Linux 10' /etc/issue
if ! grep -q 'Linux 9' /etc/issue
then
die "Linux 10 (buster) is supported only"x
die "Linux 9 (stretch) is supported only"x
fi
}
@@ -199,17 +207,21 @@ function print_warn {
}
function stop_hubzilla {
print_info "stopping apache webserver..."
systemctl stop apache2
print_info "stopping mysql db..."
systemctl stop mariadb
if [ -d /etc/apache2 ]
then
print_info "stopping apache webserver..."
service apache2 stop
fi
if [ -f /etc/init.d/mysql ]
then
print_info "stopping mysql db..."
/etc/init.d/mysql stop
fi
}
function install_apache {
print_info "installing apache..."
nocheck_install "apache2 apache2-utils"
a2enmod rewrite
systemctl restart apache2
}
function install_imagemagick {
@@ -222,11 +234,6 @@ function install_curl {
nocheck_install "curl"
}
function install_wget {
print_info "installing wget..."
nocheck_install "wget"
}
function install_sendmail {
print_info "installing sendmail..."
nocheck_install "sendmail sendmail-bin"
@@ -235,47 +242,65 @@ function install_sendmail {
function install_php {
# openssl and mbstring are included in libapache2-mod-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"
sed -i "s/^upload_max_filesize =.*/upload_max_filesize = 100M/g" /etc/php/7.3/apache2/php.ini
sed -i "s/^post_max_size =.*/post_max_size = 100M/g" /etc/php/7.3/apache2/php.ini
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.0/apache2/php.ini
sed -i "s/^post_max_size =.*/post_max_size = 100M/g" /etc/php/7.0/apache2/php.ini
}
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..."
if [ -z "$mysqlpass" ]
then
die "mysqlpass not set in $configfile"
fi
if type mysql ; then
echo "Yes, mysql is installed"
else
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
echo mysql-server mysql-server/root_password password $mysqlpass | debconf-set-selections
echo mysql-server mysql-server/root_password_again password $mysqlpass | debconf-set-selections
nocheck_install "php-mysql mysql-server mysql-client"
}
function install_adminer {
print_info "installing adminer..."
nocheck_install "adminer"
if [ ! -f /etc/adminer/adminer.conf ]
function install_phpmyadmin {
print_info "installing phpmyadmin..."
if [ -z "$phpmyadminpass" ]
then
echo "Alias /adminer /usr/share/adminer/adminer" > /etc/adminer/adminer.conf
ln -s /etc/adminer/adminer.conf /etc/apache2/conf-available/adminer.conf
else
print_info "file /etc/adminer/adminer.conf exists already"
die "phpmyadminpass not set in $configfile"
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
if [ ! -f /etc/apache2/apache2.conf ]
then
die "could not find file /etc/apache2/apache2.conf"
@@ -283,10 +308,12 @@ function install_adminer {
sed -i \
"s/AllowOverride None/AllowOverride all/" \
/etc/apache2/apache2.conf
a2enconf adminer
systemctl restart mariadb
systemctl reload apache2
if [ -z "`grep 'Include /etc/phpmyadmin/apache.conf' /etc/apache2/apache2.conf`" ]
then
echo "Include /etc/phpmyadmin/apache.conf" >> /etc/apache2/apache2.conf
fi
service apache2 restart
/etc/init.d/mysql start
}
function create_hubzilla_db {
@@ -303,7 +330,6 @@ function create_hubzilla_db {
then
die "hubzilla_db_pass not set in $configfile"
fi
systemctl restart mariadb
Q1="CREATE DATABASE IF NOT EXISTS $hubzilla_db_name;"
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';"
@@ -423,11 +449,22 @@ function install_letsencrypt {
then
die "Failed to install let's encrypt: 'le_domain' is empty in $configfile"
fi
# check if user gave mail address
if [ -z "$le_email" ]
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
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 ..."
certbot --apache -w /var/www/html -d $le_domain -m $le_email --agree-tos --non-interactive --redirect --hsts --uir
service apache2 restart
@@ -446,19 +483,12 @@ function check_https {
}
function install_hubzilla {
print_info "installing addons..."
print_info "installing hubzilla addons..."
cd /var/www/html/
if git remote -v | grep -i "origin.*hubzilla.*core"
then
print_info "hubzilla"
util/add_addon_repo https://framagit.org/hubzilla/addons hzaddons
elif git remote -v | grep -i "origin.*zap.*core"
then
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
# if you install Hubzilla
util/add_addon_repo https://framagit.org/hubzilla/addons hzaddons
# if you install ZAP
#util/add_addon_repo https://framagit.org/zot/zap-addons.git zaddons
mkdir -p "store/[data]/smarty3"
chmod -R 777 store
touch .htconfig.php
@@ -468,7 +498,13 @@ function install_hubzilla {
chown root:www-data /var/www/html/
chown root:www-data /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 {
@@ -599,6 +635,7 @@ source $configfile
selfhostdir=/etc/selfhost
selfhostscript=selfhost-updater.sh
hubzilladaily=hubzilla-daily.sh
plugins_update=.homeinstall/plugins_update.sh
backup_mount_point=/media/hubzilla_backup
#set -x # activate debugging from here
@@ -607,13 +644,12 @@ check_config
stop_hubzilla
update_upgrade
install_curl
install_wget
install_sendmail
install_apache
install_imagemagick
install_php
install_mysql
install_adminer
install_phpmyadmin
create_hubzilla_db
run_freedns
install_run_selfhost
@@ -623,34 +659,23 @@ configure_cron_selfhost
if [ "$le_domain" != "localhost" ]
then
install_letsencrypt
configure_apache_for_https
check_https
install_letsencrypt
check_https
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"
fi
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
if [ "$le_domain" != "localhost" ]
then
install_cryptosetup
write_uninstall_script
install_rsync
install_cryptosetup
else
print_info "is localhost - skipped installation of cryptosetup"
print_info "is localhost - skipped installation of cryptosetup"
fi
#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)
- Introduce Calendar app which deprecates Events and CalDAV apps and streamlines the featuresets
- 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.
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
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
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
SOFTWARE.
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -97,26 +97,26 @@ class Cron {
// 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",
intval(PHOTO_CACHE),
db_utcnow(),
db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY')
db_utcnow(),
db_quoteinterval($age . ' DAY')
);
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) {
$file = dbunescbin($rr['content']);
if(is_file($file)) {
@unlink($file);
@rmdir(dirname($file));
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
// (time travel posts). Restrict to items that have come of age in the last
@@ -187,7 +187,7 @@ class Cron {
if($r) {
require_once('include/photo/photo_driver.php');
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'
where xchan_hash = '%s'",
dbesc($photos[0]),
@@ -214,7 +214,7 @@ class Cron {
$restart = true;
$generation = intval($argv[2]);
if(! $generation)
return;
killme();
}
reload_plugins();

View File

@@ -44,11 +44,6 @@ class Cron_daily {
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
require_once('include/statistics_fns.php');

View File

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

View File

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

View File

@@ -285,21 +285,8 @@ class Notifier {
}
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);
return;
}
$target_item = $hookinfo['targetitem'];
logger('notifier: target item not forwardable: type ' . $target_item['item_type'], LOGGER_DEBUG);
return;
}
// Check for non published items, but allow an exclusion for transmitting hidden file activities

View File

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

View File

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

View File

@@ -2,12 +2,10 @@
namespace Zotlabs\Lib;
use Zotlabs\Access\PermissionLimits;
use Zotlabs\Daemon\Master;
use Zotlabs\Web\HTTPSig;
use Zotlabs\Zot6\HTTPSig;
require_once('include/event.php');
require_once('include/html2plain.php');
class Activity {
@@ -42,8 +40,6 @@ class Activity {
if($x['type'] === ACTIVITY_OBJ_PHOTO) {
return self::fetch_image($x);
}
call_hooks('encode_object',$x);
}
return $x;
@@ -67,39 +63,19 @@ class Activity {
}
else {
$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 = [
'Accept' => 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
'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);
$x = z_fetch_url($url, true, $redirects, [ 'headers' => $h ] );
}
if($x['success']) {
$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);
}
else {
@@ -175,6 +151,7 @@ class Activity {
static function fetch_image($x) {
$ret = [
'type' => 'Image',
'id' => $x['id'],
@@ -202,11 +179,6 @@ class Activity {
$ev = bbtoevent($x['content']);
if($ev) {
if (! $ev['timezone']) {
$ev['timezone'] = 'UTC';
}
$actor = null;
if(array_key_exists('author',$x) && array_key_exists('link',$x['author'])) {
$actor = $x['author']['link'][0]['href'];
@@ -214,17 +186,16 @@ class Activity {
$y = [
'type' => 'Event',
'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
'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 ]),
'location' => [ 'type' => 'Place', 'content' => bbcode($ev['location'], [ 'cache' => true ]) ],
'source' => [ 'content' => format_event_bbcode($ev), 'mediaType' => 'text/bbcode' ],
'actor' => $actor,
];
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
@@ -304,14 +275,8 @@ class Activity {
$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'])) {
$ret['type'] = 'Tombstone';
$ret['formerType'] = $objtype;
@@ -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'];
if($i['id'] != $i['parent']) {
@@ -401,13 +351,9 @@ class Activity {
$ret = [];
if ($item['tag'] && is_array($item['tag'])) {
$ptr = $item['tag'];
if (! array_key_exists(0,$ptr)) {
$ptr = [ $ptr ];
}
foreach ($ptr as $t) {
if (! array_key_exists('type',$t))
if($item['tag']) {
foreach($item['tag'] as $t) {
if(! array_key_exists('type',$t))
$t['type'] = 'Hashtag';
switch($t['type']) {
@@ -417,14 +363,14 @@ class Activity {
case 'Mention':
$mention_type = substr($t['name'],0,1);
if ($mention_type === '!') {
if($mention_type === '!') {
$ret[] = [ 'ttype' => TERM_FORUM, 'url' => $t['href'], 'term' => escape_tags(substr($t['name'],1)) ];
}
else {
$ret[] = [ 'ttype' => TERM_MENTION, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'],0,1) === '@') ? substr($t['name'],1) : $t['name']) ];
}
break;
default:
break;
}
@@ -435,7 +381,6 @@ class Activity {
}
static function encode_taxonomy($item) {
$ret = [];
@@ -444,9 +389,9 @@ class Activity {
foreach($item['term'] as $t) {
switch($t['ttype']) {
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']) {
$ret[] = [ 'type' => 'Hashtag', 'href' => $t['url'], 'name' => '#' . $t['term'] ];
$ret[] = [ 'id' => $t['url'], 'name' => '#' . $t['term'] ];
}
break;
@@ -519,12 +464,6 @@ class Activity {
$ret = [];
$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'])) {
$ret['type'] = 'Tombstone';
$ret['formerType'] = self::activity_obj_mapper($i['obj_type']);
@@ -537,41 +476,14 @@ class Activity {
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']);
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']));
@@ -609,15 +521,9 @@ class Activity {
}
if($i['id'] != $i['parent']) {
$ret['inReplyTo'] = ((strpos($i['thr_parent'],'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_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']));
}
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",
intval($i['parent'])
@@ -655,7 +561,7 @@ class Activity {
$i['obj'] = json_decode($i['obj'],true);
}
if($i['obj']['type'] === ACTIVITY_OBJ_PHOTO) {
$i['obj']['id'] = $i['mid'];
$i['obj']['id'] = $i['id'];
}
$obj = self::encode_object($i['obj']);
@@ -746,24 +652,8 @@ class Activity {
}
$ret = [];
$c = ((array_key_exists('channel_id',$p)) ? $p : channelx_by_hash($p['xchan_hash']));
$ret['type'] = 'Person';
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']);
}
$ret['id'] = $p['xchan_url'];
if($p['xchan_addr'] && strpos($p['xchan_addr'],'@'))
$ret['preferredUsername'] = substr($p['xchan_addr'],0,strpos($p['xchan_addr'],'@'));
$ret['name'] = $p['xchan_name'];
@@ -825,7 +715,6 @@ class Activity {
'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept'
];
call_hooks('activity_mapper',$acts);
if(array_key_exists($verb,$acts) && $acts[$verb]) {
return $acts[$verb];
@@ -838,9 +727,6 @@ class Activity {
if(strpos($verb,ACTIVITY_MOOD) !== false)
return 'Create';
if(strpos($verb,ACTIVITY_FRIEND) !== false)
return 'Create';
if(strpos($verb,ACTIVITY_POKE) !== false)
return 'Activity';
@@ -871,7 +757,6 @@ class Activity {
'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept'
];
call_hooks('activity_decode_mapper',$acts);
foreach($acts as $k => $v) {
if($verb === $v) {
@@ -905,8 +790,6 @@ class Activity {
];
call_hooks('activity_obj_decode_mapper',$objs);
foreach($objs as $k => $v) {
if($obj === $v) {
return $k;
@@ -944,8 +827,6 @@ class Activity {
];
call_hooks('activity_obj_mapper',$objs);
if(array_key_exists($obj,$objs)) {
return $objs[$obj];
}
@@ -1535,11 +1416,6 @@ class Activity {
if($act->recips && (! in_array(ACTIVITY_PUBLIC_INBOX,$act->recips)))
$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);
if($parent) {
set_iconfig($s,'activitypub','rawmsg',$act->raw,1);
@@ -1694,7 +1570,7 @@ class Activity {
$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;
}
@@ -1704,12 +1580,11 @@ class Activity {
}
if($act->obj['type'] === 'Event') {
$s['obj'] = [];
$s['obj']['asld'] = $act->obj;
$s['obj']['type'] = ACTIVITY_OBJ_EVENT;
$s['obj']['id'] = $act->obj['id'];
$s['obj']['title'] = $act->obj['name'];
$s['obj']['title'] = $act->obj['summary'];
if(strpos($act->obj['startTime'],'Z'))
$s['obj']['adjust'] = true;
@@ -1873,14 +1748,14 @@ class Activity {
}
foreach($ptr as $vurl) {
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;
}
}
}
elseif(is_string($act->obj['url'])) {
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;
set_iconfig($s,'activitypub','recips',$act->raw_recips);
$parent = (($s['parent_mid'] && $s['parent_mid'] === $s['mid']) ? true : false);
// @FIXME: $parent is not defined
if($parent) {
set_iconfig($s,'activitypub','rawmsg',$act->raw,1);
}
$hookinfo = [
'act' => $act,
's' => $s
];
call_hooks('decode_note',$hookinfo);
$s = $hookinfo['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) {
$s = [];
@@ -2376,21 +1965,25 @@ class Activity {
$x = item_store($s);
}
if(is_array($x) && $x['item_id']) {
if($s['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]);
}
if(is_array($x) && $x['item_id']) {
// @FIXME: $parent is not defined
if($parent) {
if($s['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 function like_note($channel,$observer_hash,$act) {
@@ -2625,12 +2218,7 @@ class Activity {
}
if($event) {
$event['summary'] = $content['name'];
if(! $event['summary']) {
if($content['summary']) {
$event['summary'] = html2plain($content['summary']);
}
}
$event['summary'] = html2bbcode($content['summary']);
$event['description'] = html2bbcode($content['content']);
if($event['summary'] && $event['dtstart']) {
$content['event'] = $event;
@@ -2665,4 +2253,4 @@ class Activity {
}
}
}

View File

@@ -11,10 +11,8 @@ class Cache {
$hash = hash('whirlpool',$key);
$r = q("SELECT v FROM cache WHERE k = '%s' AND updated > %s - INTERVAL %s LIMIT 1",
dbesc($hash),
db_utcnow(),
db_quoteinterval(get_config('system','object_cache_days', '30') . ' DAY')
$r = q("SELECT v FROM cache WHERE k = '%s' limit 1",
dbesc($hash)
);
if ($r)
@@ -42,5 +40,12 @@ class Cache {
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'])
? t('created a new post')
: 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;
@@ -830,14 +825,12 @@ class Enotify {
// convert this logic into a json array just like the system notifications
$who = (($item['verb'] === ACTIVITY_SHARE) ? 'owner' : 'author');
$x = array(
'notify_link' => $item['llink'],
'name' => $item[$who]['xchan_name'],
'addr' => (($item[$who]['xchan_addr']) ? $item[$who]['xchan_addr'] : $item[$who]['xchan_url']),
'url' => $item[$who]['xchan_url'],
'photo' => $item[$who]['xchan_photo_s'],
'name' => $item['author']['xchan_name'],
'addr' => (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url']),
'url' => $item['author']['xchan_url'],
'photo' => $item['author']['xchan_photo_s'],
'when' => relative_date(($edit)? $item['edited'] : $item['created']),
'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'])),
@@ -845,7 +838,7 @@ class Enotify {
'thread_top' => (($item['item_thread_top']) ? true : false),
'message' => strip_tags(bbcode($itemem_text)),
// these are for the superblock addon
'hash' => $item[$who]['xchan_hash'],
'hash' => $item['author']['xchan_hash'],
'uid' => local_channel(),
'display' => true
);

View File

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

View File

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

View File

@@ -2,7 +2,7 @@
namespace Zotlabs\Lib;
use Zotlabs\Web\HTTPSig;
use Zotlabs\Zot6\HTTPSig;
use Zotlabs\Access\Permissions;
use Zotlabs\Access\PermissionLimits;
use Zotlabs\Daemon\Master;
@@ -1223,39 +1223,9 @@ class Libzot {
if($private) {
$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
if($AS->data['hubloc']) {
$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']) {
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
// 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
* Called when an item has been posted on this machine via mod/item.php (also via API).
@@ -1849,10 +1819,6 @@ class Libzot {
$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) {
$AS = new ActivityStreams($activity);
@@ -1911,23 +1877,6 @@ class Libzot {
if($AS->data['hubloc']) {
$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']) {
IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false);
}
@@ -2088,7 +2037,7 @@ class Libzot {
$item_found = false;
$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",
dbesc($sender),
dbesc($sender),
@@ -2098,12 +2047,10 @@ class Libzot {
);
if($r) {
$stored = $r[0];
if($stored['author_xchan'] === $sender || $stored['owner_xchan'] === $sender || $stored['source_xchan'] === $sender)
if($r[0]['author_xchan'] === $sender || $r[0]['owner_xchan'] === $sender || $r[0]['source_xchan'] === $sender)
$ownership_valid = true;
$post_id = $stored['id'];
$post_id = $r[0]['id'];
$item_found = true;
}
else {
@@ -2127,27 +2074,8 @@ class Libzot {
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(intval($stored['item_deleted'])) {
if(intval($r[0]['item_deleted'])) {
logger('delete_imported_item: item was already deleted');
if(! $relay)
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
// 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",
intval($stored['id']),
intval($stored['uid'])
intval($r[0]['id']),
intval($r[0]['uid'])
);
}
}

View File

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

View File

@@ -250,7 +250,7 @@ class Queue {
$host_crypto = null;
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)
);
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();
$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']))))
? t('Private Message')
: false);
@@ -110,7 +110,7 @@ class ThreadItem {
$shareable = true;
$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');
if(! in_array($observer['xchan_url'], $recips['to']))
@@ -778,6 +778,8 @@ class ThreadItem {
call_hooks('comment_buttons',$arr);
$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(
'$return_path' => '',
'$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),
'$anonname' => [ 'anonname', t('Your full name (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;

View File

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

View File

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

View File

@@ -43,12 +43,6 @@ class Security {
$be = $this->trim_array_elems(explode("\n",$_POST['embed_deny']));
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);
set_config('system','transport_security_header',$ts);
@@ -92,7 +86,7 @@ class Security {
$embedhelp2 = t("The recommended setting is to only allow unfiltered HTML from the following sites:");
$embedhelp3 = t("https://youtube.com/<br />https://www.youtube.com/<br />https://youtu.be/<br />https://vimeo.com/<br />https://soundcloud.com/<br />");
$embedhelp4 = t("All other embedded content will be filtered, <strong>unless</strong> embedded content from that site is explicitly blocked.");
$t = get_markup_template('admin_security.tpl');
return replace_macros($t, array(
'$title' => t('Administration'),
@@ -112,9 +106,7 @@ class Security {
'$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_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')),
'$submit' => t('Submit')
@@ -136,4 +128,4 @@ class Security {
}
}
}

View File

@@ -73,6 +73,7 @@ class Site {
$feed_contacts = ((x($_POST,'feed_contacts')) ? intval($_POST['feed_contacts']) : 0);
$verify_email = ((x($_POST,'verify_email')) ? 1 : 0);
$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);
$pub_incl = escape_tags(trim($_POST['pub_incl']));
$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_name' , $from_email_name);
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', 'pubstream_incl',$pub_incl);
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.")),
'$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")),
'$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.")),
'$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)), ''),

View File

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

View File

@@ -85,9 +85,10 @@ class Article_edit extends \Zotlabs\Web\Controller {
$mimetype = $itm[0]['mimetype'];
$summary = (($itm[0]['summary']) ? '[summary]' . $itm[0]['summary'] . '[/summary]' . "\r\n" : '');
$content = $itm[0]['body'];
$rp = 'articles/' . $channel['channel_address'];
$x = array(
@@ -109,7 +110,7 @@ class Article_edit extends \Zotlabs\Web\Controller {
'ptyp' => $itm[0]['type'],
'mimeselect' => false,
'mimetype' => $itm[0]['mimetype'],
'body' => $summary . undo_post_tagging($content),
'body' => undo_post_tagging($content),
'post_id' => $post_id,
'visitor' => true,
'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/conversation.php');
require_once('include/acl_selectors.php');
require_once('include/opengraph.php');
class Articles extends Controller {
@@ -193,7 +192,7 @@ class Articles extends Controller {
$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
WHERE item.uid = %d $item_normal
AND item.parent IN ( %s )
@@ -201,18 +200,15 @@ class Articles extends Controller {
intval(App::$profile['profile_uid']),
dbesc($parents_str)
);
if($r) {
xchan_query($r);
$items = fetch_post_tags($r, true);
if($items) {
xchan_query($items);
$items = fetch_post_tags($items, true);
$items = conv_sort($items,'updated');
}
else
$items = [];
}
// Add Opengraph markup
opengraph_add_meta((! empty($items) ? $r[0] : []), $channel);
$mode = 'articles';
if(get_pconfig(local_channel(),'system','articles_list_mode') && (! $selected_card))

View File

@@ -1,10 +1,6 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
require_once('include/conversation.php');
require_once('include/bbcode.php');
require_once('include/datetime.php');
@@ -13,13 +9,15 @@ require_once('include/items.php');
require_once('include/html2plain.php');
class Cal extends Controller {
class Cal extends \Zotlabs\Web\Controller {
function init() {
if(observer_prohibited()) {
return;
}
$o = '';
if(argc() > 1) {
$nick = argv(1);
@@ -27,21 +25,19 @@ class Cal extends Controller {
$channelx = channelx_by_nick($nick);
if(! $channelx) {
notice( t('Channel not found.') . EOL);
if(! $channelx)
return;
}
App::$data['channel'] = $channelx;
\App::$data['channel'] = $channelx;
$observer = App::get_observer();
App::$data['observer'] = $observer;
$observer = \App::get_observer();
\App::$data['observer'] = $observer;
$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,8 +52,18 @@ class Cal extends Controller {
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
if(! perm_is_allowed($channel['channel_id'], get_observer_hash(), 'view_stream')) {
@@ -66,152 +72,295 @@ class Cal extends Controller {
}
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');
if(! perm_is_allowed($channel['channel_id'], get_observer_hash(), 'view_contacts') || App::$profile['hide_friends'])
$sql_extra .= " and etype != 'birthday' ";
$first_day = feature_enabled($channel['channel_id'], 'cal_first_day');
$sql_extra = permissions_sql($channel['channel_id'],get_observer_hash(),'event');
$first_day = feature_enabled($channel['channel_id'], 'events_cal_first_day');
$first_day = (($first_day) ? $first_day : 0);
$start = '';
$finish = '';
if (argv(2) === 'json') {
if (x($_GET,'start')) $start = $_GET['start'];
if (x($_GET,'end')) $finish = $_GET['end'];
}
$start = datetime_convert('UTC','UTC',$start);
$finish = datetime_convert('UTC','UTC',$finish);
$adjust_start = datetime_convert('UTC', date_default_timezone_get(), $start);
$adjust_finish = datetime_convert('UTC', date_default_timezone_get(), $finish);
if (x($_GET, '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
where item.resource_type = 'event' and event.uid = %d and event.id = %d $sql_extra limit 1",
intval($channel['channel_id']),
intval($_GET['id'])
);
}
else {
// fixed an issue with "nofinish" events not showing up in the calendar.
// 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.
// 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
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
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' ))
$sql_extra",
intval($channel['channel_id']),
dbesc($start),
dbesc($finish),
dbesc($adjust_start),
dbesc($adjust_finish)
);
}
if($r) {
xchan_query($r);
$r = fetch_post_tags($r,true);
$r = sort_by_date($r);
}
$events = [];
if($r) {
foreach($r as $rr) {
$tz = get_iconfig($rr, 'event', 'timezone');
if(! $tz)
$tz = 'UTC';
$start = (($rr['adjust']) ? datetime_convert($tz, date_default_timezone_get(), $rr['dtstart'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtstart'], 'c'));
if ($rr['nofinish']){
$end = null;
} else {
$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);
}
$events[] = array(
'calendar_id' => 'channel_calendar',
'rw' => true,
'id'=>$rr['id'],
'uri' => $rr['event_hash'],
'timezone' => $tz,
'start'=> $start,
'end' => $end,
'drop' => $drop,
'allDay' => (($rr['adjust']) ? 0 : 1),
'title' => html_entity_decode($rr['summary'], ENT_COMPAT, 'UTF-8'),
'editable' => $edit ? true : false,
'item' => $rr,
'plink' => [$rr['plink'], t('Link to source')],
'description' => html_entity_decode($rr['description'], ENT_COMPAT, 'UTF-8'),
'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') {
echo json_encode($events);
killme();
}
if (x($_GET,'id')) {
$o = replace_macros(get_markup_template("cal_event.tpl"), [
'$events' => $events
]);
echo $o;
killme();
}
$nick = $channel['channel_address'];
$sources = '{
id: \'channel_calendar\',
url: \'/cal/' . $nick . '/json/\',
color: \'#3a87ad\'
}';
$o = replace_macros(get_markup_template("cal_calendar.tpl"), [
'$sources' => $sources,
'$lang' => App::$language,
$htpl = get_markup_template('event_head.tpl');
\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,
'$prev' => t('Previous'),
'$next' => t('Next'),
'$today' => t('Today'),
'$title' => $title,
'$dtstart' => $dtstart,
'$dtend' => $dtend,
'$nick' => $nick
]);
'$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 (x($_GET,'start')) $start = $_GET['start'];
if (x($_GET,'end')) $finish = $_GET['end'];
}
$start = datetime_convert('UTC','UTC',$start);
$finish = datetime_convert('UTC','UTC',$finish);
$adjust_start = datetime_convert('UTC', date_default_timezone_get(), $start);
$adjust_finish = datetime_convert('UTC', date_default_timezone_get(), $finish);
return $o;
if(! perm_is_allowed(\App::$profile['uid'],get_observer_hash(),'view_contacts'))
$sql_extra .= " and etype != 'birthday' ";
if (x($_GET,'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 resource_id = event_hash where resource_type = 'event' and event.uid = %d and event.id = %d $sql_extra limit 1",
intval($channel['channel_id']),
intval($_GET['id'])
);
}
else {
// fixed an issue with "nofinish" events not showing up in the calendar.
// 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.
// 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
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 $ignored
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' )) ",
intval(local_channel()),
dbesc($start),
dbesc($finish),
dbesc($adjust_start),
dbesc($adjust_finish)
);
}
$links = array();
if($r) {
xchan_query($r);
$r = fetch_post_tags($r,true);
$r = sort_by_date($r);
}
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) {
foreach($r as $rr) {
$tz = get_iconfig($rr, 'event', 'timezone');
if(! $tz)
$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'));
if ($rr['nofinish']){
$end = null;
} else {
$end = (($rr['adjust']) ? datetime_convert($tz,date_default_timezone_get(),$rr['dtend'], 'c') : datetime_convert('UTC','UTC',$rr['dtend'],'c'));
}
$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(
'id'=>$rr['id'],
'hash' => $rr['event_hash'],
'start'=> $start,
'end' => $end,
'drop' => $drop,
'allDay' => (($rr['adjust']) ? 0 : 1),
'title' => $title,
'j' => $j,
'd' => $d,
'edit' => $edit,
'is_first'=>$is_first,
'item'=>$rr,
'html'=>$html,
'plink' => array($rr['plink'],t('Link to Source'),'',''),
);
}
}
if (argv(2) === 'json'){
echo json_encode($events); killme();
}
// links: array('href', 'text', 'extra css classes', 'title')
if (x($_GET,'id')){
$tpl = get_markup_template("event_cal.tpl");
}
else {
$tpl = get_markup_template("events_cal-js.tpl");
}
$nick = $channel['channel_address'];
$o = replace_macros($tpl, array(
'$baseurl' => z_root(),
'$new_event' => array(z_root().'/cal',(($event_id) ? t('Edit Event') : t('Create Event')),'',''),
'$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'),'',''),
'$calendar' => cal($y,$m,$links, ' eventcal'),
'$events' => $events,
'$upload' => t('Import'),
'$submit' => t('Submit'),
'$prev' => t('Previous'),
'$next' => t('Next'),
'$today' => t('Today'),
'$form' => $form,
'$expandform' => ((x($_GET,'expandform')) ? true : false)
));
if (x($_GET,'id')){ echo $o; killme(); }
return $o;
}
}

View File

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

View File

@@ -6,14 +6,13 @@ namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\PermissionDescription;
use Zotlabs\Web\HTTPSig;
use Zotlabs\Zot6\HTTPSig;
use Zotlabs\Lib\Libzot;
require_once('include/items.php');
require_once('include/security.php');
require_once('include/conversation.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
// we start loading content
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) {
@@ -364,7 +351,7 @@ class Channel extends Controller {
$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
WHERE item.uid = %d $item_normal
AND item.parent IN ( %s )
@@ -373,8 +360,8 @@ class Channel extends Controller {
dbesc($parents_str)
);
xchan_query($r);
$items = fetch_post_tags($r, true);
xchan_query($items);
$items = fetch_post_tags($items, true);
$items = conv_sort($items,$ordering);
if($load && $mid && (! count($items))) {

View File

@@ -21,7 +21,7 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
$event_hash = ((x($_POST,'event_hash')) ? $_POST['event_hash'] : '');
$xchan = ((x($_POST,'xchan')) ? dbesc($_POST['xchan']) : '');
$uid = local_channel();
$uid = local_channel();
// only allow editing your own events.
if(($xchan) && ($xchan !== get_observer_hash()))
@@ -34,8 +34,8 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
$adjust = intval($_POST['adjust']);
$start = datetime_convert('UTC', 'UTC', escape_tags($_REQUEST['dtstart']));
$finish = datetime_convert('UTC', 'UTC', escape_tags($_REQUEST['dtend']));
$start = (($adjust) ? datetime_convert($tz, 'UTC', escape_tags($_REQUEST['dtstart'])) : datetime_convert('UTC', 'UTC', escape_tags($_REQUEST['dtstart'])));
$finish = (($adjust) ? datetime_convert($tz, 'UTC', escape_tags($_REQUEST['dtend'])) : datetime_convert('UTC', 'UTC', escape_tags($_REQUEST['dtend'])));
$summary = escape_tags(trim($_POST['summary']));
$desc = escape_tags(trim($_POST['desc']));
@@ -381,12 +381,12 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
'end' => $end,
'drop' => $drop,
'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,
'item' => $rr,
'plink' => [$rr['plink'], t('Link to source')],
'description' => html_entity_decode($rr['description'], ENT_COMPAT, 'UTF-8'),
'location' => html_entity_decode($rr['location'], ENT_COMPAT, 'UTF-8'),
'description' => htmlentities($rr['description'], ENT_COMPAT, 'UTF-8', false),
'location' => htmlentities($rr['location'], ENT_COMPAT, 'UTF-8', false),
'allow_cid' => expand_acl($rr['allow_cid']),
'allow_gid' => expand_acl($rr['allow_gid']),
'deny_cid' => expand_acl($rr['deny_cid']),
@@ -402,7 +402,7 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
echo ical_wrapper($r);
killme();
}
if (\App::$argv[1] === 'json'){
json_return_and_die($events);
}
@@ -422,67 +422,13 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
dbesc($event_id),
intval(local_channel())
);
if($r) {
$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",
$r = q("update item set resource_type = '', resource_id = '' where resource_type = 'event' and resource_id = '%s' and uid = %d",
dbesc($event_id),
intval(local_channel())
);
if ($i) {
$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']);
}
}
}
$sync_event['event_deleted'] = 1;
build_sync_packet(0,array('event' => array($sync_event)));
killme();
}
notice( t('Failed to remove event' ) . EOL);

View File

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

View File

@@ -322,10 +322,7 @@ class Connections extends \Zotlabs\Web\Controller {
'ignore' => ((! $rr['abook_ignored']) ? t('Ignore') : false),
'recent_label' => t('Recent activity'),
'recentlink' => z_root() . '/network/?f=&cid=' . intval($rr['abook_id']) . '&name=' . $rr['xchan_name'],
'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')
'oneway' => $oneway
);
}
}

View File

@@ -8,9 +8,8 @@
namespace Zotlabs\Module;
use Sabre\DAV as SDAV;
use Zotlabs\Storage;
use Zotlabs\Web\HTTPSig;
use \Sabre\DAV as SDAV;
use \Zotlabs\Storage;
require_once('include/attach.php');
require_once('include/auth.php');
@@ -47,7 +46,7 @@ class Dav extends \Zotlabs\Web\Controller {
continue;
}
$sigblock = HTTPSig::parse_sigheader($_SERVER[$head]);
$sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]);
if($sigblock) {
$keyId = str_replace('acct:','',$sigblock['keyId']);
if($keyId) {
@@ -70,7 +69,7 @@ class Dav extends \Zotlabs\Web\Controller {
continue;
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'])) {
$record = null;
}
@@ -95,8 +94,6 @@ class Dav extends \Zotlabs\Web\Controller {
$auth = new \Zotlabs\Storage\BasicAuth();
$auth->observer = get_observer_hash();
$auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . ' ' . 'WebDAV');
$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);
$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'] : '');
@@ -345,7 +345,7 @@ class Directory extends \Zotlabs\Web\Controller {
'pdesc_label' => t('Description:'),
'marital' => $marital,
'homepage' => $homepage,
'homepageurl' => linkify($homepageurl, true),
'homepageurl' => linkify($homepageurl),
'hometown' => $hometown,
'hometown_label' => t('Hometown:'),
'about' => $about,

View File

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

View File

@@ -11,9 +11,6 @@ require_once('include/html2plain.php');
class Events extends \Zotlabs\Web\Controller {
function post() {
// this module is deprecated
return;
logger('post: ' . print_r($_REQUEST,true), LOGGER_DATA);
@@ -248,9 +245,6 @@ class Events extends \Zotlabs\Web\Controller {
function get() {
// this module is deprecated
return;
if(argc() > 2 && argv(1) == 'ical') {
$event_id = argv(2);
@@ -668,10 +662,9 @@ class Events extends \Zotlabs\Web\Controller {
'html'=>$html,
'plink' => array($rr['plink'],t('Link to Source'),'',''),
);
}
}
if($export) {
header('Content-type: text/calendar');
header('content-disposition: attachment; filename="' . t('calendar') . '-' . $channel['channel_address'] . '.ics"' );

View File

@@ -1,8 +1,6 @@
<?php
namespace Zotlabs\Module;
use Zotlabs\Web\HTTPSig;
/**
* module: getfile
*
@@ -48,7 +46,7 @@ class Getfile extends \Zotlabs\Web\Controller {
continue;
}
$sigblock = HTTPSig::parse_sigheader($_SERVER[$head]);
$sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]);
if($sigblock) {
$keyId = $sigblock['keyId'];
@@ -59,7 +57,7 @@ class Getfile extends \Zotlabs\Web\Controller {
);
if($r) {
$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']) {
$header_verified = true;
}

View File

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

View File

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

View File

@@ -9,7 +9,7 @@ use Zotlabs\Daemon\Master;
use Zotlabs\Lib\Activity;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\LDSignatures;
use Zotlabs\Web\HTTPSig;
use Zotlabs\Zot6\HTTPSig;
use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\ThreadListener;
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
// with a bias towards those items owned by channels on this site (item_wall = 1)
$sql_extra = item_permissions_sql(0);
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'])
);
}
@@ -193,25 +192,6 @@ class Item extends Controller {
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');
}
}
@@ -570,10 +550,10 @@ class Item extends Controller {
$public_policy = $orig_post['public_policy'];
$private = $orig_post['item_private'];
}
if($public_policy || $acl->is_private()) {
$private = (($private) ? $private : 1);
}
if($private || $public_policy || $acl->is_private())
$private = 1;
$location = $orig_post['location'];
$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);
$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($parent_item) {
$private = 0;
$acl->set($parent_item);
$private = intval($acl->is_private() || $parent_item['item_private']);
$public_policy = $parent_item['public_policy'];
@@ -760,12 +741,7 @@ 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']
);
}
$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);
$i++;
}
@@ -1227,7 +1208,13 @@ class Item extends Controller {
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",
intval($post_id)
);

View File

@@ -2,6 +2,9 @@
namespace Zotlabs\Module;
class Linkinfo extends \Zotlabs\Web\Controller {
function get() {
@@ -45,22 +48,7 @@ class Linkinfo extends \Zotlabs\Web\Controller {
}
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));
if($result['success']) {
$hdrs=array();
@@ -287,7 +275,7 @@ class Linkinfo extends \Zotlabs\Web\Controller {
// 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] : '');
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, 'HTML-ENTITIES', "UTF-8");
@@ -456,9 +444,8 @@ class Linkinfo extends \Zotlabs\Web\Controller {
while (strpos($text, " "))
$text = trim(str_replace(" ", " ", $text));
$text = substr(html_entity_decode($text, ENT_QUOTES, "UTF-8"), 0, 350);
$siteinfo["text"] = rtrim(substr($text, 0, strrpos($text, " ")), "?.,:;!-") . '...';
$siteinfo["text"] = html_entity_decode(substr($text,0,350), ENT_QUOTES, "UTF-8").'...';
}
}

View File

@@ -76,7 +76,7 @@ class Lockview extends \Zotlabs\Web\Controller {
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']))) {
// 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
namespace Zotlabs\Module;
use Zotlabs\Web\HTTPSig;
@require_once('include/zot.php');
@@ -154,9 +152,10 @@ class Magic extends \Zotlabs\Web\Controller {
$headers['Accept'] = 'application/x-zot+json' ;
$headers['X-Open-Web-Auth'] = random_string();
$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 ]);
if($x['success']) {

View File

@@ -25,10 +25,6 @@ class Mail extends \Zotlabs\Web\Controller {
$expires = ((x($_REQUEST,'expires')) ? datetime_convert(date_default_timezone_get(),'UTC', $_REQUEST['expires']) : NULL_DATE);
$raw = ((x($_REQUEST,'raw')) ? intval($_REQUEST['raw']) : 0);
$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) {
@@ -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
$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']) {
xchan_mail_query($ret['mail']);
@@ -400,9 +396,8 @@ class Mail extends \Zotlabs\Web\Controller {
'can_recall' => ($channel['channel_hash'] == $message['from_xchan']),
'is_recalled' => (intval($message['mail_recalled']) ? t('Message has been recalled.') : ''),
'date' => datetime_convert('UTC',date_default_timezone_get(),$message['created'], 'c'),
'sig' => base64_encode($message['sig'])
);
$seen = $message['seen'];
}

View File

@@ -54,10 +54,9 @@ class Menu extends \Zotlabs\Web\Controller {
if($_REQUEST['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) {
$_REQUEST['menu_id'] = $menu_id;
$_REQUEST['menu_id'] = intval(argv(1));
$r = menu_edit($_REQUEST);
if($r) {
menu_sync_packet($uid,get_observer_hash(),$menu_id);

View File

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

View File

@@ -31,7 +31,12 @@ class Photo extends \Zotlabs\Web\Controller {
// 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);
$observer_xchan = get_observer_hash();
@@ -139,7 +144,7 @@ class Photo extends \Zotlabs\Web\Controller {
$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),
intval($resolution)
);
@@ -158,10 +163,13 @@ class Photo extends \Zotlabs\Web\Controller {
if($u === PHOTO_CACHE) {
// Validate cache
if($cache_mode['on']) {
$cache = [ 'status' => false, 'item' => $r[0] ];
$cache = array(
'resid' => $photo,
'status' => false
);
call_hooks('cache_url_hook', $cache);
if(! $cache['status']) {
$url = html_entity_decode($cache['item']['display_path'], ENT_QUOTES);
$url = htmlspecialchars_decode($r[0]['display_path']);
// SSLify if needed
if(strpos(z_root(),'https:') !== false && strpos($url,'https:') === false)
$url = z_root() . '/sslify/' . $filename . '?f=&url=' . urlencode($url);
@@ -214,14 +222,14 @@ class Photo extends \Zotlabs\Web\Controller {
if(! $data)
killme();
$etag = '"' . md5($data . $modified) . '"';
$etag = md5($data . $modified);
if($modified == 0)
$modified = time();
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('Cache-Control');
header_remove('Set-Cookie');
@@ -264,12 +272,7 @@ class Photo extends \Zotlabs\Web\Controller {
$maxage = $expires - time();
header("Expires: " . gmdate("D, d M Y H:i:s", $expires) . " GMT");
// 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);
header("Cache-Control: max-age=" . $maxage . $cachecontrol);
}

View File

@@ -1080,6 +1080,7 @@ class Photos extends \Zotlabs\Web\Controller {
$comments = '';
if(! $r) {
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(
'$return_path' => '',
'$mode' => 'photos',
@@ -1095,7 +1096,8 @@ class Photos extends \Zotlabs\Web\Controller {
'$submit' => t('Submit'),
'$preview' => t('Preview'),
'$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)
$message = substr($message, strlen($tt['xname']) + 1);
$mid = basename($tt['link']);
$mid = ((strpos($mid, 'b64.') === 0) ? @base64url_decode(substr($mid, 4)) : $mid);
if(in_array($tt['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) {
// we need the thread parent
@@ -291,6 +291,7 @@ class Ping extends \Zotlabs\Web\Controller {
dbesc($mid),
intval(local_channel())
);
$b64mid = ((strpos($r[0]['thr_parent'], 'b64.') === 0) ? $r[0]['thr_parent'] : 'b64.' . base64url_encode($r[0]['thr_parent']));
}
else {

View File

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

View File

@@ -86,7 +86,7 @@ class Wall_attach extends \Zotlabs\Web\Controller {
$def_attach = get_pconfig($channel['channel_id'],'system','attach_path');
$r = attach_store($channel,(($observer) ? $observer['xchan_hash'] : ''),'', array('source' => 'editor', 'visible' => 0, 'album' => $def_album, 'directory' => $def_attach, 'allow_cid' => '<' . $channel['channel_hash'] . '>'));
if(! $r['success']) {
notice( $r['message'] . EOL);
killme();
@@ -111,24 +111,9 @@ class Wall_attach extends \Zotlabs\Web\Controller {
}
if(strpos($r['data']['filetype'],'audio') === 0) {
$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";
}

View File

@@ -63,18 +63,6 @@ class Well_known extends \Zotlabs\Web\Controller {
case 'dnt-policy.txt':
echo file_get_contents('doc/dnt-policy.txt');
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:
if(file_exists(\App::$cmd)) {

View File

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

View File

@@ -3,7 +3,7 @@
namespace Zotlabs\Module;
use Zotlabs\Lib\Zotfinger;
use Zotlabs\Web\HTTPSig;
use Zotlabs\Zot6\HTTPSig;
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);
$result['project'] = 'Hubzilla';
$result['messages'] = zot_feed($r[0]['channel_id'],$observer['xchan_hash'],array('mindate' => $mindate));
$result['success'] = true;
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 scale int
* @return boolean
* @return boolean|array
*/
public function storeThumbnail($arr, $scale = 0) {
// We only process thumbnails here
if($scale == 0)
return false;
$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']);
$arr['os_storage'] = 1;
$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[]
*/
function ChannelList(&$auth) {
$ret = [];
if (intval(get_config('system','cloud_disable_siteroot'))) {
return $ret;
}
$ret = array();
$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)
@@ -734,7 +730,8 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
foreach ($r as $rr) {
if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage') && $rr['publish']) {
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;
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 {
/**
@@ -21,32 +15,41 @@ class HTTPSig {
* @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
* @param boolean $set (optional, default true)
* 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') {
$digest = base64_encode(hash($alg, $body, true));
switch($alg) {
case 'sha512':
return 'SHA-512=' . $digest;
case 'sha256':
default:
return 'SHA-256=' . $digest;
break;
if($set) {
header('Digest: SHA-256=' . $digest);
}
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
if(is_array($data) && $data['header']) {
if(! $data['success'])
return [];
return $result;
$h = new HTTPHeaders($data['header']);
$h = new \Zotlabs\Web\HTTPHeaders($data['header']);
$headers = $h->fetcharr();
$body = $data['body'];
$headers['(request-target)'] = $data['request_target'];
@@ -54,7 +57,9 @@ class HTTPSig {
else {
$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-length'] = $_SERVER['CONTENT_LENGTH'];
@@ -66,35 +71,9 @@ class HTTPSig {
}
}
//logger('SERVER: ' . print_r($_SERVER,true), LOGGER_ALL);
// 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;
// logger('headers: ' . print_r($headers,true), LOGGER_ALL);
$sig_block = null;
@@ -106,7 +85,7 @@ class HTTPSig {
}
if(! $sig_block) {
logger('no signature provided.', LOGGER_DEBUG);
logger('no signature provided.');
return $result;
}
@@ -124,6 +103,9 @@ class HTTPSig {
if(array_key_exists($h,$headers)) {
$signed_data .= $h . ': ' . $headers[$h] . "\n";
}
if(strpos($h,'.')) {
$spoofable = true;
}
if($h === 'date') {
$d = new \DateTime($headers[$h]);
$d->setTimeZone(new \DateTimeZone('UTC'));
@@ -146,89 +128,63 @@ class HTTPSig {
$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;
if($key && function_exists($key)) {
$result['signer'] = $sig_block['keyId'];
$key = $key($sig_block['keyId']);
}
$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);
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));
if(! $x)
return $result;
}
$result['portable_id'] = $key['portable_id'];
$result['header_valid'] = true;
if(! $spoofable)
$result['header_valid'] = true;
if(in_array('digest',$signed_headers)) {
$result['content_signed'] = true;
$digest = explode('=', $headers['digest'], 2);
$digest = explode('=', $headers['digest']);
if($digest[0] === 'SHA-256')
$hashalg = 'sha256';
if($digest[0] === 'SHA-512')
$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;
}
logger('Content_Valid: ' . (($result['content_valid']) ? 'true' : 'false'));
}
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'));
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
*
@@ -236,131 +192,57 @@ class HTTPSig {
* @return boolean|string
* false if no pub key found, otherwise return the pub key
*/
function get_activitypub_key($id) {
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] ];
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",
dbesc(str_replace('acct:','',$id))
);
}
else {
$x = q("select xchan_pubkey from xchan where xchan_hash = '%s' and xchan_network = 'activitypub' ",
dbesc($id)
);
}
$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(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' => [] ];
}
$j = json_decode($r,true);
if(array_key_exists('publicKey',$j) && array_key_exists('publicKeyPem',$j['publicKey'])) {
if((array_key_exists('id',$j['publicKey']) && $j['publicKey']['id'] !== $id) && $j['id'] !== $id)
return false;
return($j['publicKey']['publicKeyPem']);
}
}
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 string $request
* @param array $head
* @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 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
*/
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 = [];
@@ -371,15 +253,14 @@ class HTTPSig {
$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) {
$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($crypt_key) {
$x = crypto_encapsulate($headerval,$crypt_key,$crypt_algo);
$headerval = 'iv="' . $x['iv'] . '",key="' . $x['key'] . '",alg="' . $x['alg'] . '",data="' . $x['data'] . '"';
}
if($auth) {
@@ -391,52 +272,43 @@ class HTTPSig {
if($head) {
foreach($head as $k => $v) {
// strip the request-target virtual header from the output headers
if($k === '(request-target)') {
continue;
if($send_headers) {
header($k . ': ' . $v);
}
else {
$return_headers[] = $k . ': ' . $v;
}
$return_headers[] = $k . ': ' . $v;
}
}
$return_headers[] = $sighead;
if($send_headers) {
header($sighead);
}
else {
$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 string $request
* @param array $head
* @param string $prvkey
* @param string $alg (optional) default 'sha256'
* @return array
*/
static function sign($head, $prvkey, $alg = 'sha256') {
static function sign($request, $head, $prvkey, $alg = 'sha256') {
$ret = [];
$headers = '';
$fields = '';
logger('signing: ' . print_r($head,true), LOGGER_DATA);
if($request) {
$headers = '(request-target)' . ': ' . trim($request) . "\n";
$fields = '(request-target)';
}
if($head) {
foreach($head as $k => $v) {
@@ -468,9 +340,12 @@ class HTTPSig {
* - \e array \b headers
* - \e string \b signature
*/
static function parse_sigheader($header) {
if(is_array($header)) {
btlogger('is_array: ' . print_r($header,true));
}
$ret = [];
$matches = [];
@@ -506,7 +381,6 @@ class HTTPSig {
* - \e string \b alg
* - \e string \b data
*/
static function decrypt_sigheader($header, $prvkey = null) {
$iv = $key = $alg = $data = null;

View File

@@ -56,7 +56,7 @@ class Router {
$routes = Route::get();
if($routes) {
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]);
if(class_exists($modname)) {
$this->controller = new $modname;

View File

@@ -38,15 +38,10 @@ class SessionHandler implements \SessionHandlerInterface {
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) {
return true;
return false;
}
// Unless we authenticate somehow, only keep a session for 5 minutes
// The viewer can extend this by performing any web action using the
// original cookie, but this allows us to cleanup the hundreds or

View File

@@ -2,8 +2,6 @@
namespace Zotlabs\Zot;
use Zotlabs\Web\HTTPSig;
/**
* @brief Finger
*
@@ -97,7 +95,8 @@ class Finger {
$headers['X-Zot-Nonce'] = random_string();
$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;
@@ -130,7 +129,7 @@ class Finger {
$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'])) {
$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['X-Zot-Channel'] = $channel['channel_address'] . '@' . \App::get_hostname();
$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;
@@ -121,7 +122,7 @@ class Finger {
$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'])) {
$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\Libzot;
use Zotlabs\Web\HTTPSig;
class Receiver {
@@ -194,9 +193,7 @@ class Receiver {
case 'response': // upstream message
case 'sync':
default:
if ($this->sender) {
$this->response = $this->handler->Notify($this->data,$this->hub);
}
$this->response = $this->handler->Notify($this->data,$this->hub);
break;
}

View File

@@ -50,7 +50,7 @@ require_once('include/attach.php');
require_once('include/bbcode.php');
define ( 'PLATFORM_NAME', 'hubzilla' );
define ( 'STD_VERSION', '4.6' );
define ( 'STD_VERSION', '4.2' );
define ( 'ZOT_REVISION', '6.0a' );
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.
define ( 'DIRECTORY_REALM', 'RED_GLOBAL');
define ( 'DIRECTORY_FALLBACK_MASTER', 'https://hub.netzgemeinde.eu');
define ( 'DIRECTORY_FALLBACK_MASTER', 'https://zotadel.net');
$DIRECTORY_FALLBACK_SERVERS = array(
'https://hub.netzgemeinde.eu',
'https://zotadel.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 ( 'ZOT_APSCHEMA_REV', '/apschema/v1.8' );
define ( 'ZOT_APSCHEMA_REV', '/apschema/v1.5' );
/**
* activity stream defines
*/
@@ -896,49 +896,6 @@ class App {
if(x($_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"
if((substr(self::$cmd, 0, 1) === '~') || (substr(self::$cmd, 0, 1) === '@'))
@@ -1205,8 +1162,7 @@ class App {
'$linkrel' => head_get_links(),
'$js_strings' => js_strings(),
'$zid' => get_my_address(),
'$channel_id' => self::$profile['uid'],
'$auto_save_draft' => ((feature_enabled(self::$profile['uid'], 'auto_save_draft')) ? "true" : "false")
'$channel_id' => self::$profile['uid']
]
) . self::$page['htmlhead'];

View File

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

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