From 113d3090e7a4cbaaf57c8419431c2e0efe461807 Mon Sep 17 00:00:00 2001 From: pezcurrel Date: Thu, 26 Dec 2019 21:57:36 +0100 Subject: [PATCH] 26 dicembre 2019 --- mastblocksdump/mastblocksmerge.wip.sh | 237 +++++++ mastblocksdump/php/domblocks.php | 38 + web/admin/crawler/.htaccess | 2 + web/admin/crawler/blacklist_bida.txt | 36 - web/admin/crawler/blacklist_cagi.txt | 157 ----- web/admin/crawler/crawler.php | 862 ++++++++++------------- web/admin/crawler/crawler_pant.ini | 9 - web/admin/crawler/crawler_sorellanza.ini | 9 - web/admin/crawler/istanzesorelle | 5 - web/admin/crawler/istanzesorelle_pant | 1 - web/admin/favicon.ico | Bin 0 -> 9662 bytes web/admin/imgs/icona-180.png | Bin 0 -> 4129 bytes web/admin/imgs/icona-192.png | Bin 0 -> 4342 bytes web/admin/imgs/icona-32.png | Bin 0 -> 962 bytes web/admin/imgs/icona-512.png | Bin 0 -> 13302 bytes web/admin/include/connuser.php | 10 + web/admin/include/glob.php | 10 + web/admin/include/menu.php | 52 ++ web/admin/include/muoribene.php | 31 + web/admin/include/myconn.php | 9 + web/admin/include/sessionstart.php | 12 + web/admin/index.php | 59 ++ web/admin/instances.php | 90 +++ web/admin/js/alerta.js | 4 + web/admin/login.php | 36 + web/admin/sec/.htaccess | 2 + web/admin/sec/mastostartadmin.ini | 6 + web/admin/theme.css | 213 ++++++ web/favicon.ico | Bin 9086 -> 9662 bytes web/imgs/ClosedPadlock.png | Bin 2630 -> 2550 bytes web/imgs/Earth.png | Bin 3587 -> 3529 bytes web/imgs/OpenPadlock.png | Bin 2706 -> 2612 bytes web/imgs/TrendingHashtags.png | Bin 17377 -> 11432 bytes web/imgs/icona-180.png | Bin 0 -> 4147 bytes web/imgs/icona-192.png | Bin 0 -> 4350 bytes web/imgs/icona-32.png | Bin 0 -> 1005 bytes web/imgs/icona-512.png | Bin 0 -> 13433 bytes web/index.php | 20 +- web/theme.css | 10 +- 39 files changed, 1193 insertions(+), 727 deletions(-) create mode 100755 mastblocksdump/mastblocksmerge.wip.sh create mode 100644 mastblocksdump/php/domblocks.php create mode 100644 web/admin/crawler/.htaccess delete mode 100644 web/admin/crawler/blacklist_bida.txt delete mode 100644 web/admin/crawler/blacklist_cagi.txt delete mode 100644 web/admin/crawler/crawler_pant.ini delete mode 100644 web/admin/crawler/crawler_sorellanza.ini delete mode 100644 web/admin/crawler/istanzesorelle delete mode 100644 web/admin/crawler/istanzesorelle_pant create mode 100644 web/admin/favicon.ico create mode 100644 web/admin/imgs/icona-180.png create mode 100644 web/admin/imgs/icona-192.png create mode 100644 web/admin/imgs/icona-32.png create mode 100644 web/admin/imgs/icona-512.png create mode 100644 web/admin/include/connuser.php create mode 100644 web/admin/include/glob.php create mode 100644 web/admin/include/menu.php create mode 100644 web/admin/include/muoribene.php create mode 100644 web/admin/include/myconn.php create mode 100644 web/admin/include/sessionstart.php create mode 100644 web/admin/index.php create mode 100644 web/admin/instances.php create mode 100644 web/admin/js/alerta.js create mode 100644 web/admin/login.php create mode 100644 web/admin/sec/.htaccess create mode 100644 web/admin/sec/mastostartadmin.ini create mode 100644 web/admin/theme.css create mode 100644 web/imgs/icona-180.png create mode 100644 web/imgs/icona-192.png create mode 100644 web/imgs/icona-32.png create mode 100644 web/imgs/icona-512.png diff --git a/mastblocksdump/mastblocksmerge.wip.sh b/mastblocksdump/mastblocksmerge.wip.sh new file mode 100755 index 0000000..f1bbbac --- /dev/null +++ b/mastblocksdump/mastblocksmerge.wip.sh @@ -0,0 +1,237 @@ +#!/bin/bash + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +MASTHOME='/var/lib/mastodon' +MASTENVFP="$MASTHOME/live/.env.production" +SISTERSFP="istanzesorelle" +LOCAL=0 +INTERACTIVE=0 + +HELP="SINTASSI + mastblocksmerge.sh [opzioni] +DESCRIZIONE + Questo script integra i dati di una o più blocklist esterne nella + tabella domain_blocks di mastodon. + Legge i domini delle istanze di cui recuperare la blocklist da un file + di inizializzazione, per default \"$SISTERSP\" (formato del file: + un dominio per riga), prova a recuperare ciascuna blocklist da + https://[dominio]/domain_blocks.txt, costruisce dalle liste recuperate + un\'unica lista senza duplicati, si collega al db di mastodon e scrive + nella tabella domain_blocks i dati relativi alle istanze bloccate che + non sono già presenti nella tabella stessa. + Per la connessione al db di mastodon legge i dati necessari dal file + di configurazione di mastodon, per default + \"$MASTENVFP\" + È pensato per essere eseguito periodicamente da un cron job, come + utente mastodon oppure root oppure altro utente che abbia accesso in + lettura al file di configurazione di mastodon. +OPZIONI + -H, --home + Definisce la home di mastodon (per default \"$MASTHOME\") + e di conseguenza il percorso del suo file di configurazione + (per default \"$MASTENVFP\"). + È comunque possibile specificare individualmente il percorso + del file di configurazione di mastodon con l\'opzione che segue. + -e, --envfp + Definisce il percorso del file di configurazione di mastodon in uso. + -s, --sistersfp + Definisce il percorso del file di inizializzazione da cui leggere + la lista dei domini delle istanze sorelle. + -l, --local + Interpreta il file di inizializzazione come lista di file locali + contenenti blacklist (formato: un file per riga). + -i, --interactive + Modalità interattiva: se vengono nelle blocklist vengono trovate + istanze ancora non presenti nel database di mastodon, viene chiesto + per ciascuna se aggiungerla o meno. + -h, --help + Mostra questo aiuto ed esce." + +args=("$@") +i=0 +while [ $i -lt ${#args[@]} ]; do + if [ "${args[$i]:0:1}" == "-" ]; then + case "${args[$i]}" in + "-H" | "--home" ) + if [ -z "${args[$i+1]}" ]; then + echo "L'opzione \"${args[$i]}\" richiede un parametro (usa \"-h\" per l'aiuto)." + exit 1 + else + ((i++)) + MASTHOME=$(echo "${args[$i]}" | sed -e 's/\/$//') + MASTENVFP="$MASTHOME/live/.env.production" + fi + ;; + "-e" | "--envfp" ) + if [ -z "${args[$i+1]}" ]; then + echo "L'opzione \"${args[$i]}\" richiede un parametro (usa \"-h\" per l'aiuto)." + exit 1 + else + ((i++)) + MASTENVFP="${args[$i]}" + fi + ;; + "-s" | "--sistersfp" ) + if [ -z "${args[$i+1]}" ]; then + echo "L'opzione \"${args[$i]}\" richiede un parametro (usa \"-h\" per l'aiuto)." + exit 1 + else + ((i++)) + SISTERSFP="${args[$i]}" + fi + ;; + "-l" | "--local" ) + LOCAL=1 + ;; + "-i" | "--interactive" ) + INTERACTIVE=1 + ;; + "-h" | "--help" ) + echo "$HELP" + exit 0 + ;; + *) + echo "\"${args[$i]}\": opzione sconosciuta (usa \"-h\" per l'aiuto)." + exit 1 + ;; + esac + else + echo "\"${args[$i]}\": opzione sconosciuta (usa \"-h\" per l'aiuto)." + exit 1 + fi + ((i++)) +done + +[ ! -e "$MASTENVFP" ] && echo "\"$MASTENVFP\" non esiste, muoio (usa \"-h\" per l'aiuto)." && exit 1 +[ ! -f "$MASTENVFP" ] && echo "\"$MASTENVFP\" non è un file, muoio (usa \"-h\" per l'aiuto)." && exit 1 +[ ! -r "$MASTENVFP" ] && echo "\"$MASTENVFP\" non è leggibile, muoio (usa \"-h\" per l'aiuto)." && exit 1 + +[ ! -e "$SISTERSFP" ] && echo "\"$SISTERSFP\" non esiste, muoio (usa \"-h\" per l'aiuto)." && exit 1 +[ ! -f "$SISTERSFP" ] && echo "\"$SISTERSFP\" non è un file, muoio (usa \"-h\" per l'aiuto)." && exit 1 +[ ! -r "$SISTERSFP" ] && echo "\"$SISTERSFP\" non è leggibile, muoio (usa \"-h\" per l'aiuto)." && exit 1 + +DB_HOST=`grep 'DB_HOST' "$MASTENVFP"|sed -e 's/[^=]*=//'` +DB_PORT=`grep 'DB_PORT' "$MASTENVFP"|sed -e 's/[^=]*=//'` +DB_NAME=`grep 'DB_NAME' "$MASTENVFP"|sed -e 's/[^=]*=//'` +DB_USER=`grep 'DB_USER' "$MASTENVFP"|sed -e 's/[^=]*=//'` +DB_PASS=`grep 'DB_PASS' "$MASTENVFP"|sed -e 's/[^=]*=//'` + +IFS=$'\n' + +function decode { + #dominio + record[0]=$(echo "$1" | sed -e 's/\t.*//') + #data creazione + record[1]=$(echo "$1" | sed -e 's/^[^\t]*\t\([^\t]*\).*/\1/') + #data ultima modifica + record[2]=$(echo "$1" | sed -e 's/^[^\t]*\t[^\t]*\t\([^\t]*\).*/\1/') + #tipo di blocco + record[3]=$(echo "$1" | sed -e 's/^[^\t]*\t[^\t]*\t[^\t]*\t\([^\t]*\).*/\1/') + #rifiuto media + record[4]=$(echo "$1" | sed -e 's/^[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t\([^\t]*\).*/\1/') + #rifiuto reports + record[5]=$(echo "$1" | sed -e 's/^[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t\([^\t]*\).*/\1/') + #commento pubblico + record[6]=$(echo "$1" | sed -e 's/^[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t\([^\t]*\).*/\1/') + if [ "${record[4]}" == "f" ]; then + record[4]="No" + elif [ "${record[4]}" == "t" ]; then + record[4]="Si" + fi + if [ "${record[5]}" == "f" ]; then + record[5]="No" + elif [ "${record[5]}" == "t" ]; then + record[5]="Si" + fi + if [ "${record[3]}" == "0" ]; then + record[3]="Silenziata" + elif [ "${record[3]}" == "1" ]; then + record[3]="Sospesa" + elif [ "${record[3]}" == "2" ]; then + record[3]="Nessuno" + fi +} + +for sisdom in $(grep -P '^[^#]+[^\s]+' "$SISTERSFP"); do + if [ $LOCAL -eq 0 ]; then + blocks+="$(curl --connect-timeout 3 -s "https://$sisdom/domain_blocks.txt" | grep -P '^[^#]+[^\s]+')$IFS" + else + blocks+="$(cat "$sisdom" | grep -P '^[^#]+[^\s]+')$IFS" + fi +done +blocks=$(echo "$blocks" | head -n -1 | sort -u) +echo "$blocks" +echo "~~~~~~~~~~~~~~~~~~~~" +okblocks='' +for line in $blocks; do + dom=$(echo "$line" | sed -e 's/\t.*//' -e 's/\./\\./g') + echo "$okblocks" | grep -P "^$dom\t" + if [ $? -ne 0 ]; then + entries=$(echo "$blocks" | grep -P "^$dom\t") + howmany=$(echo "$entries" | wc -l) + if [ $howmany -gt 1 ]; then + if [ $INTERACTIVE -eq 1 ]; then + i=0 + for entry in $entries; do + ((i++)) + echo "$i: $entry" + done + read + else + # qui ci vorrebbe codice "intelligente" che sceglie la entry più recente, ma per ora così + okblocks+="$line$IFS" + fi + fi + fi +done +okblocks=$(echo "$okblocks" | head -n -1 | sort) +echo "$okblocks" +echo "~~~~~~~~~~~~~~~~~~~~" + +exit + + + + +blocks=$(PGPASSWORD="$DB_PASS" psql -h "$DB_HOST" -p "$DB_PORT" -d "$DB_NAME" -U "$DB_USER" -c 'SELECT domain, updated_at, severity, public_comment FROM domain_blocks' -A -t -F $'\t') + +i=0 +for line in $allblocks; do + dom=$(echo "$line" | sed -e 's/\t.*//' -e 's/\./\\./g') + echo "$blocks" | grep -P "^$dom\t" &>/dev/null + [ $? -ne 0 ] && newblocks+="$line$IFS" && ((i++)) +done +newblocks=$(echo "$newblocks" | head -n -1 | sort) + +[ $i -eq 0 ] && echo "Non ho trovato nessuna nuova istanza bloccata." && exit 0 + +echo "Ho trovato $i istanza/e bloccata da aggiungere." + +if [ $INTERACTIVE -eq 1 ]; then + for line in $newblocks; do + decode "$line" + echo "Dominio: ${record[0]}; Data creaz.: ${record[1]}; Data ult. mod.: ${record[2]}; Tipo blocco: ${record[3]}; Rifiuto media: ${record[4]}; Rifiuto reports: ${record[5]}; Commento pub.: ${record[6]}" + ask=1 + while [ $ask -eq 1 ]; do + read -p "Vuoi aggiungere questa istanza alla tabella delle istanze bloccate? [S/n] " inp + echo "$inp" | grep -P '^[sSnN]{0,1}$' &>/dev/null + [ $? -eq 0 ] && ask=0 + done + if [ "$inp" == "" ] || [ "$inp" == "s" ] || [ "$inp" == "S" ]; then + buf+="$line$IFS" + fi + done + newblocks=$(echo "$buf" | head -n -1) +fi + +echo "$newblocks" | PGPASSWORD="$DB_PASS" psql -h "$DB_HOST" -p "$DB_PORT" -d "$DB_NAME" -U "$DB_USER" -A -t -c "COPY domain_blocks ( domain, created_at, updated_at, severity, reject_media, reject_reports, public_comment ) FROM STDIN WITH ( FORMAT text, DELIMITER ' ' )" diff --git a/mastblocksdump/php/domblocks.php b/mastblocksdump/php/domblocks.php new file mode 100644 index 0000000..8fc6311 --- /dev/null +++ b/mastblocksdump/php/domblocks.php @@ -0,0 +1,38 @@ +null, + 'DB_PORT'=>null, + 'DB_NAME'=>null, + 'DB_USER'=>null, + 'DB_PASS'=>null +); + +$confa=file($conffp,FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES); + +foreach ($confa as $line) { + if (preg_match('/^([A-Z_]+)=(.*)$/',$line,$buf)===1 && array_key_exists($buf[1],$conf)) + $conf[$buf[1]]=$buf[2]; +} + +$dbconn=pg_connect('host='.$conf['DB_HOST'].' port='.$conf['DB_PORT'].' dbname='.$conf['DB_NAME'].' user='.$conf['DB_USER'].' password='.$conf['DB_PASS']) + or die('Connessione fallita: '.pg_last_error()); + +$res=pg_query('SELECT domain, created_at, updated_at, severity, reject_media, reject_reports, public_comment FROM domain_blocks') + or die('Query fallita: '.pg_last_error()); + +while ($row=pg_fetch_assoc($res)) + $domblocks[]=$row; + +pg_free_result($res); +pg_close($dbconn); + +echo(json_encode($domblocks)); + +exit(0); + +?> diff --git a/web/admin/crawler/.htaccess b/web/admin/crawler/.htaccess new file mode 100644 index 0000000..93169e4 --- /dev/null +++ b/web/admin/crawler/.htaccess @@ -0,0 +1,2 @@ +Order deny,allow +Deny from all diff --git a/web/admin/crawler/blacklist_bida.txt b/web/admin/crawler/blacklist_bida.txt deleted file mode 100644 index 7dfe535..0000000 --- a/web/admin/crawler/blacklist_bida.txt +++ /dev/null @@ -1,36 +0,0 @@ -anitwitter.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f -anitwitter.moe 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f -babymetal.party 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f -baraag.net 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f -bsd.moe 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f https://mastodon.bida.im/@Ca_Gi/101270762003908554 -ediot.social 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f -freespeechextremist.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f -freespeech.firedragonstudios.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f https://mastodon.bida.im/@Ca_Gi/101344114624456297 -freezepeach.xyz 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f -gorf.club 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f -gs.smuglo.li 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f -humblr.social 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 0 f f https://mastodon.bida.im/@cirku17/101399587014096355 -ika.moe 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f -mastodon.starrevolution.org 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f https://a.nom.pl/notice/450131 -mobile.co 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f https://mastodon.bida.im/@Ca_Gi/101355947506820592 -neckbeard.xyz 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f Instance suspended: neckbeard.xyz - anime nazi shit, irony bro admin -newjack.city 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f -noagendasocial.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 0 f f -pawoo.net 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f -pl.smuglo.li 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f -porntoot.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 0 f f -preteengirls.biz 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f -quodverum.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f https://mastodon.bida.im/@Ca_Gi/101514801964087604 -sealion.club 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 0 f f -shitposter.club 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 0 f f -shitposter.club 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f https://mastodon.bida.im/@Ca_Gi/101270762003908554 -social.au2pb.net 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f -social.heldscal.la 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f -social.imirhil.fr 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f -social.quodverum.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f Razzisti -social.targaryen.house 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 0 f f -switter.at 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 0 f f https://mastodon.bida.im/@jops/101404791975700441 -toot.love 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 0 f f -unsafe.space 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f -woofer.alfter.us 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f -wrongthink.net 2019-12-11 18:44:05.111111 2019-12-11 18:44:05.111111 1 f f diff --git a/web/admin/crawler/blacklist_cagi.txt b/web/admin/crawler/blacklist_cagi.txt deleted file mode 100644 index b8f989e..0000000 --- a/web/admin/crawler/blacklist_cagi.txt +++ /dev/null @@ -1,157 +0,0 @@ -2.distsn.org 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Spam -2hu.club 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Pedo – Loli -anitwitter.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -anitwitter.moe 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Bad Moderation -ap.torlipen.net 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -ap.uwu.st 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Harassment or abuse -babymetal.party 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -baraag.net 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Pedo – Loli -beehub.org 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 0 f f -blob.cat 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -bodybuilding.im 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -bofa.lol 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -bsd.moe 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -carnal-gabhub.protohype.net 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -civiq.social 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -cofe.moe 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Bad Moderation -comm.network 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -community.halle-leaks.de 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -community.highlandarrow.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -counter.social 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Bad Moderation -cryzed.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 0 f f -cyzed.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -daffodil-11.org 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Malicious site -dev.civiq.social 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -develop.gab.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -dickshow.social 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Bad Moderation -djitter.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -ediot.social 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 0 f f Fascism – Hatespeech -ediot.socialsilence 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -ekrem.develop.gab.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -exited.eu 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -explosion.party 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Conspiracy theories -fedichive.tk 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -feminism.lgbt 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Pedo – Loli -freefedifollowers.ga 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -freehold.earth 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Bad Moderation -freespeechextremist.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -freespeech.firedragonstudios.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -freespeech.host 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -freevoice.space 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 0 f f Fascism – Hatespeech -freezepeach.xyz 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -gab.ai 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -gabble.xyz 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -gab.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -gabfed.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -gab.io 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -gab.polaris-1.work 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -gab.protohype.net 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -gab.sleek.eu 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -gameliberty.club 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Pedo – Loli -gasthe.lgbt 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -gnusocial.no 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -goldandblack.xyz 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -gorf.club 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 0 f f Fascism – Hatespeech -gorf.club 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -gs.archae.me 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -gs.kawa-kun.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -gs.mon5t3r.info 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -gs.smuglo.li 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -hakui.club 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -homura.space 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Harassment or abuse -ika.moe 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Bad Moderation -impeccable.social 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -inditoot.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Bad Moderation -jabb.in 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Conspiracy theories -juche.town 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -karolat.press 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -kawaiistu.moe 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -kawen.space 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -kazvam.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -kipper.im 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Bad Moderation -kiwifarms.cc 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 0 f f -kneegrows.top 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -kowai.youkai.town 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Pedo – Loli -kyot.me 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Bad Moderation -liberdon.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -libertarianism.club 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -libre.tube 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 0 f f -loli.estate 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Pedo – Loli -lolis.world 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -manx.social 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Bad Moderation -mastodon.loliandstuff.moe 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Pedo – Loli -mastodon.starrevolution.org 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -mast.wholemars.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 0 f f -melalandia.tk 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -me.nooruul.xyz 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -mobile.co 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -neckbeard.xyz 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -neenster.org 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -newjack.city 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Spam -niu.moe 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Bad Moderation -noagendasocial.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 0 f f Fascism – Hatespeech -not-develop.gab.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -not.phrack.fyi 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Conspiracy theories -npf.mlpol.net 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -pawoo.net 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Pedo – Loli -pleroma.cucked.me 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -pleroma.rareome.ga 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Malicious site -pleroma.soykaf.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -pleroma.wolfie.pw 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -pleroma.yorha.club 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Harassment or abuse -pleville.net 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 0 f f -pl.smuglo.li 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -porntoot.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Pedo – Loli -preteen.biz 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Pedo – Loli -preteengirls.bi 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Pedo – Loli -preteengirls.biz 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Pedo – Loli -pridelands.io 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -qoto.org 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -quey.org 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 0 f f -quitter.pw 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -quodverum.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -rainbowdash.net 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -rapefeminists.network 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -sealion.club 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -shitasstits.life 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Pedo – Loli -shitposter.club 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -social.allthefallen.ninja 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Pedo – Loli -social.au2pb.net 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -social.guizzyordi.info 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -social.heldscal.la 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -social.hidamari.blue 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 0 f f -social.homunyan.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 0 f f -social.i2p.rocks 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -social.imirhil.fr 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -social.louisoft01.moe 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Conspiracy theories -social.lucci.xyz 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Conspiracy theories -social.quodverum.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -social.raptorengineering.io 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Advertisement -social.sunshinegardens.org 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Harassment or abuse -social.super-niche.club 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Pedo – Loli -social.targaryen.house 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 0 f f Fascism – Hatespeech -social.wiuwiu.de 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Bad Moderation -socnet.supes.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Bad Moderation -spinster.dev 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -spinster.xyz 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -sunshinegardens.org 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Harassment or abuse -thechad.zone 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -the.hedgehoghunter.club 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 0 f f -toot.love 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Bad Moderation -unsafe.space 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 0 f f Fascism – Hatespeech -vampire.estate 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Pedo – Loli -video.halle-leaks.de 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f -vipgirlfriend.xxx 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Unflagged porn -voluntaryism.club 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -wagesofsinisdeath.com 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -waifu.social 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -warc.space 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 0 f f -weeaboo.space 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Pedo – Loli -weedis.life 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 0 f f -wogan.im 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -woofer.alfter.us 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech -wrongthink.net 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 0 f f Fascism – Hatespeech -wxw.moe 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Pedo – Loli -yiff.rocks 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Harassment or abuse -youkai.town 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Pedo – Loli -zerohack.xyz 2019-12-11 18:44:05.111111 2019-12-11 18:44:06.710862 1 f f Fascism – Hatespeech diff --git a/web/admin/crawler/crawler.php b/web/admin/crawler/crawler.php index f51b933..59b9c74 100755 --- a/web/admin/crawler/crawler.php +++ b/web/admin/crawler/crawler.php @@ -18,118 +18,38 @@ define('N',"\n"); -$inifp=null; +declare(ticks=1); +pcntl_signal(SIGTERM,'signalHandler');// Termination ('kill' was called) +pcntl_signal(SIGHUP,'signalHandler');// Terminal log-out +pcntl_signal(SIGINT,'signalHandler');// Interrupted (Ctrl-C is pressed) +function signalHandler($signal) { + global $link, $logf, $jsonf; + lecho(N.'Sono stato interrotto.'.N); + if ($link) { + lecho('La connessione MySQL è aperta, la chiudo.'.N); + mysqli_close($link); + } + if ($jsonf) { + echo('Il file di dump json è aperto, lo chiudo.'.N); + fwrite($jsonf,'"Fine?": true'.N.'}'.N); + fclose($jsonf); + } + if ($logf) { + echo('Il file di log è aperto, lo chiudo.'.N); + fclose($logf); + } + exit(2); +} $opts=array( - 'excludeafter'=>60*60*24*30, - 'startinstancesfp'=>null, - 'loadbiglist'=>true, - 'onlinecheck'=>true, - 'timeout'=>5, - 'biglistfp'=>null, - 'prodlistfp'=>null, - 'blacklists'=>array(), - 'whitelists'=>array() + 'timeout'=>3, + 'log'=>true, + 'jsonfp'=>'instances.json', + 'jsonwrite'=>true, + 'jsonread'=>false ); -$help='DESCRIZIONE - Questo script parte da una selezione di istanze Mastodon («istanze - di partenza»), ciascuna con una relativa lista di istanze da essa - bloccate (che può anche essere omessa), e genera/aggiorna due liste: - una che conterrà i dati di tutte le istanze di partenza e delle istanze - ad esse note (comprese quelle bloccate, escluse soltanto quelle che non - rispondono da un lasso di tempo impostabile), e una che conterrà solo - le istanze non bloccate, la cui piattaforma è mastodon, che danno - possibilità di iscrizione di nuovi utenti, il cui numero di utenti - è compreso tra 11 e 30000, che conoscono almeno altre 500 istanze, - che hanno avuto almeno 10 utenti attivi nell\'ultimo mese o, se questo - dato non è disponibile, la cui media di toot per utente è maggiore - o uguale a 10. -SINTASSI - crawler.php -i | -s -b -p [altre opzioni] -OPZIONI - -i, --inifp - Imposta un file di configurazione da cui leggere le opzioni. - Il formato di questo file è semplice: una opzione per riga in formato - =, dove «opzione» è una qualsiasi tra le opzioni - descritte qui nel suo formato lungo, tranne «inifp» e «help». - Esempio: «startinstancesfp=startinstances.txt». - Il file di configurazione può non contenere tutte le opzioni - disponibili. - Nota bene: tutte le opzioni impostate da riga di comando, che siano - specificate prima o dopo questa, hanno la precedenza su quelle - definite nel file di configurazione. - -s, --startinstancesfp - DEVE essere specificata. - Imposta il file da cui leggere le istanze di partenza e le relative - liste di istanze sospese-silenziate. - Il formato del file è questo: per ogni riga: - |[uri della relativa lista di istanze - bloccate] - Ogni riga vuota o che cominci con il carattere «#» sarà ignorata. - Il formato del file delle istanze bloccate è questo: per ogni riga: - |||| - - Esempio di : «2019-12-11 18:44:06.710862» - : «0» per silenziata, «1» per sospesa, «2» per "solo - file media e rapporti". - -b, --biglistfp - DEVE essere specificata. - Imposta il file da cui leggere le istanze già testate in passato - (se il file esiste e non è specificata l’opzione «-d», vedi sotto) - e in cui scrivere tutti i dati recuperabili delle istanze testate. - -p, --prodlistfp - DEVE essere specificata. - Imposta il file da cui leggere (se esiste) e in cui scrivere i dati - relativi alle istanze corrispondenti ai criteri di selezione descritti - nel paragrafo «DESCRIZIONE». - -B, --blacklistfp - Imposta un eventuale file di istanze bloccate aggiuntivo. Per il - formato di questi file vedi sopra il paragrafo relativo nella - descrizione dell\'opzione «-s, --startinstancesfp». Questa opzione può - essere utilizzata più volte per specificare più file di istanze - bloccate. Nel file di configurazione ha un formato particolare: - «blacklistfp=file1[,file2[,file3[...]]]». - -w, --whitelistfp - Imposta un eventuale file di istanze da non scartare mai, nemmeno - se fanno parte di una delle blacklist utilizzato o non corrispondono - ai criteri di filtraggio. Il formato di questi file è semplice: - un dominio per riga (le righe vuote o che cominciano con il carattere - «#» vengono ignorate. Questa opzione può essere utilizzata più volte - per specificare più whitelist. Nel file di configurazione - ha un formato particolare: «whitelistfp=file1[,file2[,file3[...]]]». - -t, --timeout - Imposta il timeout delle richieste http(s) in secondi. - DEFAULT: '.$opts['timeout'].' secondi. - -e, --excludeafter - Imposta il lasso di tempo dopo il quale un’istanza che non risponde - viene eliminata dal listone di tutte le istanze testate. - «tempo» deve essere specificato come un numero, seguito eventualmente - da un carattere che ne indica l’unità di misura: «s» o nessun - carattere per secondi, «m» per minuti, «o» per ore, «g» per giorni, - «S» per settimane, «M» per mesi (30 giorni), «A» per anni. - DEFAULT: 1 mese. - -l, --loadbiglist - Dice al programma se caricare o meno il listone delle istanze già - testate in passato. - DEFAULT: «si». - -c, --onlinecheck - Dice al programma se interrogare o meno le istanze note. - Se impostato a «no» forza a «si» «loadbiglist» (vedi opzione - precedente). - DEFAULT: «si». - -h, --help - Mostra questo aiuto ed esce. - - This program comes with ABSOLUTELY NO WARRANTY; for details see - the source. - This is free software, and you are welcome to redistribute it under - certain conditions; see for details.'.N; - -function mexit($msg,$code) { - echo($msg); - exit($code); -} +use function mysqli_real_escape_string as myesc; function tosec($str) { if (preg_match('/^([0-9]+)([smogSMA]?)/',$str,$buf)===1) { @@ -162,441 +82,377 @@ function tosec($str) { } } -for ($i=1; $i<$argc; $i++) { - if ($argv[$i]=='-i' || $argv[$i]=='--inifp') { - if ($i+1>=$argc || $argv[$i+1]=='') - mexit('L’opzione «'.$argv[$i].'» richiede di specificare un file di configurazione (usa «-h» per vedere la guida).'.N,1); - $i++; - $inifp=$argv[$i]; +function mexit($msg,$code,$closemy=false) { + global $link; + lecho($msg); + if ($closemy) + mysqli_close($link); + if ($logf) + fclose($logf); + exit($code); +} + +function lecho($msg,$logonly=false) { + global $opts, $logf; + if (!$logonly) + echo($msg); + if ($opts['log']) + fwrite($logf,$msg); +} + +$logfp='crawler.log'; +if ($opts['log']) { + $logf=@fopen(__DIR__.'/'.$logfp,'w') + or mexit('Non ho potuto aprire in scrittura il file di log «'.$logfp.'».',1); +} + +$inifp='../sec/mastostartadmin.ini'; +$iniarr=parse_ini_file($inifp) + or mexit('Impossibile aprire il file di configurazione «'.$inifp.'»'.N,1); +$link=mysqli_connect($iniarr['db_host'],$iniarr['db_admin_name'],$iniarr['db_admin_password'],$iniarr['db_name'],$iniarr['db_port'],$iniarr['db_socket']) + or mexit(mysqli_error($link).N,1); +mysqli_set_charset($link,'utf8'); + +$contextopts=array( + 'http'=>array( + 'timeout'=>$opts['timeout'] + ), + 'socket'=>array( + 'tcp_nodelay'=>true + ) +); +$context=stream_context_create($contextopts); + +$blacklist=array(); +lecho('Carico la blacklist dal database...'.N); +$res=mysqli_query($link,'SELECT * FROM Blacklist') + or mexit(mysqli_error($link).N,3,true); +lecho(mysqli_num_rows($res).' istanze nella blacklist.'.N); +while($row=mysqli_fetch_assoc($res)) { + $blacklist[$row['Domain']]=$row; +} + +function pgdatetomy($pgdate) { + if (preg_match('/^(\d+)-(\d+)-(\d+)[ T]{1}(\d+):(\d+):(\d+)\.(\d+)Z?$/',$pgdate,$buf)===1) { + return(mktime($buf[4],$buf[5],$buf[6],$buf[2],$buf[3],$buf[1])+floatval('0.'.$buf[7])); + } else { + return(false); } } -if (!is_null($inifp)) { - $buf=@parse_ini_file($inifp); +function blpgdumplinetomy($line) { + $truefalse=array('f'=>0,'t'=>1); + $row=explode("\t",$line); + $row=array('Domain'=>$row[0], + 'CreatedAt'=>pgdatetomy($row[1]), + 'ModifiedAt'=>pgdatetomy($row[2]), + 'Severity'=>$row[3], + 'RejectMedia'=>$truefalse[$row[4]], + 'RejectReports'=>$truefalse[$row[5]], + 'PublicComment'=>$row[6]); + return($row); +} + +$blacklistnew=array(); +$insts=array(); +lecho('Carico le istanze di partenza...'.N); +$res=mysqli_query($link,'SELECT Domain FROM StartNodes') + or mexit(mysqli_error($link).N,3,true); +lecho(mysqli_num_rows($res).' istanze di partenza.'.N); +while($row=mysqli_fetch_assoc($res)) { + $insts[$row['Domain']]=null; + lecho('Recupero la lista delle istanze note a «'.$row['Domain'].'» ... '); + $buf=@file_get_contents('https://'.$row['Domain'].'/api/v1/instance/peers',false,$context); if ($buf!==false) { - foreach ($buf as $key=>$val) { - if (array_key_exists($key,$opts)) { - if ($key=='excludeafter') { - $opts['excludeafter']=tosec($val); - if ($opts['excludeafter']===false) - mexit('L’opzione «excludeafter» specificata in «'.$inifp.'» non è in un formato corretto (usa «-h» per vedere la guida).'.N,1); - } elseif ($key=='blacklists') { - $opts['blacklists']=explode(',',$val); - } elseif ($key=='whitelists') { - $opts['whitelists']=explode(',',$val); - } else { - $opts[$key]=$val; - } - } else { - echo('Attenzione: l’opzione «'.$key.'» in «'.$inifp.'» è sconosciuta e sarà ignorata.'.N); + lecho('OK :-)'.N); + $peers=json_decode($buf,true); + foreach ($peers as $pdom) { + if (!array_key_exists($pdom,$insts) && strlen($pdom)<=64) { + $insts[$pdom]=null; } } } else { - mexit('Attenzione: non ho potuto leggere la configurazione dal file «'.$inifp.'».'.N,1); + lecho('ERRORE :-('.N); } -} - -for ($i=1; $i<$argc; $i++) { - if (substr($argv[$i],0,1)=='-') { - switch($argv[$i]) { - case '-i': - case '--inifp': - $i++; - break; - case '-e': - case '--excludeafter': - if ($i+1>=$argc) - $i++; - $opts['excludeafter']=tosec($argv[$i]); - if ($opts['excludeafter']===false) - mexit('Opzione «'.$argv[$i].'»: formato non corretto (usa «-h» per vedere la guida).'.N,1); - break; - case '-t': - case '--timeout': - if ($i+1>=$argc || preg_match('/^[0-9]+$/',$argv[$i+1])!==1) - mexit('L’opzione «'.$argv[$i].'» richiede un parametro numerico intero (usa «-h» per vedere la guida).'.N,1); - $i++; - $opts['timeout']=$argv[$i]; - break; - case '-b': - case '--biglistfp': - if ($i+1>=$argc || $argv[$i+1]=='') - mexit('L’opzione «'.$argv[$i].'» richiede un parametro di tipo file (usa «-h» per vedere la guida).'.N,1); - $i++; - $opts['biglistfp']=$argv[$i]; - break; - case '-p': - case '--prodlistfp': - if ($i+1>=$argc || $argv[$i+1]=='') - mexit('L’opzione «'.$argv[$i].'» richiede un parametro di tipo file (usa «-h» per vedere la guida).'.N,1); - $i++; - $opts['prodlistfp']=$argv[$i]; - break; - case '-s': - case '--startinstancesfp': - if ($i+1>=$argc || $argv[$i+1]=='') - mexit('L’opzione «'.$argv[$i].'» richiede un parametro di tipo file (usa «-h» per vedere la guida).'.N,1); - $i++; - $opts['startinstancesfp']=$argv[$i]; - break; - case '-B': - case '--blacklistfp': - if ($i+1>=$argc || $argv[$i+1]=='') - mexit('L’opzione «'.$argv[$i].'» richiede un parametro di tipo file (usa «-h» per vedere la guida).'.N,1); - $i++; - $opts['blacklists'][]=$argv[$i]; - break; - case '-w': - case '--whitelistfp': - if ($i+1>=$argc || $argv[$i+1]=='') - mexit('L’opzione «'.$argv[$i].'» richiede un parametro di tipo file (usa «-h» per vedere la guida).'.N,1); - $i++; - $opts['whitelists'][]=$argv[$i]; - break; - case '-l': - case '--loadbiglist': - if ($i+1>=$argc || ($argv[$i+1]!='si' && $argv[$i+1]!='no')) - mexit('L’opzione «'.$argv[$i].'» richiede un parametro («si/no») (usa «-h» per vedere la guida).'.N,1); - $i++; - $opts['loadbiglist']=true; - if ($argv[$i]=='no') $opts['loadbiglist']=false; - break; - case '-c': - case '--onlinecheck': - if ($i+1>=$argc || ($argv[$i+1]!='si' && $argv[$i+1]!='no')) - mexit('L’opzione «'.$argv[$i].'» richiede un parametro («si/no») (usa «-h» per vedere la guida).'.N,1); - $i++; - $opts['onlinecheck']=true; - if ($argv[$i]=='no') $opts['onlinecheck']=false; - break; - case '-h': - case '--help': - mexit($help,1); - break; - default: - mexit('Opzione «'.$argv[$i].'» sconosciuta (usa «-h» per vedere la guida).'.N,1); - break; - } - } else { - mexit('Opzione «'.$argv[$i].'» sconosciuta (usa «-h» per vedere la guida).'.N,1); - } -} - -$buf=null; -if (is_null($opts['startinstancesfp'])) - $buf.='- Non hai specificato il file delle istanze di partenza («-s/--startinstancesfp»)'.N; -if (is_null($opts['biglistfp'])) - $buf.='- Non hai specificato il file da cui leggere e in cui salvare i dati di tutte le istanze testate («-b/--biglistfp»)'.N; -if (is_null($opts['prodlistfp'])) - $buf.='- Non hai specificato il file da cui leggere e in cui salvare i dati di tutte le istanze testate che corrispondono ai criteri di selezione («-p/--prodlistfp»)'.N; -if (!is_null($buf)) - mexit('ERRORI'.N.$buf.'Usa «-h/--help» per leggere la guida.'.N,1); - -if (!$opts['onlinecheck']) - $opts['loadbiglist']=true; - -$biglist=array(); -$ibiglistc=0; -if ($opts['loadbiglist']) { - if (file_exists($opts['biglistfp']) && is_file($opts['biglistfp']) && is_readable($opts['biglistfp'])) { - echo('Carico la listona pre-esistente («'.$opts['biglistfp'].'») ... '); - $buf=@file_get_contents($opts['biglistfp']); - if ($buf!==false) { - echo('OK :-)'.N); - $biglist=json_decode($buf,true); - $ibiglistc=count($biglist); - } else { - echo('ERRORE :-('.N); - } - } -} - -$blinstances=array(); -$wlinstances=array(); - -function loadblacklist($bluri) { - global $blinstances, $opts; - $context=stream_context_create(array('http'=>array('timeout'=>$opts['timeout']))); - $f=@fopen($bluri,'r',false,$context); - if ($f!==false) { - $i=0; - while (!feof($f)) { - $lin=fgets($f); -//bsd.moe|2019-12-11 18:44:06.710862|1|https://mastodon.bida.im/@Ca_Gi/101270762003908554 - if (preg_match('/^([^#\|]{1}[^\|]+)\|{1}([^\|]+)\|{1}([012]{1})\|{1}(.*)$/',$lin,$buf)===1 && !in_array($buf[1],$blinstances) ) { - $i++; - $blinstances[]=$buf[1]; - } - } - fclose($f); - echo('OK :-) (+'.$i.' istanze bloccate caricate; totale: '.count($blinstances).')'.N); - } else { - mexit('ERRORE :-('.N,1); - } -} - -$startinstances=array(); -echo('Carico il file delle istanze di partenza («'.$opts['startinstancesfp'].'») ... '); -$buf=@file_get_contents($opts['startinstancesfp']); -if ($buf!==false) { - echo('OK :-)'.N); - $buf=explode(N,$buf); - foreach ($buf as $val) { - if ($val!='' && $val[0]!='#') { - $kv=explode('|',$val); - if ($kv[1]=='') $kv[1]=null; - $startinstances[$kv[0]]=$kv[1]; - } - } -} else { - mexit(N.'Non ho potuto caricare il file delle istanze di partenza «'.$opts['startinstancesfp'].'», muoio.'.N,1); -} -if (count($startinstances)<1) - mexit('Il file delle istanze di partenza «'.$opts['startinstancesfp'].'» non contiene alcuna voce, muoio.'.N,1); - -foreach ($startinstances as $dom=>$bluri) { - if (!is_null($bluri)) { - echo('Recupero la lista delle istanze bloccate da «'.$dom.'» («'.$bluri.'») ... '); - loadblacklist($bluri); - } else { - echo('NON recupero la lista delle istanze bloccate da «'.$dom.'»: la uri della stessa non è definita.'.N); - } -} -foreach ($opts['blacklists'] as $bluri) { - echo('Carico la lista delle istanze bloccate dall\'URI «'.$bluri.'» ... '); - loadblacklist($bluri); -} -sort($blinstances); -echo(count($blinstances).' istanze bloccate.'.N); - -foreach ($opts['whitelists'] as $wluri) { - echo('Carico la whitelist delle istanze dall\'URI «'.$wluri.'» ... '); - $buf=@file_get_contents($wluri); + lecho('Recupero la blacklist di «'.$row['Domain'].'» ... '); + $buf=@file_get_contents('https://'.$row['Domain'].'/domain_blocks.txt',false,$context); if ($buf!==false) { - echo('OK :-)'.N); + lecho('OK :-)'.N); $buf=explode(N,$buf); - foreach ($buf as $val) { - if ($val!='' && $val[0]!='#' && !in_array($val,$wlinstances)) - $wlinstances[]=$val; + foreach ($buf as $line) { + if (preg_match('/(^#.*$)|(^\s*$)/',$line)===0) { + $brow=blpgdumplinetomy($line); + if (!array_key_exists($brow['Domain'],$blacklist)) { + $blacklistnew[$brow['Domain']]=$brow; + } + $blacklist[$brow['Domain']]=$brow; + } } } else { - mexit(N.'Non ho potuto caricare la whitelist delle istanze «'.$wluri.'», muoio.'.N,1); + lecho('ERRORE :-('.N); } } -sort($wlinstances); -echo(count($wlinstances).' istanze whitelistate.'.N); +//lecho('Carico le istanze note dal DB e aggiungo alla lista di quelle da controllare quelle che non ci sono già.'.N); +$res=mysqli_query($link,'SELECT URI FROM Instances') + or mexit(mysqli_error($link).N,3,true); +while($row=mysqli_fetch_assoc($res)) { + if (!array_key_exists($row['URI'],$insts)) + $insts[$row['URI']]=null; +} +ksort($insts); +ksort($blacklist); +ksort($blacklistnew); +lecho('Istanze recuperate: '.count($insts).N); +lecho('Istanze blacklistate: '.count($blacklist).', di cui '.count($blacklistnew).' nuove da aggiungere al DB.'.N); -if ($opts['onlinecheck']) { +foreach ($blacklistnew as $row) { + foreach($row as $key=>$val) + $row[$key]=myesc($link,$val); + mysqli_query($link,'INSERT INTO Blacklist (ID, Domain, CreatedAt, ModifiedAt, Severity, RejectMedia, RejectReports, PrivateComment, PublicComment) VALUES (NULL, \''.$row['Domain'].'\', \''.$row['CreatedAt'].'\', \''.$row['ModifiedAt'].'\', \''.$row['Severity'].'\', \''.$row['RejectMedia'].'\', \''.$row['RejectReports'].'\', NULL, \''.$row['PublicComment'].'\')') + or mexit(mysqli_error($link).N,3,true); +} - $context=stream_context_create(array('http'=>array('timeout'=>$opts['timeout']))); +//INSERT INTO `Instances` (`ID`, `New`, `Chosen`, `Visible`, `BlackListed`, `URI`, `Title`, `ShortDesc`, `LongDesc`, `OurDesc`, `PlaceID`, `Email`, `Software`, `Version`, `UserCount`, `StatusCount`, `DomainCount`, `ActiveUsersMonth`, `ActiveUsersHalfYear`, `Thumb`, `RegOpen`, `RegReqApproval`, `MaxTootChars`, `AdmAccount`, `AdmDisplayName`, `AdmCreatedAt`, `AdmNote`, `AdmURL`, `AdmAvatar`, `AdmHeader`) VALUES (NULL, '1', '0', '0', '0', 'pantagruel.dnsup.net', 'Pantagruel', 'Descrizione breve', 'Descrizione lunga', 'Istanza molto carina senza soffitto, senza cucina', '1', 'Graume ', 'mastodon', '3.0.1', '2', '12', '345', '5', '10', 'http://www.iedm.it', '1', '0', '540', 'admin', 'Admin', '2019-12-11', 'Note \'admin\'', 'https://rame.altervista.org', 'http://www.iedm.it', 'http://www.iedm.it'); - foreach ($startinstances as $dom=>$bluri) { - if (!array_key_exists($dom,$biglist)) - $biglist[$dom]=null; - echo('Recupero la lista delle istanze note a «'.$dom.'» ... '); - $buf=@file_get_contents('https://'.$dom.'/api/v1/instance/peers',false,$context); - if ($buf!==false) { - echo('OK :-)'.N); - $peers=json_decode($buf,true); - foreach ($peers as $pdom) { - if (!array_key_exists($pdom,$biglist)) { - $biglist[$pdom]=null; - } - } - } else { - echo('ERRORE :-('.N); - } +function b2i($bool) { + if ($bool) + return(1); + else + return(0); +} + +//array key exists and value is not null +function akeavinn($key,&$arr) { + if (array_key_exists($key,$arr) && !is_null($arr[$key])) + return(true); + else + return(false); +} + +function nempty($str) { + if (preg_match('/^\s*$/',$str)===1) + return(null); + else + return($str); +} + +function subarim($glue,$key,&$arr) { + $str=''; + $i=1; + $carr=count($arr); + foreach ($arr as $inarr) { + $str.=$inarr[$key]; + if ($i<$carr) + $str.=$glue; + $i++; } - ksort($biglist); - $diff=count($biglist)-$ibiglistc; - if ($diff>=0) $diff='+'.$diff; - echo('Totale istanze note: '.count($biglist).' ('.$diff.' rispetto all\'ultima volta).'.N); + return($str); } -$prodlist=array(); -$iprodlistc=0; -$buf=@file_get_contents($opts['prodlistfp']); -if ($buf!==false) { - $prodlist=json_decode($buf,true); - $iprodlistc=count($prodlist); +function notify($msg,$sev) { + global $link; + mysqli_query($link,'INSERT INTO Notifications (ID, Notification, Severity, Microtime) VALUES (NULL, \''.myesc($link,$msg).'\', '.$sev.', '.microtime().')') + or mexit(mysqli_error($link).N,3,true); } -$newbiglist=array(); +/* + * Nodeinfo ('https://'.$dom.'/nodeinfo/2.0') è stato aggiunto nella 3.0.0 + * Trends ('https://'.$dom.'/api/v1/trends') è stato aggiunto nella 3.0.0 + * Activity ('https://'.$dom.'/api/v1/instance/activity') è stato aggiunto nella 2.1.2 +*/ + +if ($opts['jsonwrite']) { + $jsonf=@fopen(__DIR__.'/'.$opts['jsonfp'],'w') + or mexit('Non ho potuto aprire in scrittura il file di dump delle info json «'.$opts['jsonfp'].'».',1); + fwrite($jsonf,'{'.N); +} +$cinsts=count($insts); $i=0; -$biglistc=count($biglist); -foreach ($biglist as $dom=>$oinfo) { +$ok=0; +foreach ($insts as $dom=>$row) { $i++; - echo('~~~~~~'.N); - if ($opts['onlinecheck']) { - - echo('Recupero le informazioni su «'.$dom.'» ('.$i.'/'.$biglistc.' - '.round(100/$biglistc*$i).'%)'.N); - - echo('Recupero le informazioni Nodeinfo ... '); - $ninfo=null; - $buf=@file_get_contents('https://'.$dom.'/nodeinfo/2.0',false,$context); - if ($buf!==false) { - echo('OK :-)'.N); - $ninfo=json_decode($buf,true); - } else { - echo('ERRORE :-('.N); - } - - echo('Recupero le informazioni API sull\'attività dell\'istanza ... '); - $activity=null; - $buf=@file_get_contents('https://'.$dom.'/api/v1/instance/activity',false,$context); - if ($buf!==false) { - echo('OK :-)'.N); - $activity=json_decode($buf,true); - } else { - echo('ERRORE :-('.N); - } - - echo('Recupero le informazioni API sull\'istanza ... '); - $info=null; - $buf=@file_get_contents('https://'.$dom.'/api/v1/instance',false,$context); - if ($buf!==false) { - echo('OK :-)'.N); - $info=json_decode($buf,true); - if (!is_null($oinfo) && array_key_exists('X-Checks',$oinfo)) - $info['X-Checks']=$oinfo['X-Checks']; - $info['X-Checks'][]=array('time'=>time(),'ok'=>true); - if (!is_null($ninfo)) { - if (array_key_exists('usage',$ninfo) && array_key_exists('users',$ninfo['usage'])) { - if (array_key_exists('activeMonth',$ninfo['usage']['users'])) - $info['X-ActiveUsersPerMonth']=$ninfo['usage']['users']['activeMonth']; - if (array_key_exists('activeHalfyear',$ninfo['usage']['users'])) - $info['X-ActiveUsersPerHalfYear']=$ninfo['usage']['users']['activeHalfyear']; - } - if (array_key_exists('software',$ninfo)) { - if (array_key_exists('name',$ninfo['software'])) - $info['X-Software']=$ninfo['software']['name']; - if (array_key_exists('version',$ninfo['software'])) - $info['X-Version']=$ninfo['software']['version']; + $info=null; + lecho('~~~~~~~~~~~~~~~'.N); + lecho('Provo a recuperare info su «'.$dom.'» ['.$i.'/'.$cinsts.' ('.$ok.' OK) - '.round(100/$cinsts*$i).'%]'.N); + lecho('Provo a recuperare le informazioni API sull’istanza ... '); + $buf=@file_get_contents('https://'.$dom.'/api/v1/instance',false,$context); + if ($buf!==false) { + $ok++; + lecho('OK :-)'.N); + $info=json_decode($buf,true); + if (array_key_exists('version',$info)) { + if ($info['version']>='2.1.2') { + lecho('Provo a recuperare le informazioni API sull’attività dell’istanza ... '); + $buf=@file_get_contents('https://'.$dom.'/api/v1/instance/activity',false,$context); + if ($buf!==false) { + lecho('OK :-)'.N); + $info['x-activity']=json_decode($buf,true); + } else { + lecho('ERRORE :-('.N); } } - if (!is_null($activity)) - $info['X-Activity']=$activity; - $newbiglist[$dom]=$info; - } else { - echo('ERRORE :-( ... '); - $lastokk=null; - if (!is_null($oinfo) && array_key_exists('X-Checks',$oinfo)) { - foreach ($oinfo['X-Checks'] as $key=>$val) - if ($val['ok']) $lastokk=$key; + if ($info['version']>='3.0.0') { + lecho('Provo a recuperare le informazioni Nodeinfo sull’istanza ... '); + $buf=@file_get_contents('https://'.$dom.'/nodeinfo/2.0',false,$context); + if ($buf!==false) { + lecho('OK :-)'.N); + $info['x-nodeinfo']=json_decode($buf,true); + } else { + lecho('ERRORE :-('.N); + } + lecho('Provo a recuperare le informazioni API sui trends dell’istanza ... '); + $buf=@file_get_contents('https://'.$dom.'/api/v1/trends',false,$context); + if ($buf!==false) { + lecho('OK :-)'.N); + $info['x-trends']=json_decode($buf,true); + } else { + lecho('ERRORE :-('.N); + } } - if (is_null($oinfo) || is_null($lastokk) || time()-$oinfo['X-Checks'][$lastokk]['time']<=$opts['excludeafter']) { - echo('ma riproveremo...'.N); - $oinfo['X-Checks'][]=array('time'=>time(),'ok'=>false); - $newbiglist[$dom]=$oinfo; - } else { - echo('e non riproveremo...'.N); - $oinfo=null; - } - $info=$oinfo; } } else { - $info=$oinfo; + lecho('ERRORE :-('.N); } - $whynot=array(); - if (array_key_exists('uri',$info)) { - if (!in_array($dom,$wlinstances)) { - if (in_array($dom,$blinstances)) - $whynot[]='Istanza blacklistata'; - if (array_key_exists('X-Software',$info) && !in_array($info['X-Software'],array('mastodon','corgidon'))) - $whynot[]='Il software non è Mastodon (ma '.$info['X-Software'].')'; - if (!array_key_exists('registrations',$info)) - $whynot[]='Stato delle registrazioni non disponibile'; - elseif ($info['registrations']==false) - $whynot[]='Registrazioni chiuse'; - if (!array_key_exists('stats',$info)) { - $whynot[]='Stats non disponibili'; - } else { - if (!array_key_exists('user_count',$info['stats'])) - $whynot[]='Numero utenti non disponibile'; - elseif ($info['stats']['user_count']<10 || $info['stats']['user_count']>30000) - $whynot[]='Numero utenti ('.$info['stats']['user_count'].') non compreso tra 10 e 30000'; - if (!array_key_exists('domain_count',$info['stats'])) - $whynot[]='Numero istanze conosciute non disponibile'; - elseif ($info['stats']['domain_count']<500) - $whynot[]='Numero istanze conosciute minore di 500'; - /* if (!array_key_exists('status_count',$info['stats'])) - $whynot[]='Numero di toots non disponibile'; - elseif ($info['stats']['status_count']/$info['stats']['user_count']<10) - $whynot[]='Media dei toots per utente minore di 10';*/ + if (!is_null($info) && akeavinn('uri',$info) && !is_null(nempty($info['uri']))) { + lecho(json_encode($info,JSON_PRETTY_PRINT).N,true); + if ($opts['jsonwrite']) + fwrite($jsonf,'"'.$info['uri'].'": '.json_encode($info,JSON_PRETTY_PRINT).','.N); +//INSERT INTO `Instances` (`ID`, `New`, `Chosen`, `Visible`, `BlackListed`, `URI`, `Title`, `ShortDesc`, `LongDesc`, `OurDesc`, `PlaceID`, `Email`, `Software`, `Version`, `UserCount`, `StatusCount`, `DomainCount`, `ActiveUsersMonth`, `ActiveUsersHalfYear`, `Thumb`, `RegOpen`, `RegReqApproval`, `MaxTootChars`, `AdmAccount`, `AdmDisplayName`, `AdmCreatedAt`, `AdmNote`, `AdmURL`, `AdmAvatar`, `AdmHeader`) VALUES (NULL, '1', '0', '0', '0', 'pantagruel.dnsup.net', 'Pantagruel', 'Descrizione breve', 'Descrizione lunga', 'Istanza molto carina senza soffitto, senza cucina', '1', 'Graume ', 'mastodon', '3.0.1', '2', '12', '345', '5', '10', 'http://www.iedm.it', '1', '0', '540', 'admin', 'Admin', '2019-12-11', 'Note \'admin\'', 'https://rame.altervista.org', 'http://www.iedm.it', 'http://www.iedm.it'); + $instrow=array('ID'=>null, 'New'=>0, 'Chosen'=>0, 'Visible'=>0, 'BlackListed'=>0, 'URI'=>null, 'Title'=>null, 'ShortDesc'=>null, 'LongDesc'=>null, 'OurDesc'=>null, 'PlaceID'=>null, 'Email'=>null, 'Software'=>null, 'Version'=>null, 'UserCount'=>null, 'StatusCount'=>null, 'DomainCount'=>null, 'ActiveUsersMonth'=>null, 'ActiveUsersHalfYear'=>null, 'Thumb'=>null, 'RegOpen'=>null, 'RegReqApproval'=>null, 'MaxTootChars'=>null, 'AdmAccount'=>null, 'AdmDisplayName'=>null, 'AdmCreatedAt'=>null, 'AdmNote'=>null, 'AdmURL'=>null, 'AdmAvatar'=>null, 'AdmHeader'=>null); + if (array_key_exists($info['uri'],$blacklist)) + $instrow['BlackListed']=1; + $instrow['URI']=nempty($info['uri']); + if (akeavinn('title',$info)) + $instrow['Title']=nempty($info['title']); + if (akeavinn('short_description',$info)) + $instrow['ShortDesc']=nempty($info['short_description']); + if (akeavinn('description',$info)) + $instrow['LongDesc']=nempty($info['description']); + if (akeavinn('email',$info)) + $instrow['Email']=nempty($info['email']); + if (akeavinn('version',$info)) + $instrow['Version']=nempty($info['version']); + if (akeavinn('stats',$info)) { + if (akeavinn('user_count',$info['stats'])) + $instrow['UserCount']=$info['stats']['user_count']; + if (akeavinn('status_count',$info['stats'])) + $instrow['StatusCount']=$info['stats']['status_count']; + if (akeavinn('domain_count',$info['stats'])) + $instrow['DomainCount']=$info['stats']['domain_count']; + } + if (akeavinn('thumbnail',$info)) + $instrow['Thumb']=nempty($info['thumbnail']); + if (akeavinn('max_toot_chars',$info)) + $instrow['MaxTootChars']=$info['max_toot_chars']; + if (akeavinn('registrations',$info)) + $instrow['RegOpen']=b2i($info['registrations']); + if (akeavinn('approval_required',$info)) + $instrow['RegReqApproval']=b2i($info['approval_required']); + if (akeavinn('contact_account',$info)) { + if (akeavinn('acct',$info['contact_account'])) + $instrow['AdmAccount']=nempty($info['contact_account']['acct']); + if (akeavinn('display_name',$info['contact_account'])) + $instrow['AdmDisplayName']=nempty($info['contact_account']['display_name']); + if (akeavinn('created_at',$info['contact_account'])) + $instrow['AdmCreatedAt']=pgdatetomy($info['contact_account']['created_at']); + if (akeavinn('note',$info['contact_account'])) + $instrow['AdmNote']=nempty(strip_tags($info['contact_account']['note'],'')); + if (akeavinn('url',$info['contact_account'])) + $instrow['AdmURL']=nempty($info['contact_account']['url']); + if (akeavinn('avatar',$info['contact_account'])) + $instrow['AdmAvatar']=nempty($info['contact_account']['avatar']); + if (akeavinn('header',$info['contact_account'])) + $instrow['AdmHeader']=nempty($info['contact_account']['header']); + } + if (akeavinn('x-nodeinfo',$info)) { + if (akeavinn('software',$info['x-nodeinfo']) && akeavinn('name',$info['x-nodeinfo']['software'])) + $instrow['Software']=nempty($info['x-nodeinfo']['software']['name']); + if (akeavinn('usage',$info['x-nodeinfo']) && akeavinn('users',$info['x-nodeinfo']['usage'])) { + if (akeavinn('activeMonth',$info['x-nodeinfo']['usage']['users'])) + $instrow['ActiveUsersMonth']=$info['x-nodeinfo']['usage']['users']['activeMonth']; + if (akeavinn('activeHalfyear',$info['x-nodeinfo']['usage']['users'])) + $instrow['ActiveUsersHalfYear']=$info['x-nodeinfo']['usage']['users']['activeHalfyear']; } - if (array_key_exists('X-ActiveUsersPerMonth',$info)) { - if ($info['X-ActiveUsersPerMonth']<10) - $whynot[]='Numero utenti attivi nell\'ultimo mese minore di 10'; - } elseif (array_key_exists('stats',$info) && array_key_exists('status_count',$info['stats']) && array_key_exists('user_count',$info['stats']) && $info['stats']['user_count']>0 && $info['stats']['status_count']/$info['stats']['user_count']<10) { - $whynot[]='Media dei toots per utente minore di 10'; + } + $res=mysqli_query($link,'SELECT * FROM Instances WHERE URI=\''.myesc($link,$instrow['URI']).'\'') + or mexit(mysqli_error($link).N,3,true); + if (mysqli_num_rows($res)>0) { + lecho('«'.$instrow['URI'].'» è già presente nel DB, la aggiorno...'.N); + $oldinstrow=mysqli_fetch_assoc($res); + $query='UPDATE Instances SET '; + foreach ($instrow as $field=>$value) { + if (!is_null($value)) + $query.=$field.'=\''.myesc($link,$value).'\', '; + else + $query.=$field.'=\'NULL\', '; } - if (!array_key_exists('contact_account',$info) || is_null($info['contact_account'])) { - $whynot[]='Informazioni sull\'account admin principale non disponibili'; - }/* else { - if (!array_key_exists('created_at',$info['contact_account'])) - $whynot[]='Data di creazione dell\'account admin principale non disponibile'; - elseif (time()-strtotime($info['contact_account']['created_at'])<6*31*24*60*60) - $whynot[]='L\'account admin principale risulta esser stato creato meno di 6 mesi fa'; + $query=substr($query,0,-2).' WHERE Instances.ID='.$oldinstrow['ID']; + echo('QUERONA DI UPDATE: «'.$query.'».'.N); +/* $res=mysql_query($link,'SELECT InstID, LangID, Pos, Code FROM InstLangs LEFT JOIN Languages ON Languages.ID=LangID WHERE InstID='.$oldinstrow['ID'].' ORDER BY Pos ASC') + or mexit(mysqli_error($link).N,3,true); + $oldinstlangs=array(); + while ($row=mysql_fetch_assoc($res)) + $oldinstlangs[]=$row; + if (akeavinn('languages',$info)) { + $instlangs=array(); + $pos=0; + foreach ($info['languages'] as $lang) { + $res=mysqli_query($link,'SELECT * FROM Languages WHERE Code=\''.myesc($link,$lang).'\'') + or mexit(mysqli_error($link).N,3,true); + if (mysqli_num_rows($res)<1) { + mysqli_query($link,'INSERT INTO Languages (ID, Code, Name) VALUES (NULL, \''.myesc($link,$lang).'\', NULL)') + or mexit(mysqli_error($link).N,3,true); + $langid=mysqli_insert_id($link); + notify('L’aggiornamento dei dati relativi all’istanza «'.$info['URI'].'» ha aggiunto un codice lingua non ancora noto, «'.$lang.'», di cui non conosco il nome per esteso. Puoi editarlo qui.',1); + } else { + $row=mysqli_fetch_assoc($res); + $langid=$row['ID']; + } + $pos++; + $instlangs[]=array('InstID'=>$oldinstrow['ID'],'LangID'=>$langid,'Pos'=>$pos,'Code'=>$lang); + } + print_r($instlangs); + print_r($oldinstlangs); + if ($instlangs!=$oldinstlangs) { + notify('La lista delle lingue utilizzate dichiarate dall’istanza «'.$info['URI'].'» è cambiata da «'.subarim(', ','Code',$oldinstlangs).'» a «'.subarim(', ','Code',$oldinstlangs).'».',1); + mysqli_query($link,'DELETE FROM InstLangs WHERE InstID='.$oldinstrow['ID']) + or mexit(mysqli_error($link).N,3,true); + foreach ($instlangs as $row) { + mysqli_query($link,'INSERT INTO InstLangs (InstID, LangID, Pos) VALUES ('.$row['InstID'].', '.$row['LangID'].', '.$row['Pos'].')') + or mexit(mysqli_error($link).N,3,true); + } + } }*/ } else { - echo('«'.$dom.'» è whitelistata, la teniamo a prescindere.'.N); - } - } elseif (!array_key_exists($dom,$prodlist)) { - $whynot[]='Info non disponibili, e l\'istanza non era già presente nella lista delle istanze occhei'; - } - if (count($whynot)==0) { - if (array_key_exists($dom,$prodlist)) { - if (array_key_exists('short_description',$info) && (!array_key_exists('short_description',$prodlist[$dom]) || $prodlist[$dom]['short_description']!=$info['short_description'])) { - $info['X-ShortDescriptionChanged']=true; - $info['X-PrevShortDescription']=$prodlist[$dom]['short_description']; - } else { - $info['X-ShortDescriptionChanged']=false; + lecho('«'.$info['uri'].'» non è già presente nel DB, la aggiungo...'.N); + $instrow['New']=1; + $fields=array(); + $values=''; + foreach ($instrow as $field=>$value) { + $fields[]=$field; + if (!is_null($value)) + $values.='\''.myesc($link,$value).'\', '; + else + $values.='NULL, '; } - if (array_key_exists('description',$info) && (!array_key_exists('description',$prodlist[$dom]) || $prodlist[$dom]['description']!=$info['description'])) { - $info['X-DescriptionChanged']=true; - $info['X-PrevDescription']=$prodlist[$dom]['description']; - } else { - $info['X-DescriptionChanged']=false; - } - echo('«'.$dom.'» era nella lista delle istanze occhei ed è stata AGGIORNATA! :-)'.N); - if (array_key_exists('X-Show',$prodlist[$dom])) - $info['X-Show']=$prodlist[$dom]['X-Show']; - else - $info['X-Show']=-1; - } else { - $info['X-ShortDescriptionChanged']=false; - $info['X-DescriptionChanged']=false; - $info['X-Show']=-1; - echo('«'.$dom.'» non era nella lista delle istanze occhei ed è stata AGGIUNTA! :-)'.N); + $values=substr($values,0,-2); + $query='INSERT INTO Instances ('.implode(', ',$fields).') VALUES ('.$values.')'; + echo('QUERONA DI INSERT: «'.$query.'»'.N); } - $prodlist[$dom]=$info; - } else { - if (array_key_exists($dom,$prodlist)) { - unset($prodlist[$dom]); - echo('«'.$dom.'» era nella lista delle istanze occhei ma è stata SCARTATA! :-('.N); - } else { - echo('«'.$dom.'» non era nella lista delle istanze occhei e NON CI È ENTRATA! :-('.N); - } - echo('Motivazioni: '.implode('; ',$whynot).'.'.N); +// var_dump($instrow); } } -echo('~~~~~~'.N); +mysqli_close($link); -if ($opts['onlinecheck']) { - $json=json_encode($newbiglist,JSON_PRETTY_PRINT); - file_put_contents($opts['biglistfp'],$json); - $newbiglistc=count($newbiglist); - $diff=$newbiglistc-$ibiglistc; - if ($diff>=0) $diff='+'.$diff; - echo('Totale istanze nella listona: '.$newbiglistc.' ('.$diff.' rispetto all\'ultima volta)'.N); -} else { - echo('Totale istanze nella listona: '.count($biglist).N); +if ($opts['jsonwrite']) { + fwrite($jsonf,'"Fine?": true'.N.'}'.N); + fclose($jsonf); } -$json=json_encode($prodlist,JSON_PRETTY_PRINT); -file_put_contents($opts['prodlistfp'],$json); -$diff=count($prodlist)-$iprodlistc; -if ($diff>=0) $diff='+'.$diff; -echo('Totale istanze nella listina di quelle occhei: '.count($prodlist).' ('.$diff.' rispetto all\'ultima volta)'.N); + +if ($opts['log']) + fclose($logf); + +exit(0); ?> diff --git a/web/admin/crawler/crawler_pant.ini b/web/admin/crawler/crawler_pant.ini deleted file mode 100644 index 190070f..0000000 --- a/web/admin/crawler/crawler_pant.ini +++ /dev/null @@ -1,9 +0,0 @@ -excludeafter=1M -startinstancesfp=istanzesorelle_pant -loadbiglist=true -onlinecheck=true -timeout=5 -biglistfp=biglist_pant.json -prodlistfp=prodlist_pant.json -blacklists=blacklist_cagi.txt -whitelists=whitelist_sorellanza.txt diff --git a/web/admin/crawler/crawler_sorellanza.ini b/web/admin/crawler/crawler_sorellanza.ini deleted file mode 100644 index 9d82098..0000000 --- a/web/admin/crawler/crawler_sorellanza.ini +++ /dev/null @@ -1,9 +0,0 @@ -excludeafter=1M -startinstancesfp=istanzesorelle -loadbiglist=true -onlinecheck=true -timeout=3 -biglistfp=biglist.json -prodlistfp=prodlist.json -blacklists=blacklist_cagi.txt -whitelists=whitelist_sorellanza.txt diff --git a/web/admin/crawler/istanzesorelle b/web/admin/crawler/istanzesorelle deleted file mode 100644 index 06acaac..0000000 --- a/web/admin/crawler/istanzesorelle +++ /dev/null @@ -1,5 +0,0 @@ -mastodon.bida.im|blacklist_bida.txt -mastodon.cisti.org| -nebbia.fail| -stereodon.social| -snapj.saja.freemyip.com| diff --git a/web/admin/crawler/istanzesorelle_pant b/web/admin/crawler/istanzesorelle_pant deleted file mode 100644 index 8b56c12..0000000 --- a/web/admin/crawler/istanzesorelle_pant +++ /dev/null @@ -1 +0,0 @@ -pantagruel.dnsup.net|blacklist_bida.txt diff --git a/web/admin/favicon.ico b/web/admin/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..c03b1b97b2c00e0c2d1b91557b166af9bd135ebf GIT binary patch literal 9662 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 E07}*O8UO$Q literal 0 HcmV?d00001 diff --git a/web/admin/imgs/icona-32.png b/web/admin/imgs/icona-32.png new file mode 100644 index 0000000000000000000000000000000000000000..b9b903e236cbf11f3a17898757a139599fdf75c4 GIT binary patch literal 962 zcmV;z13mnSP)H@O+YPen%WwT)=Ke47iv|o zs30OJRY57PilFY?=}KKGx{;FXR7CLt0asmwLTQ8+wQbPWNYd)iG$u7kC*(5Y%yDrh zlg#8~a*r?ki|>55_q_lAbG{R^FsgAc?!q2yLlbU6E#j!p$BrR~6fR>3f8iW@a2iu( zdKKXje3dU2tkFv0YaA%oIF66ku<1hUlYFmv_;drB&#a@R%@1v0^O^M`#88O~Xo-@g zp)TQ>M{C{QQYDw;eE+o0u5qKOY*E||wP9TAjwt8@ca{XgoQX#e;jVE7(ILSv|c| zw%t@|*Y+y#)34#x-q%(QdM~9V2Q&8UuGZL)n5}hY(*BqFqX?XZ0VUEjH6()ExmhXC ze77^GuZb7@?;dHIC-*x?nhO5f-$z82Y!!PG^~?x*n{{T zzX<;m%Howp-r~?=1y+j+oG(M5YrP4;L7|ijkvNK)wQgEECA@_X%fw&B55hTe0HZ?E zap8GrMjQ6w&XtmSRrs^H+A9}1gDn-!LM5)Ou=z!7UP`0rVSW~scmVfdFLvQ(G|b7L kMiQ5V_x(72w8S~%KYY;`qBWZxUjP6A07*qoM6N<$f^g=}ZvX%Q literal 0 HcmV?d00001 diff --git a/web/admin/imgs/icona-512.png b/web/admin/imgs/icona-512.png new file mode 100644 index 0000000000000000000000000000000000000000..9ad6300709efdee439d855c891c7db58a2edefbf GIT binary patch literal 13302 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 literal 0 HcmV?d00001 diff --git a/web/admin/include/connuser.php b/web/admin/include/connuser.php new file mode 100644 index 0000000..553b365 --- /dev/null +++ b/web/admin/include/connuser.php @@ -0,0 +1,10 @@ +Login.',true); +$user=mysqli_fetch_assoc($res); + +?> diff --git a/web/admin/include/glob.php b/web/admin/include/glob.php new file mode 100644 index 0000000..af9f50c --- /dev/null +++ b/web/admin/include/glob.php @@ -0,0 +1,10 @@ + diff --git a/web/admin/include/menu.php b/web/admin/include/menu.php new file mode 100644 index 0000000..c6927a5 --- /dev/null +++ b/web/admin/include/menu.php @@ -0,0 +1,52 @@ +array('liadd'=>null, 'href'=>'istanze.php', 'title'=>'Istanze', 'selected'=>false, 'submenu'=> + array( + 'aggiungi'=>array('liadd'=>'onclick="golang(\'en\')" onmouseover="this.style.cursor=\'pointer\'"', 'href'=>null, 'title'=>'English', 'selected'=>false, 'submenu'=>null), + 'italiano'=>array('liadd'=>'onclick="golang(\'it\')" onmouseover="this.style.cursor=\'pointer\'"', 'href'=>null, 'title'=>'Italiano', 'selected'=>false, 'submenu'=>null) + ) + ), + 'boh'=>array('liadd'=>null, 'href'=>'#', 'title'=>'Non saprei', 'selected'=>false, 'submenu'=>null), + 'vedremo'=>array('liadd'=>null, 'href'=>'#', 'title'=>'Vedremo', 'selected'=>false, 'submenu'=>null), + 'forse'=>array('liadd'=>null, 'href'=>'#', 'title'=>'Forse', 'selected'=>false, 'submenu'=>null) +); + + +/* +
  • Guide
  • +
  • Instances
  • +
  • About us
  • +
  • Language + +
  • +*/ + +$menuout=''; + +function buildmenu($menu) { + global $menuout; + foreach ($menu as $key=>$arr) { + $menuout.=''.$arr['title'].''; + else + $menuout.=$arr['title']; + if (!is_null($arr['submenu'])) { +// qui bisognerebbe aggiungere che a seconda del "livello" imposta class giusta: ula, oppure ulb per livello > 1 + $menuout.=N.'
      '.N; + buildmenu($arr['submenu']); + $menuout.='
    '.N; + } + $menuout.=''.N; + } +} + +?> diff --git a/web/admin/include/muoribene.php b/web/admin/include/muoribene.php new file mode 100644 index 0000000..20927a8 --- /dev/null +++ b/web/admin/include/muoribene.php @@ -0,0 +1,31 @@ + + + +Mastodon Startpage Admin - Errori + + + + + + + + + + +
    +
    +

    '.$msg.'

    +
    +
    + + +'); + exit(1); +} + +?> diff --git a/web/admin/include/myconn.php b/web/admin/include/myconn.php new file mode 100644 index 0000000..945b5cd --- /dev/null +++ b/web/admin/include/myconn.php @@ -0,0 +1,9 @@ +'.$btl,false); +$link=mysqli_connect($iniarr['db_host'],$iniarr['db_admin_name'],$iniarr['db_admin_password'],$iniarr['db_name'],$iniarr['db_port'],$iniarr['db_socket']) + or muoribene('Impossibile connettersi al database: '.mysqli_connect_error().' ['.mysqli_connect_errno().']',false); +mysqli_set_charset($link,'utf8'); + +?> diff --git a/web/admin/include/sessionstart.php b/web/admin/include/sessionstart.php new file mode 100644 index 0000000..fa820ca --- /dev/null +++ b/web/admin/include/sessionstart.php @@ -0,0 +1,12 @@ +Torna alla pagina di accesso.',false); +} + +?> diff --git a/web/admin/index.php b/web/admin/index.php new file mode 100644 index 0000000..2c229ff --- /dev/null +++ b/web/admin/index.php @@ -0,0 +1,59 @@ + + + + +Mastodon Startpage Admin Login + + + + + + + + + + + + +
    +
    +
    +Mastodon Startpage Admin Login +
    +
    +
    + + + + + +
    Nome:
    Password:
    Password dimenticata?
    +
    +
    +
    +
    + + + diff --git a/web/admin/instances.php b/web/admin/instances.php new file mode 100644 index 0000000..033802e --- /dev/null +++ b/web/admin/instances.php @@ -0,0 +1,90 @@ +'.$btl,false); +mysqli_close($link); +if (mysqli_num_rows($res)<1) { + $out='

    Nessuna istanza da mostrare.

    '.N; +} else { + $out=''.N; + while ($row=mysqli_fetch_assoc($res)) { + $out.=''.N; + } + $out.='
    '.$row['URI'].'
    '.N; +} + + +?> + + + +Mastodon Startpage Admin - Main Menu + + + + + + + + + + + + + + +
    +
    + +
    +
    + + + + diff --git a/web/admin/js/alerta.js b/web/admin/js/alerta.js new file mode 100644 index 0000000..b0bc995 --- /dev/null +++ b/web/admin/js/alerta.js @@ -0,0 +1,4 @@ +function alerta(msg) { + document.getElementById('popupcont').innerHTML='

    Attenzione

    '+msg+''; + document.getElementById('popup').style.display='table'; +} diff --git a/web/admin/login.php b/web/admin/login.php new file mode 100644 index 0000000..7c7df0b --- /dev/null +++ b/web/admin/login.php @@ -0,0 +1,36 @@ +Torna al login'; + +$errs=''; + +if (!array_key_exists('username',$_POST) || $_POST['username']=='') + $errs.='Non hai specificato il nome
    '.N; +if (!array_key_exists('password',$_POST) || $_POST['password']=='') + $errs.='Non hai specificato la password
    '.N; +if ($errs!='') muoribene($errs.$btl,false); + +$iniarr=parse_ini_file('sec/mastostartadmin.ini') + or muoribene('Impossibile aprire il file di configurazione.
    '.$btl,false); +$link=mysqli_connect($iniarr['db_host'],$iniarr['db_admin_name'],$iniarr['db_admin_password'],$iniarr['db_name'],$iniarr['db_port'],$iniarr['db_socket']) + or muoribene('Impossibile connettersi al database: '.mysqli_connect_error().' ['.mysqli_connect_errno().']',false); +mysqli_set_charset($link,'utf8'); +$res=mysqli_query($link,'SELECT * FROM Admins WHERE Username=\''.mysqli_real_escape_string($link,$_POST['username']).'\'') + or muoribene(mysqli_error($link).'
    '.$btl,true); +mysqli_close($link); +if (mysqli_num_rows($res)>1) + muoribene('Record admin duplicato.
    '.$btl,false); +$row=mysqli_fetch_assoc($res); +if (mysqli_num_rows($res)<1 || !password_verify($_POST['password'],$row['Password'])) + muoribene('Nome admin e/o password sbagliati.
    '.$btl,false); + +session_name('mastostartadmin'); +session_start(); +$_SESSION['id']=$row['ID']; + +header('Location: instances.php'); + +?> diff --git a/web/admin/sec/.htaccess b/web/admin/sec/.htaccess new file mode 100644 index 0000000..93169e4 --- /dev/null +++ b/web/admin/sec/.htaccess @@ -0,0 +1,2 @@ +Order deny,allow +Deny from all diff --git a/web/admin/sec/mastostartadmin.ini b/web/admin/sec/mastostartadmin.ini new file mode 100644 index 0000000..b634513 --- /dev/null +++ b/web/admin/sec/mastostartadmin.ini @@ -0,0 +1,6 @@ +db_host=localhost +db_port=3306 +db_socket=/run/mysqld/mysqld.sock +db_name=mastostart +db_admin_name=MastoStartAdmin +db_admin_password=MastoStartAdmin diff --git a/web/admin/theme.css b/web/admin/theme.css new file mode 100644 index 0000000..3aa981d --- /dev/null +++ b/web/admin/theme.css @@ -0,0 +1,213 @@ +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} +html { + scroll-behavior: smooth; + height: 100% +} +body { + background-color: white; + color: black; + font-family: Arial, Helvetica, Sans-Serif, sans; + font-size: 14pt; + margin: 0; + padding: 5px; + height: 100% +} +h1,h2,h3,h4,h5,h6 { + text-align: center; +} +a { + text-decoration: none; + color: red; +} +a:hover { + text-decoration: underline; +} +ul { + list-style-type: disc; + padding-left: 0; + margin-left: 14pt; +} +#fullscreen, #fullscreenm { + width: 100%; + height: 100%; + display: table; +} +#fullscreenm { + padding-top: 40px; +} +#middlerow { + display: table-cell; + vertical-align: middle; + text-align: center; +} +#centertit, #centerbox { + font-size: 12pt; + margin-right: auto; + margin-left: auto; + width: 320px; + padding: 5px; +} +#centertit { + font-size: 13pt; + padding: 8px; + background-color: #916f6f; + color: white; + text-shadow: 1px 1px 2px black; + font-weight: bold; + text-align: center; + border-radius: 9px 9px 0 0; +} +#centerbox { + background-color: lightgrey; + border-radius: 0 0 9px 9px; +} +#logintable { + width: 100%; +} +#logintable td { + text-align: right; + width: 1%; +} +#logintable .rtd { + text-align: left; + width: 99%; +} +#logintable .tiptd { + font-size: 10pt; + text-align: center; + width: 100%; + padding-top:10px; + padding-bottom: 10px; +} +input { + width: 100%; + font-size: 11pt; + padding-top: 2px; + padding-bottom: 2px; +} +.button { + font-size: 11pt; + height: 40px; +} +#popup { + z-index: 1; + display: none; + top: 0px; + position: fixed; + width: 100%; + height: 100%; + background-color: rgba(0,0,0,0.75); + color: white; + padding: 0; + font-size: 12pt; +} +#inpopup { + display: table-cell; + vertical-align: middle; +} +#popupcont { + position: relative; + margin-left: auto; + margin-right: auto; + border: 1px solid gray; + width: 200px; + background-color: white; + border-radius: 9px; + color: black; + padding: 5px; + text-align: left; +} +#footer { + color: white; + position: fixed; + height: 40px; + width: 100%; + bottom: 0; + left: 0; + background-color: rgba(0,0,0,0.85); + line-height: 40px; + vertical-align: middle; +} + + +#hmenu { + font-size: 14pt; + background-color: rgba(0,0,0,0.85); + color: white; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 40px; + margin: 0; + padding: 0; + /*box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.4);*/ + /*padding-left: 40px;*/ + z-index: 2; + /*display: none;*/ +} +#hmenu ul { + list-style-type: none; + margin: 0; + padding: 0; + overflow: visible; +} +#hmenu ul li { + width: 80pt; + height: 40px; + text-align: center; + display: table-cell; + vertical-align: middle; + color: #3088D4; +} +#hmenu ul li:hover { + background-color: rgba(255,255,255,0.10); + cursor: default; +} +#hmenu ul li a { + width: 80pt; + line-height: 40px; + display: block; + color: #3088D4; +} +#hmenu .ula { + position: absolute; + top: 40px; + background-color: rgba(0,0,0,0.85); + display: none; +} +#hmenu .ulb { + background-color: rgba(0,0,0,0.85); + left: 80pt; + position: relative; + top: -40px; + display: none; +} +#hmenu .ula li, .ulb li { + width: 80pt; + height: 40px; + display: block; + float: none; + text-align: center; + line-height: 40px; + vertical-align: middle; +} +#hmenu .ula li:hover, .ulb li:hover { + text-decoration: underline; +} +#hmenu .hil { + background-color: rgba(255,255,255,0.10); + color: #97C3E9; +} +#hmenu .hil:hover { + cursor: default; + text-decoration: none; +} +#hmenu .ula li.hil:hover, .ulb li.hil:hover { + text-decoration: none; +} + diff --git a/web/favicon.ico b/web/favicon.ico index 79000c9cc43c2044b5ab5129202e993aa2cf70af..f4ac4da46acd6a383c8aaea7f37c2db6ca30df6e 100644 GIT binary patch literal 9662 zcmdT~ZEO@p7~bpk3$Q>av_ioWpnQ~C3KgQnQ1qyvF&K~pV)(EHN&-XzB-SdiHA+NO zKz|4!geDRNiGqS5n2>NGBtVeh4?zf!97gez0!E=o%lJIk9k|}k&h72(*}G|;dw1S> zKc07Xc6WBcFnsu{s4(z5*w|HK7zKu5j0B)EUIeHQw_%1+>+3*=!u4-1JRb#?0vmw6 zz;{3hXaVj5!aV*N@;LB0unDLEMgaeJn}CGtfK$M~0Qn_?-{HRv2mqMXq_ydYd=f~6 zYb@XXNnoFknER5sYl$>~!D2o_mN&paxhA>;$+^_!0OAu=ACAuGOW(pL;@MBT|?@Ybyo# z479B?#raPMcRugamH%pRzv?yrz?dPTZdzq0P^Zh|V*N87?>&4Ev5oC!{p@;qmgQQc zPM60e|J{hG-7BUz|3l!f-TS0C|I=yC|1$Wu0=8>2#pj>jAi0-FSN?p5(|(I}Gyi*E zn`62EP^X(Gm-ipud$jL?bDt=;aJjp$QS`{ow&inb(-Mo%$qjY3_Kd}t(fc3f*41os z*RKC(#}Bu}WuCI)0%h#n>`d|3?gop`jn5iHPFAMUr+jds#hy8yd89;XA5jzMz9ph> zvA2u;ZtYVRTgF*EW1^A^`K)~IF{RJ@3#Tf5?B*zfFW3M1h`uF$hR-KjcGg?s^L(#c zFeSWa=RUo3P(SfD`fXp`-v_tDhLG!mV{7LH!nX3gVtq}ua_wCGv|cc`jvK}<00&~& zh!5+YzQ;jwaU$vG)_3EgX|cF-{2=gFEdB%g_Eeq&T@9DFuM~ORa>C%T&Nh0C=esDs zrxX7CZWV~dpX0oaTlcJS#DmvwRRGg*m0%AX2`jExfhTCt@lRH~I;K(m4(=X;sDib?a%@oJp zTO`hHSuT#QuN5D!njxN_SSqqHZWoL9PukFyKJ;Y__8F70?R*vbSD=%v2M$2REXgWl7Ia^va1CFB8^8JJ8f(}H$p6C-&v{Lj zExCLEkekz11;fKY8;~qsvEuSuZ4j6YxNQY+TnzAg<4-`WoQaMz2XirJA>eiEgMd}Q zQh?8IUi18h%I}bufDphvE%%1979LX<0%${9`p}m#7;7@X*l{({YWM}Rh#*K&!kdzd zhLSG_l-CV^s1Y)Ro(M|_$e=Gu`rE?sn&8K$5v9>+%3^lVdUc3IhNh+?PCYte5l2vyLeV{|F59LgzpJC@Qc3 literal 9086 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 delta 2232 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 L9Nm$0`vBtaYX8CF delta 2308 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 FKL8Rus4@Tm literal 17377 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 Z8-YIGN5=hL21mS-kx=+jE%q(w{{XxD*S7!w diff --git a/web/imgs/icona-180.png b/web/imgs/icona-180.png new file mode 100644 index 0000000000000000000000000000000000000000..e277cd2e7e81ca0b330b6e8d0eac261924e79b22 GIT binary patch literal 4147 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 MX~VQ?G~jRk54zX%)&Kwi literal 0 HcmV?d00001 diff --git a/web/imgs/icona-32.png b/web/imgs/icona-32.png new file mode 100644 index 0000000000000000000000000000000000000000..11680a15fac32153809aa0e807a19c891d64c8f3 GIT binary patch literal 1005 zcmV^#q1S4(`JeEX8~j;}+y2L_xoA3wqItv$%-A@f&LK z3pz4zrC=4l>QB};POTMHSe=PD#QWn&I#m0hpX)k&GzsJbZCg5d#UzpswDk}m3w2l& zw=C197b+`XXZF0s`uciZI(<~#!CgAqnp6C8@@87Ra-E{NWr84d>GU7!4(@XGpQgC9 z@E7h(V9ikEOCEUAnioHolQ%P^zrD55H}7q5tY$YTU9raF8$XqsUzFn4(bnwS4`1;6 zk5zH$7hr9G?RY+YbkVZao_ceyFq{%Azq_l$j!pN2=iWUaF*PUFueZ0y=dV8GWbOXA z;mRp^12?CSJh5q~g5m{9yRGG-Gsk|`*V|)S{w(2?gt?_Fl$AfGpm;uLJX^2f#1Yxk z@?~Y`f*=SL%`0vhr8YTWrh)Sr^!M#oAkNf_!%}M*h zsoD`|zHq8GB}dcw<8f{W;0u#q3-n?iE52_NmK|WQG{zZ z2<#dIX%A}fvj58XBnFi1#lsnvY*~MzyKtMRnkm9;B>KmQYX1h&!EV4Y{3`lS$cPO$ zm_@~n5{wlI9L*r$hlv&dkBF9XC=uH*eY{D7Gb%sqVsSo?#6Q5 zGg?tki+(o8dgZ2$RshjVw&MIK$xkA0I7I1Nkd7>rV+HQT9hif{LGhh9jZ>ogz8^ms bW}WdbjjGG&N>5dT00000NkvXXu0mjfKAq;2 literal 0 HcmV?d00001 diff --git a/web/imgs/icona-512.png b/web/imgs/icona-512.png new file mode 100644 index 0000000000000000000000000000000000000000..ee1f2392a225c7ea3d919e99e0d2302caaebc4c5 GIT binary patch literal 13433 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 QpN#=cRUMT#N;Z%FA3Y+B$p8QV literal 0 HcmV?d00001 diff --git a/web/index.php b/web/index.php index 53e7d06..c3a3763 100644 --- a/web/index.php +++ b/web/index.php @@ -1,6 +1,6 @@ array('liadd'=>null, 'href'=>$instpath, 'title'=>'Guide', 'selected'=>false, 'submenu'=>null), + 'guide'=>array('liadd'=>null, 'href'=>$instpath.'/', 'title'=>'Guide', 'selected'=>false, 'submenu'=>null), 'instances'=>array('liadd'=>null, 'href'=>$instpath.'/instances', 'title'=>'Instances', 'selected'=>false, 'submenu'=>null), 'about'=>array('liadd'=>null, 'href'=>$instpath.'/about', 'title'=>'About', 'selected'=>false, 'submenu'=>null), 'language'=>array('liadd'=>null, 'href'=>null, 'title'=>'Language', 'selected'=>false, 'submenu'=>array( @@ -25,7 +25,7 @@ function tradmenu($lang) { switch ($lang) { case 'it': $menu['guide']['title']='Guida'; - $menu['guide']['href'].='/it'; + $menu['guide']['href'].='it'; $menu['instances']['title']='Istanze'; $menu['instances']['href'].='/it'; $menu['about']['title']='Info'; @@ -42,6 +42,7 @@ switch($path) { 'fp'=>'home_en.php', 'lang'=>'en', 'atit'=>' - Guide', + 'desc'=>'A thorough introduction to Mastodon', 'js'=>array('shsum','guideanchors','scrolltrack') ); $menu['guide']['liadd']='onclick="shsum()" onmouseover="this.style.cursor=\'pointer\'; this.style.textDecoration=\'underline\'" onmouseout="this.style.textDecoration=\'none\'"'; @@ -56,6 +57,7 @@ switch($path) { 'fp'=>'home_it.php', 'lang'=>'it', 'atit'=>' - Guida', + 'desc'=>'Una approfondita introduzione a Mastodon', 'js'=>array('shsum','guideanchors','scrolltrack') ); tradmenu('it'); @@ -71,6 +73,7 @@ switch($path) { 'fp'=>'instances_en.php', 'lang'=>'en', 'atit'=>' - Instances', + 'desc'=>'Recommended Mastodon Instances', 'js'=>array() ); $menu['instances']['href']=null; @@ -84,6 +87,7 @@ switch($path) { 'fp'=>'instances_it.php', 'lang'=>'it', 'atit'=>' - Istanze', + 'desc'=>'Istanze Mastodon consigliate', 'js'=>array() ); tradmenu('it'); @@ -98,6 +102,7 @@ switch($path) { 'fp'=>'about_en.php', 'lang'=>'en', 'atit'=>' - About us', + 'desc'=>'Infos about Mastodon Startpage’s authors, contributors, license', 'js'=>array() ); $menu['about']['href']=null; @@ -111,6 +116,7 @@ switch($path) { 'fp'=>'about_it.php', 'lang'=>'it', 'atit'=>' - Info', + 'desc'=>'Informazioni sugli autori, i collaboratori e la licenza di Mastodon Startpage', 'js'=>array() ); tradmenu('it'); @@ -125,6 +131,7 @@ switch($path) { 'fp'=>'404.php', 'lang'=>'en', 'atit'=>' - 404', + 'desc'=>'Page not found', 'js'=>array() ); break; @@ -178,9 +185,12 @@ $cjrand=rand(0,999999); Mastodon Startpage<?php echo($cont['atit']); ?> - + - + + + +