diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000000000000000000000000000000000..b0329d6531a58afd8ad0d8eaa86a4a1e78788354 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,102 @@ +# Changelog +The format is based on [Keep a Changelog] and this project adheres to [Semantic Versioning]. + +## [2.4.0] - 2018-09-03 +:exclamation: DB migrations required! (see [SQL migration script][2.4.0-sql-migration]) +:exclimation: config.php rewritten - requires migration +### Added +- Added bootstrapping to simplify initialisation of config and database +- Config syntax has changed to array style (#155) +- Added `pghost` config to set database port +- Added `CONTRIBUTING.md` +- Podmin can choose at what fail score to send the notice out +- Podmin email shares details on why pod is failing +- Only retrieve location data for remote servers / IPs +- Fontawesome for icons +### Changed +- Introduce proper changelog format (#189) +- Moved DB migration scripts into `db` folder +- Use Curl for all http calls +- Use filter dropdowns for pre-defined columns +- Use pretty URLs (see nginx.example) +- Open pod URLs in a new tab +- Use detectlanguage.com API for language guess +- Only use JSON data, ignore HTML when returned +- Allow curl redirect on home page check +- Score now goes to -5000 before a pod is removed so dead pods get checked a while then removed for good +- Move functions to dedicated file to allow reuse +- Backup script rewrite +- Store services as json array +- Paging can be changed to some or all on advanced view +### Deprecated +### Removed +### Fixed +- Notify podmins just once at 50 when pod failing (#186) +- Add missing meta and PHP module requirements to `composer.json` +### Security + +## [2.3.1] - 2018-08-05 +### Added +- Podmins can link directly to their pod via `https://podupti.me/domain.name` for stats and to allow users to rate easier +- Wizard to help you filter the columns to what you need (#145) +- Cookie used to remember last pod you clicked +### Changed +- Now one table with a basic default view you can customize (#171) +- Switch to a library for country to lat long lookup +- Switch GeoIP from built in PHP to library and use newer Maxmind database file + +## [2.3.0] - 2018-07-19 +:exclamation: DB migrations required! (see [SQL migration script][2.2.0-sql-migration]) +### Added +- Language is detected based on your homepage, edit your homepage to non-en if that is what you use +- Add development and release dates to `masterversions` table (#143) +- Store full country name, store days monitored each pod (#150) +- Store detectedlanguage (#144) +- Show version and update in full view cleaner (#143) +- Filter and search on the columns of data (#147) +- Paginate the results so they fit per page (#147) +### Changed +- Podmins can no longer access `db/pull.php` to test their pod, they can however get to a debug screen from the edit pod area +- Edit will send to email on file and be less delay, runner of site does not really have any way to verify email address +- Default new pods to `UP` to be checked +- Use the git API for release versions, check development releases on pods (#143) +- Move from [bower to yarn](https://bower.io/blog/2017/how-to-migrate-away-from-bower/) for packages +- Move to PHP 7.2 with strict typing +- Move to [Eslint compliance](https://eslint.org/docs/rules/) +- Move to [PSR-2 compliance](https://www.php-fig.org/psr/psr-2/) +- NOTE `config.php.example` change to full paths for 2 items! +- Show time as human readable everywhere (#150) +### Removed +- Unused `hidden` and `secure` columns (#140, #141) +### Fixed +- Rename table `rating_comments` to `ratingcomments` for redbean support (#146) +### Security +- Forbid access to files that should be CLI only (#152) + +## [2.2.0] - 2018-05-12 +:exclamation: DB migrations required! (see [SQL migration script][2.2.0-sql-migration]) +### Added +- Podmins can now pause/unpause or delete from podmin area +- Graph on user growth on the network +- Add monthly stats table +### Changed +- `go.php` auto select picks a more stable pod than before +- Make map prettier +- Use lines on tables to make them more readable +- Don't delete dead pods, keep them and data for history hide them for users +- Put daily tasks in the `pull.sh` and run each day +- Update status to 1-5 rather than text +### Fixed +- Fix ipv6 + +[2.4.0-sql-migration]: https://git.feneas.org/diasporg/Poduptime/blob/master/db/migrations/2.3.0-2.4.0.sql +[2.3.0-sql-migration]: https://git.feneas.org/diasporg/Poduptime/blob/master/db/migrations/2.2.0-2.3.0.sql +[2.2.0-sql-migration]: https://git.feneas.org/diasporg/Poduptime/blob/master/db/migrations/2.1.4-2.2.0.sql + +[Unreleased]: https://git.feneas.org/diasporg/Poduptime/compare/master...develop +[2.3.1]: https://git.feneas.org/diasporg/Poduptime/compare/2.3.0...2.3.1 +[2.3.0]: https://git.feneas.org/diasporg/Poduptime/compare/v2.2.0...2.3.0 +[2.2.0]: https://git.feneas.org/diasporg/Poduptime/compare/2.1.3...v2.2.0 + +[Keep a Changelog]: https://keepachangelog.com/ +[Semantic Versioning]: https://semver.org/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000000000000000000000000000000000..c9f1111bca691db6b72146869ca6fab19ebc2177 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,31 @@ +# How To Contribute + +## Workflow + +* Fork Git Repo https://git.feneas.org/diasporg/Poduptime +* Pull Git +* Create a topic branch to work from +* Commit and push your branch up +* Create a Merge Request to the develop branch + +## Guidelines + +* Note your changes in [`CHANGELOG.md`] following https://keepachangelog.com +* Create any necessary DB migration script in [`db/migrations`] and note them in the changelog. +* Update [`README.md`] with needed changes +* Update the [Wiki] with API changes +* Write your tests and validate them before you do your MR + +## Coding Style + +* PHP follows [PSR-2] +* CSS follows [CSSLint] +* JS follows [ESLint] + +[`README.md`]: https://git.feneas.org/diasporg/Poduptime/blob/master/README.md +[`CHANGELOG.md`]: https://git.feneas.org/diasporg/Poduptime/blob/master/CHANGELOG.md +[`db/migrations`]: https://git.feneas.org/diasporg/Poduptime/tree/master/db/migrations +[Wiki]: https://git.feneas.org/diasporg/Poduptime/wikis/home +[PSR-2]: https://www.php-fig.org/psr/psr-2/ +[CSSLint]: https://github.com/CSSLint/csslint +[ESLint]: https://eslint.org/docs/rules/ diff --git a/README.md b/README.md index 9e0521ca1665cfb8af2cb223887920481f6315a2..4126453a8a899fc75b2a5f81dbf4e790534aeb7d 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,8 @@ Environmental items you need (debian based system assumed): OS Dependencies: ``` -php7.2 php7.2-curl php7.2-pgsql php-geoip php7.2-cli php7.2-common php7.2-bcmath php7.2-json php7.2-readline php7.2-mbstring php7.2-xml php-cgi git curl postgresql postgresql-contrib dnsutils bind9 npm nodejs composer +php7.2 php7.2-curl php7.2-pgsql php7.2-bcmath php-geoip php7.2-cli php7.2-common php7.2-bcmath php7.2-json php7.2-readline php7.2-mbstring php7.2-xml php-cgi git curl postgresql postgresql-contrib dnsutils bind9 npm nodejs composer ``` -GeoIP needs setup normally with a dat file Yarn is a separate install: https://yarnpkg.com @@ -54,13 +53,14 @@ run `db/pull.sh debug` to debug output run `db/pull.sh sqldebug` to debug sql run `db/pull.sh develop` to run without email alerts to end users run `db/pull.sh Check_System_Deleted` to re-check system deleted pods as needed +These commands can be combined # To Upgrade: ``` git pull yarn install composer install -psql -U podupuser podupdb < db/migrationXXX.sql (see db/version.md for proper migration versions) +psql -U podupuser podupdb < db/migrations/xxx.sql (see db/migrations/README.md for proper migration versions) ``` # Status diff --git a/api.php b/api.php index 0baeca5974bbe50b0dcbc114c138c477d3b96682..477ac6b06f291a7be1e0061d00f9895bbb0c84c5 100644 --- a/api.php +++ b/api.php @@ -15,15 +15,7 @@ $_format = $_GET['format'] ?? ''; $_method = $_GET['method'] ?? ''; $_callback = $_GET['callback'] ?? ''; -require_once __DIR__ . '/vendor/autoload.php'; -require_once __DIR__ . '/config.php'; - -define('PODUPTIME', microtime(true)); - -// Set up global DB connection. -R::setup("pgsql:host={$pghost};dbname={$pgdb}", $pguser, $pgpass, true); -R::testConnection() || die('Error in DB connection'); -R::usePartialBeans(true); +require_once __DIR__ . '/boot.php'; if ($_format === 'georss') { echo <<=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*" + }, + "type": "library", + "autoload": { + "psr-0": { + "DetectLanguage": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurynas Butkus" + } + ], + "description": "Language Detection API PHP Client", + "homepage": "https://github.com/detectlanguage/detectlanguage-php", + "keywords": [ + "api", + "client", + "detect", + "detection", + "language" + ], + "time": "2018-03-28T20:56:36+00:00" }, { "name": "gabordemooij/redbean", @@ -195,16 +243,16 @@ }, { "name": "jaybizzle/crawler-detect", - "version": "v1.2.65", + "version": "v1.2.66", "source": { "type": "git", "url": "https://github.com/JayBizzle/Crawler-Detect.git", - "reference": "1ea1c897018c93e3c2ac76e008519085b24e339e" + "reference": "55ad4b140d821c19dbaf1a6ea9d9e5ca6444ecc1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/JayBizzle/Crawler-Detect/zipball/1ea1c897018c93e3c2ac76e008519085b24e339e", - "reference": "1ea1c897018c93e3c2ac76e008519085b24e339e", + "url": "https://api.github.com/repos/JayBizzle/Crawler-Detect/zipball/55ad4b140d821c19dbaf1a6ea9d9e5ca6444ecc1", + "reference": "55ad4b140d821c19dbaf1a6ea9d9e5ca6444ecc1", "shasum": "" }, "require": { @@ -240,7 +288,63 @@ "crawlerdetect", "php crawler detect" ], - "time": "2018-07-24T17:53:06+00:00" + "time": "2018-07-30T20:23:10+00:00" + }, + { + "name": "longman/ip-tools", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/akalongman/php-ip-tools.git", + "reference": "6c050dfbf91811d14b9b3aa31fb7116eac0f0a18" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/akalongman/php-ip-tools/zipball/6c050dfbf91811d14b9b3aa31fb7116eac0f0a18", + "reference": "6c050dfbf91811d14b9b3aa31fb7116eac0f0a18", + "shasum": "" + }, + "require": { + "ext-bcmath": "*", + "php": ">=5.5" + }, + "require-dev": { + "phpspec/phpspec": "~2.1", + "phpunit/phpunit": "~4.1", + "squizlabs/php_codesniffer": "~2.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Longman\\IPTools\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Avtandil Kikabidze aka LONGMAN", + "email": "akalongman@gmail.com", + "homepage": "https://longman.me", + "role": "Developer" + } + ], + "description": "PHP IP Tools for manipulation with IPv4 and IPv6", + "homepage": "https://github.com/akalongman/php-ip-tools", + "keywords": [ + "IP", + "Match", + "compare", + "ipv4", + "ipv6", + "mask", + "subnet", + "tools", + "utilities" + ], + "time": "2016-10-23T20:08:46+00:00" }, { "name": "matriphe/iso-639", @@ -390,16 +494,16 @@ }, { "name": "nesbot/carbon", - "version": "1.32.0", + "version": "1.33.0", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "64563e2b9f69e4db1b82a60e81efa327a30ff343" + "reference": "55667c1007a99e82030874b1bb14d24d07108413" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/64563e2b9f69e4db1b82a60e81efa327a30ff343", - "reference": "64563e2b9f69e4db1b82a60e81efa327a30ff343", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/55667c1007a99e82030874b1bb14d24d07108413", + "reference": "55667c1007a99e82030874b1bb14d24d07108413", "shasum": "" }, "require": { @@ -441,7 +545,7 @@ "datetime", "time" ], - "time": "2018-07-05T06:59:26+00:00" + "time": "2018-08-07T08:39:47+00:00" }, { "name": "noplanman/xec", @@ -496,30 +600,37 @@ "time": "2017-03-12T19:16:23+00:00" }, { - "name": "patrickschur/language-detection", - "version": "v3.3.0", + "name": "rinvex/country", + "version": "v3.1.0", "source": { "type": "git", - "url": "https://github.com/patrickschur/language-detection.git", - "reference": "21a2e7a1b9bf6bff578ac11c6dcf3d3668aeccdf" + "url": "https://github.com/rinvex/country.git", + "reference": "e32228ef43f26d3b02296be9454f842c52d492f3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/patrickschur/language-detection/zipball/21a2e7a1b9bf6bff578ac11c6dcf3d3668aeccdf", - "reference": "21a2e7a1b9bf6bff578ac11c6dcf3d3668aeccdf", + "url": "https://api.github.com/repos/rinvex/country/zipball/e32228ef43f26d3b02296be9454f842c52d492f3", + "reference": "e32228ef43f26d3b02296be9454f842c52d492f3", "shasum": "" }, "require": { - "ext-mbstring": "*", - "php": "^7" + "php": "^7.0.0" }, "require-dev": { - "phpunit/phpunit": "^6" + "phpunit/phpunit": "^5.4.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, "autoload": { + "files": [ + "src/helpers.php" + ], "psr-4": { - "LanguageDetection\\": "src/LanguageDetection" + "Rinvex\\Country\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -528,18 +639,39 @@ ], "authors": [ { - "name": "Patrick Schur", - "email": "patrick_schur@outlook.de" + "name": "Rinvex LLC", + "email": "help@rinvex.com", + "homepage": "https://rinvex.com" + }, + { + "name": "Abdelrahman Omran", + "email": "me@omranic.com", + "homepage": "https://omranic.com", + "role": "Project Lead" + }, + { + "name": "The Generous Laravel Community", + "homepage": "https://github.com/rinvex/country/contributors" } ], - "description": "A language detection library for PHP. Detects the language from a given text string.", - "homepage": "https://github.com/patrickschur/language-detection", + "description": "Rinvex Country is a simple and lightweight package for retrieving country details with flexibility. A whole bunch of data including name, demonym, capital, iso codes, dialling codes, geo data, currencies, flags, emoji, and other attributes for all 250 countries worldwide at your fingertips.", + "homepage": "https://rinvex.com", "keywords": [ - "detect", - "detection", - "language" + "Flexible", + "Simple", + "countries", + "country", + "currencies", + "demonym", + "dialling", + "emoji", + "flags", + "geographic", + "languages", + "rinvex", + "svg" ], - "time": "2018-02-01T17:12:47+00:00" + "time": "2017-03-07T18:40:20+00:00" }, { "name": "rinvex/country", @@ -617,16 +749,16 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.8.0", + "version": "v1.9.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "3296adf6a6454a050679cde90f95350ad604b171" + "reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/3296adf6a6454a050679cde90f95350ad604b171", - "reference": "3296adf6a6454a050679cde90f95350ad604b171", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d0cd638f4634c16d8df4508e847f14e9e43168b8", + "reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8", "shasum": "" }, "require": { @@ -638,7 +770,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8-dev" + "dev-master": "1.9-dev" } }, "autoload": { @@ -672,20 +804,20 @@ "portable", "shim" ], - "time": "2018-04-26T10:06:28+00:00" + "time": "2018-08-06T14:22:27+00:00" }, { "name": "symfony/translation", - "version": "v4.1.2", + "version": "v4.1.4", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "2dd74d6b2dcbd46a93971e6ce7d245cf3123e957" + "reference": "fa2182669f7983b7aa5f1a770d053f79f0ef144f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/2dd74d6b2dcbd46a93971e6ce7d245cf3123e957", - "reference": "2dd74d6b2dcbd46a93971e6ce7d245cf3123e957", + "url": "https://api.github.com/repos/symfony/translation/zipball/fa2182669f7983b7aa5f1a770d053f79f0ef144f", + "reference": "fa2182669f7983b7aa5f1a770d053f79f0ef144f", "shasum": "" }, "require": { @@ -741,22 +873,22 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2018-07-23T08:20:20+00:00" + "time": "2018-08-07T12:45:11+00:00" } ], "packages-dev": [ { "name": "squizlabs/php_codesniffer", - "version": "3.3.0", + "version": "3.3.1", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "d86873af43b4aa9d1f39a3601cc0cfcf02b25266" + "reference": "628a481780561150481a9ec74709092b9759b3ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/d86873af43b4aa9d1f39a3601cc0cfcf02b25266", - "reference": "d86873af43b4aa9d1f39a3601cc0cfcf02b25266", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/628a481780561150481a9ec74709092b9759b3ec", + "reference": "628a481780561150481a9ec74709092b9759b3ec", "shasum": "" }, "require": { @@ -794,7 +926,7 @@ "phpcs", "standards" ], - "time": "2018-06-06T23:58:19+00:00" + "time": "2018-07-26T23:47:18+00:00" } ], "aliases": [], @@ -803,7 +935,12 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.2" + "php": "^7.2", + "ext-curl": "*", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-bcmath": "*" }, "platform-dev": [], "platform-overrides": { diff --git a/config.php.example b/config.php.example index ea36e923c83f4c20ae832710e6e357fd9d71f997..07c4c3251863811171f1254b317bc52282da39f4 100644 --- a/config.php.example +++ b/config.php.example @@ -4,38 +4,46 @@ * Config for Poduptime. */ -//backup directory - full dir path -$backup_dir = __DIR__ . '/backup'; +return [ + //backup directory - full dir path + 'backup_dir' => __DIR__ . '/backup', -//log directory - full dir path -$log_dir = __DIR__ . '/log'; + //log directory - full dir path + 'log_dir' => __DIR__ . '/log', -//location of pg dump - full dir path -$pg_dump_dir = '/usr/bin'; + //location of pg dump - full dir path + 'pg_dump_dir' => '/usr/bin', -//db host -$pghost = 'localhost'; + //db host + 'pghost' => 'localhost', -//db username -$pguser = ''; + //db port + 'pgport' => 5432, -//db password -$pgpass = ''; + //db username + 'pguser' => '', -//db name -$pgdb = ''; + //db password + 'pgpass' => '', -//admin email for forms -$adminemail = ''; + //db name + 'pgdb' => '', -//DNS server for dnssec testing. 1.1.1.1 tests the best -$dnsserver = ''; + //admin email for forms + 'adminemail' => '', -//CA for curl to use - full file path (pull.sh will update this monthly) -$cafullpath = ''; + //DNS server for dnssec testing. 1.1.1.1 tests the best + 'dnsserver' => '', -//Mapbox.com API key. https://www.mapbox.com/help/how-access-tokens-work/ -$mapboxkey = ''; + //CA for curl to use - full file path (pull.sh will update this monthly) + 'cafullpath' => '', -//Geolite2-city database file in mmdb format - full file path (pull.sh will update this monthly) -$geoip2db = ''; + //Mapbox.com API key. https://www.mapbox.com/help/how-access-tokens-work/ + 'mapboxkey' => '', + + //Geolite2-city database file in mmdb format - full file path (pull.sh will update this monthly) + 'geoip2db' => '', + + //detectlanguage.com api key + 'dlkey' => '', +]; diff --git a/css/poduptime.css b/css/poduptime.css index e8a1b4900eae1d2c901dfd731e841c7eacea22a4..424f33dcd8da33d20559735e341cba17befd0413 100644 --- a/css/poduptime.css +++ b/css/poduptime.css @@ -1,3 +1,45 @@ +@import url("/node_modules/typeface-roboto/index.css"); + +body { + font-family: 'Roboto', sans-serif; + font-weight: 400; + --blue: #303030; + --grey: #4e89a4; + --green: #6B8E23; +} + +.bg-blue { + background-color: var(--blue) !important; +} + +.blue { + color: var(--blue); +} + +.bg-green { + background-color: var(--green); +} + +.green { + color: var(--green); +} + +.bg-grey { + background-color: var(--grey); +} + +.grey { + color: var(--grey); +} + +a { + color: var(--blue); +} + +.tablesorter-header { + background-color: var(--grey) !important; +} + .main { padding: 5px; } @@ -25,35 +67,8 @@ } .smlogo { - width: 16px; - height: 16px; - background: url('/images/smlogo.png') 0 0; - display: inline-block; - margin: 0; -} - -.smlogo-twitter { - background-position: 0 -776px; -} - -.smlogo-facebook { - background-position: 0 -824px; -} - -.smlogo-tumblr { - background-position: 0 -792px; -} - -.smlogo-wordpress { - background-position: 0 -656px; -} - -.smlogo-xmpp { background: none; -} - -.smlogo-xmpp img { - vertical-align: unset; + display: inline-block; } #map { diff --git a/db/add.php b/db/add.php index e4e6e5576ad1f96fd0979fe16c4731a74907eb9c..a72e7a72e21ec856d83938f5966e9edf0c7afd42 100644 --- a/db/add.php +++ b/db/add.php @@ -8,9 +8,9 @@ declare(strict_types=1); use RedBeanPHP\R; -require_once __DIR__ . '/../vendor/autoload.php'; -require_once __DIR__ . '/../config.php'; +require_once __DIR__ . '/../boot.php'; +<<<<<<< HEAD define('PODUPTIME', microtime(true)); @@ -23,11 +23,15 @@ R::usePartialBeans(true); if (!($_domain = $_GET['domain'] ?? null)) { die('no pod domain given'); } +======= +($_domain = $_GET['domain'] ?? null) || die('no pod domain given'); +>>>>>>> develop // Other parameters. -$_email = $_GET['email'] ?? ''; -$_podmin_statement = $_GET['podmin_statement'] ?? ''; -$_podmin_notify = $_GET['podmin_notify'] ?? 0; +$_email = $_GET['email'] ?? ''; +$_podmin_statement = $_GET['podmin_statement'] ?? ''; +$_podmin_notify = $_GET['podmin_notify'] ?? 0; +$_podmin_notify_level = $_GET['podmin_notify_level'] ?? 50; $_domain = strtolower($_domain); if (!filter_var(gethostbyname($_domain), FILTER_VALIDATE_IP)) { @@ -43,6 +47,7 @@ try { die('Error in SQL query: ' . $e->getMessage()); } +$stop = false; foreach ($pods as $pod) { if ($pod['domain'] === $_domain) { if ($pod['email']) { @@ -69,6 +74,7 @@ foreach ($pods as $pod) { } echo << window.onload = function() { $("#weight").ionRangeSlider(); @@ -86,11 +92,35 @@ foreach ($pods as $pod) { EOF; $stop = 1; +======= + +
+ + + +
+
+
+
+ +
+EOF; + + $stop = true; +>>>>>>> develop } } if (!$stop) { +<<<<<<< HEAD +======= +>>>>>>> develop $link = 'https://' . $_domain . '/nodeinfo/1.0'; if ($infos = file_get_contents('https://' . $_domain . '/.well-known/nodeinfo')) { $info = json_decode($infos, true); @@ -111,6 +141,7 @@ if (!$stop) { echo 'Your pod has ssl and is valid
'; $publickey = md5(uniqid($_domain, true)); +<<<<<<< HEAD try { $p = R::dispense('pods'); @@ -130,6 +161,28 @@ if (!$stop) { $subject = 'New pod added to ' . $_SERVER['HTTP_HOST']; $headers = ['From: ' . $_email, 'Reply-To: ' . $_email, 'Cc: ' . $_email]; +======= + + try { + $p = R::dispense('pods'); + $p['domain'] = $_domain; + $p['email'] = $_email; + $p['podmin_statement'] = $_podmin_statement; + $p['podmin_notify'] = $_podmin_notify; + $p['podmin_notify_level'] = $_podmin_notify_level; + $p['publickey'] = $publickey; + + R::store($p); + } catch (\RedBeanPHP\RedException $e) { + die('Error in SQL query: ' . $e->getMessage()); + } + + if ($_email) { + $to = c('adminemail'); + $subject = 'New pod added to ' . $_SERVER['HTTP_HOST']; + $headers = ['From: ' . $_email, 'Reply-To: ' . $_email, 'Cc: ' . $_email]; + +>>>>>>> develop $message_lines = [ 'https://' . $_SERVER['HTTP_HOST'], 'Your pod ' . $_domain . ' will not show up right away, as it needs to pass a few checks first.', @@ -144,4 +197,8 @@ if (!$stop) { } else { echo 'Could not validate your pod, check your setup!
Take a look at your /nodeinfo'; } -} \ No newline at end of file +<<<<<<< HEAD +} +======= +} +>>>>>>> develop diff --git a/db/api-more.php b/db/api-more.php index b76d5bf494dff7caeee376cb635f6a9ab0505976..932911a48ee2087d8543150199f4924f797f134f 100644 --- a/db/api-more.php +++ b/db/api-more.php @@ -15,15 +15,7 @@ use RedBeanPHP\R; // Other parameters. $_format = $_GET['format'] ?? ''; -require_once __DIR__ . '/../vendor/autoload.php'; -require_once __DIR__ . '/../config.php'; - -define('PODUPTIME', microtime(true)); - -// Set up global DB connection. -R::setup("pgsql:host={$pghost};dbname={$pgdb}", $pguser, $pgpass, true); -R::testConnection() || die('Error in DB connection'); -R::usePartialBeans(true); +require_once __DIR__ . '/../boot.php'; try { $pod = R::getRow(' diff --git a/db/backup.php b/db/backup.php index 6b337d2f31b4d7ab2ce7a121dca6e6e1ed27ad62..446ac856deeefb04d2a83c9a893d696d78d32a8c 100644 --- a/db/backup.php +++ b/db/backup.php @@ -6,25 +6,45 @@ declare(strict_types=1); -if (PHP_SAPI !== 'cli') { +require_once __DIR__ . '/../boot.php'; + +if (!is_cli()) { header('HTTP/1.0 403 Forbidden'); exit; } -require_once __DIR__ . '/../config.php'; +$keep_for = 60 * 60 * 6; // 6 hours +$backup_file = c('backup_dir') . '/dump_' . date('Ymd_His') . '.sql'; + +printf("Making backup of '%s' to '%s'...", c('pgdb'), $backup_file); +system(sprintf( + 'export PGPASSWORD=%3$s &&' . + '"%1$s" --clean --format=tar --username=%2$s %4$s >> "%5$s"', + c('pg_dump_dir') . '/pg_dump', + c('pguser'), + c('pgpass'), + c('pgdb'), + $backup_file +), $exit_code); +printf(" %s\n", $exit_code === 0 ? 'Success!' : 'Failed.'); -$keep = (60 * 60 * 6) * 1; -$dump_date = date('Ymd_Hs'); -$file_name = $backup_dir . '/dump_' . $dump_date . '.sql'; -system("export PGPASSWORD=$pgpass && $pg_dump_dir/pg_dump --clean --format=tar --username=$pguser $pgdb >> $file_name"); -echo "pg backup of $pgdb made"; -$dirh = dir($backup_dir); +$dirh = dir(c('backup_dir')); while ($entry = $dirh->read()) { - $old_file_time = (date('U') - $keep); - $file_created = filectime("$backup_dir/$entry"); - if ($file_created < $old_file_time && !is_dir($entry)) { - if (unlink("$backup_dir/$entry")) { - echo 'Cleaned up old backups'; - } + $file = c('backup_dir') . "/{$entry}"; + + // Skip dotfiles and non-files (folders, symlinks, etc.). + if ($entry[0] === '.' || !is_file($file)) { + continue; } + + if (filectime($file) + $keep_for > time()) { + //echo "Don't delete {$entry}\n"; + continue; + } + + printf( + "Removing old file '%s'... %s\n", + $entry, + unlink($file) ? 'Success!' : 'Failed.' + ); } diff --git a/db/edit.php b/db/edit.php index 3399b973326688e0724d4383b34d31295c1dfc0c..55772619815a2413863de0aa97057237bb6ebb02 100644 --- a/db/edit.php +++ b/db/edit.php @@ -16,14 +16,14 @@ use RedBeanPHP\R; strlen($_token) > 6 || die('bad token'); // Other parameters. -$_action = $_GET['action'] ?? ''; -$_weight = $_GET['weight'] ?? 10; -$_email = $_GET['email'] ?? ''; -$_podmin_statement = $_GET['podmin_statement'] ?? ''; -$_podmin_notify = $_GET['podmin_notify'] ?? 0; +$_action = $_GET['action'] ?? ''; +$_weight = $_GET['weight'] ?? 10; +$_email = $_GET['email'] ?? ''; +$_podmin_statement = $_GET['podmin_statement'] ?? ''; +$_podmin_notify = $_GET['podmin_notify'] ?? 0; +$_podmin_notify_level = $_GET['podmin_notify_level'] ?? 50; -require_once __DIR__ . '/../vendor/autoload.php'; -require_once __DIR__ . '/../config.php'; +require_once __DIR__ . '/../boot.php'; // Set up global DB connection. R::setup("pgsql:host={$pghost};dbname={$pgdb}", $pguser, $pgpass, true); @@ -78,10 +78,12 @@ if ('save' === $_action) { $_weight <= 10 || die('10 is max weight'); try { - $pod['email'] = $_email; - $pod['weight'] = $_weight; - $pod['podmin_statement'] = $_podmin_statement; - $pod['podmin_notify'] = $_podmin_notify; + $pod['email'] = $_email; + $pod['weight'] = $_weight; + $pod['podmin_statement'] = $_podmin_statement; + $pod['podmin_notify'] = $_podmin_notify; + $pod['podmin_notify_level'] = $_podmin_notify_level; + R::store($pod); } catch (\RedBeanPHP\RedException $e) { @@ -89,7 +91,7 @@ if ('save' === $_action) { } $to = $_email; - $headers = ['From: ' . $adminemail, 'Cc: ' . $pod['email'], 'Bcc: ' . $adminemail]; + $headers = ['From: ' . c('adminemail'), 'Cc: ' . $pod['email'], 'Bcc: ' . c('adminemail')]; $subject = 'Edit notice from poduptime'; $message = 'Data for ' . $_domain . ' updated. If it was not you reply and let me know!'; @mail($to, $subject, $message, implode("\r\n", $headers)); @@ -103,6 +105,7 @@ if ('save' === $_action) { Authorized to edit for diffForHumans(null, true); ?>
@@ -114,6 +117,8 @@ Authorized to edit for Podmin Statement (You can use HTML to include links to your terms and policies and information about your pod you wish to share with users.)



+
+
@@ -149,4 +154,4 @@ Authorized to edit for "/> Do a debug pull of your pod. Won't update the database just show what it would look like on a pass. - \ No newline at end of file + diff --git a/db/gettoken.php b/db/gettoken.php index 3427ed09264e67986b1c90ec04f6c7b8590a39e1..0e96f2b9077e4ef1752e3c82f5516fa3989304ba 100644 --- a/db/gettoken.php +++ b/db/gettoken.php @@ -14,8 +14,7 @@ use RedBeanPHP\R; // Other parameters. $_email = $_GET['email'] ?? ''; -require_once __DIR__ . '/../vendor/autoload.php'; -require_once __DIR__ . '/../config.php'; +require_once __DIR__ . '/../boot.php'; // Set up global DB connection. R::setup("pgsql:host={$pghost};dbname={$pgdb}", $pguser, $pgpass, true); @@ -33,7 +32,7 @@ try { // Set up common variables. $uuid = md5(uniqid($_domain, true)); $link = sprintf('https://%1$s/?edit&domain=%2$s&token=%3$s', $_SERVER['HTTP_HOST'], $_domain, $uuid); -$headers = ['From: ' . $adminemail]; +$headers = ['From: ' . c('adminemail')]; $message_lines = []; if ($_email) { @@ -41,7 +40,7 @@ if ($_email) { $to = $_email; $subject = 'Temporary edit key for ' . $_SERVER['HTTP_HOST']; - $headers[] = 'Bcc: ' . $adminemail; + $headers[] = 'Bcc: ' . c('adminemail'); $expire = time() + 8700; $output = 'Link sent to your email.'; } elseif (!$pod['email']) { @@ -49,7 +48,7 @@ if ($_email) { } else { $to = $pod['email']; $subject = 'Temporary edit key for ' . $_SERVER['HTTP_HOST']; - $headers[] = 'Bcc: ' . $adminemail; + $headers[] = 'Bcc: ' . c('adminemail'); $message_lines[] = 'Looks like you did not enter your email address, be sure to update it if you forgot the one we have for you.'; $message_lines[] = 'Email found: ' . $pod['email']; $expire = time() + 8700; diff --git a/db/migration00001.sql b/db/migrations/1.0.0-2.0.0.sql similarity index 99% rename from db/migration00001.sql rename to db/migrations/1.0.0-2.0.0.sql index 07d7e3b3fbcfa86089c932736d289e271711fb3a..71b323212b757dac13f267b04829bbebd9ebee5f 100644 --- a/db/migration00001.sql +++ b/db/migrations/1.0.0-2.0.0.sql @@ -5,7 +5,6 @@ ALTER TABLE pods RENAME COLUMN pingdomurl TO stats_apikey; ALTER TABLE pods RENAME COLUMN xmpp TO service_xmpp; ALTER TABLE pods RENAME COLUMN uptimelast7 TO uptime_alltime; ALTER TABLE pods RENAME COLUMN responsetimelast7 TO latency; - ALTER TABLE pods RENAME COLUMN dateUpdated TO date_updated; ALTER TABLE pods RENAME COLUMN dateLaststats TO date_laststats; ALTER TABLE pods RENAME COLUMN dateCreated TO date_created; diff --git a/db/migration00002.sql b/db/migrations/2.0.0-2.1.0.sql similarity index 100% rename from db/migration00002.sql rename to db/migrations/2.0.0-2.1.0.sql diff --git a/db/migration00003.sql b/db/migrations/2.1.0-2.1.3.sql similarity index 100% rename from db/migration00003.sql rename to db/migrations/2.1.0-2.1.3.sql diff --git a/db/migration00004.sql b/db/migrations/2.1.4-2.2.0.sql similarity index 100% rename from db/migration00004.sql rename to db/migrations/2.1.4-2.2.0.sql diff --git a/db/migration00005.sql b/db/migrations/2.2.0-2.3.0.sql similarity index 100% rename from db/migration00005.sql rename to db/migrations/2.2.0-2.3.0.sql diff --git a/db/migrations/2.3.0-2.4.0.sql b/db/migrations/2.3.0-2.4.0.sql new file mode 100644 index 0000000000000000000000000000000000000000..6a2abc29f4be131ff9b882a8abb0584252dd0416 --- /dev/null +++ b/db/migrations/2.3.0-2.4.0.sql @@ -0,0 +1,3 @@ +ALTER TABLE pods ADD services jsonb; +ALTER TABLE pods DROP COLUMN service_facebook, DROP COLUMN service_wordpress, DROP COLUMN service_tumblr, DROP COLUMN service_twitter; +ALTER TABLE pods ADD podmin_notify_level int DEFAULT 50; diff --git a/db/migrations/README.md b/db/migrations/README.md new file mode 100644 index 0000000000000000000000000000000000000000..426c0306417a9bd5ce151edf2a75fdaeaafa4a55 --- /dev/null +++ b/db/migrations/README.md @@ -0,0 +1,17 @@ +# Migrations + +## New install + +When setting up a new install, import [`db/tables.sql`] and do not perform any migrations! + +## Migrating + +If you are upgrading your existing installation, execute the necessary migrations scripts found in [`db/migrations`]. + +## API v1 + +To support the original API v1 you should import [`db/pods_apiv1.sql`] into your DB as often as you want your API updated. + +[`db/tables.sql`]: https://git.feneas.org/diasporg/Poduptime/blob/master/db/tables.sql +[`db/migrations`]: https://git.feneas.org/diasporg/Poduptime/tree/master/db/migrations +[`db/pods_apiv1.sql`]: https://git.feneas.org/diasporg/Poduptime/blob/master/db/pods_apiv1.sql diff --git a/db/monthly_stats.php b/db/monthly_stats.php index 0952acce561f5c6fed2fd8d1ebdf111275927218..5bead76651f5d41c46df79b73100359f576be270 100644 --- a/db/monthly_stats.php +++ b/db/monthly_stats.php @@ -6,22 +6,14 @@ declare(strict_types=1); -if (PHP_SAPI !== 'cli') { - header('HTTP/1.0 403 Forbidden'); - exit; -} - use RedBeanPHP\R; -require_once __DIR__ . '/../vendor/autoload.php'; -require_once __DIR__ . '/../config.php'; - -define('PODUPTIME', microtime(true)); +require_once __DIR__ . '/../boot.php'; -// Set up global DB connection. -R::setup("pgsql:host={$pghost};dbname={$pgdb}", $pguser, $pgpass, true); -R::testConnection() || die('Error in DB connection'); -R::usePartialBeans(true); +if (!is_cli()) { + header('HTTP/1.0 403 Forbidden'); + exit; +} try { $monthly_totals = R::getAll(" @@ -39,8 +31,8 @@ try { } catch (\RedBeanPHP\RedException $e) { die('Error in SQL query: ' . $e->getMessage()); } -foreach ($monthly_totals as $monthly) { +foreach ($monthly_totals as $monthly) { // Format date to timestamp. $timestamp = $monthly['yymm'] . '-01 01:01:01-01'; diff --git a/db/podcrawler.php b/db/podcrawler.php index a9e0bc0a826223bda1390c0ae1fa22860ce6ecad..02da5e99b63745298fc986a4099e2da9a6694dc5 100644 --- a/db/podcrawler.php +++ b/db/podcrawler.php @@ -6,22 +6,14 @@ declare(strict_types=1); -if (PHP_SAPI !== 'cli') { - header('HTTP/1.0 403 Forbidden'); - exit; -} - use RedBeanPHP\R; -require_once __DIR__ . '/../vendor/autoload.php'; -require_once __DIR__ . '/../config.php'; +require_once __DIR__ . '/../boot.php'; -define('PODUPTIME', microtime(true)); - -// Set up global DB connection. -R::setup("pgsql:host={$pghost};dbname={$pgdb}", $pguser, $pgpass, true); -R::testConnection() || die('Error in DB connection'); -R::usePartialBeans(true); +if (!is_cli()) { + header('HTTP/1.0 403 Forbidden'); + exit; +} try { $sql = ' diff --git a/db/pull-masterversions.php b/db/pull-masterversions.php index ebff6a1f8b4d98c024e717d0dc2bf71fcf13668d..666acec37e946474622478215b63d61f31c6bd92 100644 --- a/db/pull-masterversions.php +++ b/db/pull-masterversions.php @@ -6,22 +6,14 @@ declare(strict_types=1); -if (PHP_SAPI !== 'cli') { - header('HTTP/1.0 403 Forbidden'); - exit; -} - use RedBeanPHP\R; -require_once __DIR__ . '/../vendor/autoload.php'; -require_once __DIR__ . '/../config.php'; - -define('PODUPTIME', microtime(true)); +require_once __DIR__ . '/../boot.php'; -// Set up global DB connection. -R::setup("pgsql:host={$pghost};dbname={$pgdb}", $pguser, $pgpass, true); -R::testConnection() || die('Error in DB connection'); -R::usePartialBeans(true); +if (!is_cli()) { + header('HTTP/1.0 403 Forbidden'); + exit; +} $softwares = [ 'diaspora' => ['repo' => 'diaspora/diaspora', 'gitsite' => 'api.github.com', 'gittype' => 'github', 'devbranch' => 'develop'], @@ -39,11 +31,11 @@ $opts = [ ]; foreach ($softwares as $software => $details) { - if ($details['gittype'] == 'github') { + if ($details['gittype'] === 'github') { $context = stream_context_create($opts); - $releasejson = json_decode(file_get_contents('https://' . $details["gitsite"] . '/repos/' . $details["repo"] . '/releases/latest', false, $context)); - if ($details["devbranch"]) { - $commitjson = json_decode(file_get_contents('https://' . $details["gitsite"] . '/repos/' . $details["repo"] . '/commits/' . $details["devbranch"], false, $context)); + $releasejson = json_decode(file_get_contents('https://' . $details['gitsite'] . '/repos/' . $details['repo'] . '/releases/latest', false, $context)); + if ($details['devbranch']) { + $commitjson = json_decode(file_get_contents('https://' . $details['gitsite'] . '/repos/' . $details['repo'] . '/commits/' . $details['devbranch'], false, $context)); } else { $commitjson = ''; } @@ -63,11 +55,11 @@ foreach ($softwares as $software => $details) { die('Error in SQL query: ' . $e->getMessage()); } } - } elseif ($details['gittype'] == 'gitlab') { + } elseif ($details['gittype'] === 'gitlab') { $context = stream_context_create($opts); - $releasejson = json_decode(file_get_contents('https://' . $details["gitsite"] . '/api/v4/projects/' . $details["repo"] . '/repository/tags', false, $context)); - if ($details["devbranch"]) { - $commitjson = json_decode(file_get_contents('https://' . $details["gitsite"] . '/api/v4/projects/' . $details["repo"] . '/repository/commits/' . $details["devbranch"], false, $context)); + $releasejson = json_decode(file_get_contents('https://' . $details['gitsite'] . '/api/v4/projects/' . $details['repo'] . '/repository/tags', false, $context)); + if ($details['devbranch']) { + $commitjson = json_decode(file_get_contents('https://' . $details['gitsite'] . '/api/v4/projects/' . $details['repo'] . '/repository/commits/' . $details['devbranch'], false, $context)); } else { $commitjson = ''; } @@ -89,6 +81,5 @@ foreach ($softwares as $software => $details) { } } - printf('%s:%s:%s ', $software, $masterversion, $devlastcommit ?: 'n/a'); } diff --git a/db/pull.php b/db/pull.php index 5c722e459e3c73ad3fc2a206444db977df480e1b..64dfaa5be0e82d59a4e8e9c872bc66fd83d39489 100644 --- a/db/pull.php +++ b/db/pull.php @@ -6,7 +6,9 @@ declare(strict_types=1); -if (!in_array(PHP_SAPI, ['cgi-fcgi', 'cli'])) { +require_once __DIR__ . '/../boot.php'; + +if (!is_cli()) { $referer = ($_SERVER['HTTP_REFERER'] ? parse_url($_SERVER['HTTP_REFERER'])['host'] : ''); if ($referer !== $_SERVER['SERVER_NAME']) { header('HTTP/1.0 403 Forbidden'); @@ -14,8 +16,9 @@ if (!in_array(PHP_SAPI, ['cgi-fcgi', 'cli'])) { } } +use Carbon\Carbon; use GeoIp2\Database\Reader; -use LanguageDetection\Language; +use Longman\IPTools\Ip; use Poduptime\PodStatus; use RedBeanPHP\R; @@ -23,30 +26,21 @@ $debug = isset($_GET['debug']) || (isset($argv) && in_array('debug', $argv, t $sqldebug = isset($_GET['sqldebug']) || (isset($argv) && in_array('sqldebug', $argv, true)); $develop = isset($_GET['develop']) || (isset($argv) && in_array('develop', $argv, true)); $write = !(isset($_GET['nowrite']) || (isset($argv) && in_array('nowrite', $argv, true))); -$newline = PHP_SAPI === 'cli' ? "\n\n" : '

'; +$newline = is_cli() ? "\n\n" : '

'; $_domain = $_GET['domain'] ?? null; // Must have a domain, except if called from CLI. -$_domain || PHP_SAPI === 'cli' || die('No valid input'); - -require_once __DIR__ . '/../vendor/autoload.php'; -require_once __DIR__ . '/../config.php'; - -define('PODUPTIME', microtime(true)); +$_domain || is_cli() || die('No valid input'); -// Set up global DB connection. -R::setup("pgsql:host={$pghost};dbname={$pgdb}", $pguser, $pgpass, true); -$sqldebug && R::debug(true); -R::testConnection() || die('Error in DB connection'); -R::usePartialBeans(true); +$sqldebug && R::fancyDebug(true); try { // Setup GeoIP Database - $reader = new Reader($geoip2db); + $reader = new Reader(c('geoip2db')); $sql = ' - SELECT domain, score, date_created, weight, podmin_notify, email, masterversion, shortversion, status + SELECT domain, score, date_created, weight, podmin_notify, podmin_notify_level, email, masterversion, shortversion, status, detectedlanguage FROM pods '; @@ -55,11 +49,11 @@ try { if ($_domain) { $sql .= ' WHERE domain = ?'; $pods = R::getAll($sql, [$_domain]); - } elseif (PHP_SAPI === 'cli' && (isset($argv) && in_array('Check_System_Deleted', $argv, true))) { - $sql .= ' WHERE status = ?'; + } elseif (is_cli() && (isset($argv) && in_array('Check_System_Deleted', $argv, true))) { + $sql .= ' WHERE status = ? ORDER BY id'; $pods = R::getAll($sql, [PodStatus::SYSTEM_DELETED]); - } elseif (PHP_SAPI === 'cli') { - $sql .= ' WHERE status < ?'; + } elseif (is_cli()) { + $sql .= ' WHERE status < ? ORDER BY id'; $pods = R::getAll($sql, [PodStatus::PAUSED]); } } catch (\RedBeanPHP\RedException $e) { @@ -69,16 +63,18 @@ try { } foreach ($pods as $pod) { - $domain = $pod['domain']; - $score = (int) $pod['score']; - $dbscore = $score; - $dateadded = $pod['date_created']; - $weight = $pod['weight']; - $email = $pod['email']; - $notify = $pod['podmin_notify']; - $masterv = $pod['masterversion']; - $shortv = $pod['shortversion']; - $dbstatus = $pod['status']; + $domain = $pod['domain']; + $score = (int) $pod['score']; + $dbscore = $score; + $dateadded = $pod['date_created']; + $weight = $pod['weight']; + $email = $pod['email']; + $notify = $pod['podmin_notify']; + $notify_level = $pod['podmin_notify_level']; + $masterv = $pod['masterversion']; + $shortv = $pod['shortversion']; + $dbstatus = $pod['status']; + $language = $pod['detectedlanguage']; try { $ratings = R::getAll(' @@ -90,7 +86,7 @@ foreach ($pods as $pod) { die('Error in SQL query: ' . $e->getMessage()); } - _debug('Domain', $domain); + debug('Domain', $domain); $user_rating = 0; @@ -98,40 +94,36 @@ foreach ($pods as $pod) { $user_rating = round(array_sum($user_ratings) / count($user_ratings), 2); } + $nodeinfo_meta = curl("https://{$domain}/.well-known/nodeinfo"); + // Default link to fetch node info. - $link = "https://{$domain}/nodeinfo/1.0"; + $nodeinfo_url = "https://{$domain}/nodeinfo/1.0"; - if (($infos = @file_get_contents("https://{$domain}/.well-known/nodeinfo")) !== false) { - $info = json_decode($infos, true); - $link = max($info['links'])['href']; + if ($info = json_decode($nodeinfo_meta['body'] ?: '', true)) { + $nodeinfo_url = max($info['links'])['href']; } - _debug('Nodeinfo link', $link); - - $chss = curl_init(); - curl_setopt($chss, CURLOPT_URL, $link); - curl_setopt($chss, CURLOPT_CONNECTTIMEOUT, 10); - curl_setopt($chss, CURLOPT_TIMEOUT, 30); - curl_setopt($chss, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($chss, CURLOPT_CERTINFO, 1); - curl_setopt($chss, CURLOPT_CAINFO, $cafullpath); - $outputssl = curl_exec($chss); - $outputsslerror = curl_error($chss); - $info = curl_getinfo($chss, CURLINFO_CERTINFO); - $conntime = curl_getinfo($chss, CURLINFO_CONNECT_TIME); - $nstime = curl_getinfo($chss, CURLINFO_NAMELOOKUP_TIME); + debug('Nodeinfo link', $nodeinfo_url); + + $nodeinfo = curl($nodeinfo_url); + $outputssl = $nodeinfo['body']; + $outputsslerror = $nodeinfo['error']; + $info = $nodeinfo['info']; + $httpcode = $nodeinfo['code']; + $conntime = $nodeinfo['conntime']; + $nstime = $nodeinfo['nstime']; $latency = $conntime - $nstime; $sslexpire = $info[0]['Expire date'] ?? null; - curl_close($chss); - _debug('Nodeinfo output', $outputssl, true); - _debug('Nodeinfo output error', $outputsslerror, true); - _debug('Cert expire date', $sslexpire); - _debug('Conntime', $conntime); - _debug('NStime', $nstime); - _debug('Latency', $latency); + debug('Nodeinfo output', $outputssl, true); + debug('Nodeinfo output error', $outputsslerror, true); + debug('Nodeinfo service http response code', $httpcode); + debug('Cert expire date', $sslexpire); + debug('Conntime', $conntime); + debug('NStime', $nstime); + debug('Latency', $latency); - $jsonssl = ($outputssl ? json_decode($outputssl) : null); + $jsonssl = json_decode($outputssl ?: ''); if ($jsonssl !== null) { $version = $jsonssl->software->version ?? 0; @@ -146,17 +138,10 @@ foreach ($pods as $pod) { $local_posts = $jsonssl->usage->localPosts ?? 0; $comment_counts = $jsonssl->usage->localComments ?? 0; $service_xmpp = ($jsonssl->metadata->xmppChat ?? false) === true; - $service_facebook = false; - $service_twitter = false; - $service_tumblr = false; - $service_wordpress = false; if (json_last_error() === 0) { (!$jsonssl->software->version) || $score += 1; if (is_array($jsonssl->services->outbound)) { - $service_facebook = in_array('facebook', $jsonssl->services->outbound, true); - $service_twitter = in_array('twitter', $jsonssl->services->outbound, true); - $service_tumblr = in_array('tumblr', $jsonssl->services->outbound, true); - $service_wordpress = in_array('wordpress', $jsonssl->services->outbound, true); + $services = json_encode($jsonssl->services->outbound); } } @@ -180,7 +165,7 @@ foreach ($pods as $pod) { die('Error in SQL query: ' . $e->getMessage()); } - _debug('Version code', $shortversion); + debug('Version code', $shortversion); try { $masterdata = R::getRow(' @@ -198,13 +183,13 @@ foreach ($pods as $pod) { $devlastcommit = ($masterdata['devlastcommit'] ?? date('Y-m-d H:i:s')); $releasedate = ($masterdata['releasedate'] ?? date('Y-m-d H:i:s')); - _debug('Masterversion', $masterversion); + debug('Masterversion', $masterversion); $masterversioncheck = explode('.', $masterversion); $shortversioncheck = (strpos($shortversion, '.') ? explode('.', $shortversion) : implode('.', ['0', preg_replace('/\D/', '', $shortversion), '0'])); //this is still off with a pod with v1 as total version. cant explode that, won't have a [0] or [1] later to use either - _debug('Days since master code release', date_diff(new DateTime($releasedate), new DateTime())->format('%d')); + debug('Days since master code release', date_diff(new DateTime($releasedate), new DateTime())->format('%d')); try { $lastpodupdates = R::getRow(' @@ -222,7 +207,7 @@ foreach ($pods as $pod) { $lastdatechecked = ($lastpodupdates['date_checked'] ?? date('Y-m-d H:i:s')); $devlastdays = $devlastcommit ? date_diff(new DateTime($devlastcommit), new DateTime())->format('%a') : 30;//tmp//if no dev branch then what? - _debug('Dev last commit was ', $devlastdays); + debug('Dev last commit was ', $devlastdays); $updategap = date_diff(new DateTime($lastdatechecked), new DateTime($devlastcommit))->format('%a'); @@ -231,50 +216,53 @@ foreach ($pods as $pod) { if ($updategap + $devlastdays > 400) { - _debug('Outdated More than 400 days', 'Yes'); + debug('Outdated More than 400 days', 'Yes'); + $podminhelp = 'Your code base seems too out of date to be used. Last time you updated was ' . $updategap; $score -= 2; } } elseif (($masterversioncheck[1] - $shortversioncheck[1]) > 1) { ///tmp/If pod is two versions off AND it's been more than 60 days since that release came out AND your on the master production branch - _debug('Outdated second decimal > 1', 'Yes'); + debug('Outdated second decimal > 1', 'Yes'); $score -= 2; $updategap = date_diff(new DateTime($lastdatechecked), new DateTime($releasedate))->format('%a'); + $podminhelp = 'Your code base seems too out of date to be used. Current version is ' . $masterversion . ' and you are running ' . $shortversion; + } elseif ($updategap - date_diff(new DateTime($releasedate), new DateTime())->format('%a') > 400) { - _debug('Outdated more than 400 days since x ', 'Yes'); + debug('Outdated more than 400 days since x ', 'Yes'); $score -= 2; $updategap = date_diff(new DateTime($lastdatechecked), new DateTime($releasedate))->format('%a'); + $podminhelp = 'Your code base seems too out of date to be used. Last time you updated was ' . $updategap; + } else { $updategap = date_diff(new DateTime($lastdatechecked), new DateTime($releasedate))->format('%a'); } - _debug('Pod code was updated after ', $updategap); + debug('Pod code was updated after ', $updategap); $status = PodStatus::UP; } - $d = new DOMDocument; - libxml_use_internal_errors(true); - $d->loadHTMLFile('https://' . $domain); - $body = $d->getElementsByTagName('html')->item(0); + // Default to the already saved language. + $detectedlanguage = $language; - if ($body) { - $ld = new Language; - $detectedlanguage = strtoupper(key($ld->detect($body->nodeValue)->bestResults()->close())); - } else { - $score -= 1; + $language_snippet = getWebsiteLanguageSnippetFromUrl("https://{$domain}/"); + if (!$language_snippet) { $detectedlanguage = null; + --$score; + $podminhelp = 'Unable to render the html on your main page https://' . $domain; + } elseif ($debug || Carbon::now()->hour === 12) { + $detectedlanguage = detectWebsiteLanguageFromSnippet($language_snippet); } - _debug('Detected Language', $detectedlanguage); - - if (!$jsonssl || !$body) { + debug('Detected Language', $detectedlanguage); - _debug('Connection', 'Can not connect to pod'); + if (!$jsonssl || !$language_snippet) { + debug('Connection', 'Can not connect to pod'); try { $c = R::dispense('checks'); @@ -291,13 +279,13 @@ foreach ($pods as $pod) { die('Error in SQL query: ' . $e->getMessage()); } - $score -= 1; + --$score; $status = PodStatus::DOWN; } - _debug('Signup Open', $signup); + debug('Signup Open', $signup); - $dnsserver = !empty($dnsserver) ? $dnsserver : '1.1.1.1'; + $dnsserver = c('dnsserver') ?: '1.1.1.1'; $delv = new NPM\Xec\Command("delv @{$dnsserver} {$domain}"); $delv->throwExceptionOnError(false); @@ -315,10 +303,11 @@ foreach ($pods as $pod) { $iplookupv6 = explode(PHP_EOL, trim($delv->execute(['AAAA'], null, 15)->stdout)); $ipv6 = (bool) preg_grep('/\s+IN\s+AAAA\s+.*/', $iplookupv6); - _debug('IPv4', $ip); - _debug('IPv6', $ipv6); + debug('IPv4', $ip); + debug('IPv6', $ipv6); - if ($ip) { + // todo: Temporary workaround (see https://github.com/akalongman/php-ip-tools/issues/8) + if (Ip::isValid($ip) && Ip::isRemote($ip)) { $geo = $reader->city($ip); $countryname = ($geo->country->name ?? null) ?: null; $country = ($geo->country->isoCode ?? null) ?: null; @@ -327,7 +316,7 @@ foreach ($pods as $pod) { $lat = ($geo->location->latitude ?? null) ?: 0; $long = ($geo->location->longitude ?? null) ?: 0; - _debug('Location', json_encode($geo->raw), true); + debug('Location', json_encode($geo->raw), true); } echo $newline; $statslastdate = date('Y-m-d H:i:s'); @@ -351,27 +340,36 @@ foreach ($pods as $pod) { die('Error in SQL query: ' . $e->getMessage()); } - _debug('Uptime', $uptime); + debug('Uptime', $uptime); - if ($score == 49 && $notify && !$develop && $dbscore == 50) { + if ($score == ($notify_level - 1) && $notify && !$develop && $dbscore == $notify_level) { $to = $email; - $headers = ['From: ' . $adminemail, 'Bcc: ' . $adminemail]; + $headers = ['From: ' . c('adminemail'), 'Bcc: ' . c('adminemail')]; $subject = 'Monitoring notice from poduptime'; - $message = 'Notice for ' . $domain . '. Your score is ' . $score . ' and your pod will fall off the list soon.'; + $message = 'Notice for ' . $domain . '. Your score is ' . $score . ' and your pod will fall off the list soon. HTTP response of ' . $httpcode . '. '; + + if ($outputsslerror) { + $message .= 'SSL Error ' . $outputsslerror; + } + + if ($podminhelp) { + $message .= ' ' . $podminhelp; + } @mail($to, $subject, $message, implode("\r\n", $headers)); - _debug('Mail Notice', 'sent to ' . $email); + debug('Mail Message body', $message); + debug('Mail Notice', 'sent to ' . $email); } + if ($score > 100) { $score = 100; - } elseif ($score < 0) { - $score = 0; + } elseif ($score < -6000) { $status = PodStatus::SYSTEM_DELETED; } $weightedscore = ($uptime + $score - (10 - $weight)) / 2; - _debug('Score', $score); - _debug('Weighted Score', $weightedscore); + debug('Score', $score); + debug('Weighted Score', $weightedscore); try { $p = R::findOne('pods', 'domain = ?', [$domain]); @@ -391,7 +389,6 @@ foreach ($pods as $pod) { $p['state'] = $state; $p['lat'] = $lat; $p['long'] = $long; - $p['detectedlanguage'] = $detectedlanguage; $p['userrating'] = $user_rating; $p['masterversion'] = $masterversion; $p['weightedscore'] = $weightedscore; @@ -406,12 +403,10 @@ foreach ($pods as $pod) { $p['active_users_monthly'] = $active_users_monthly; $p['local_posts'] = $local_posts; $p['name'] = $name; + $p['detectedlanguage'] = $detectedlanguage; $p['comment_counts'] = $comment_counts; - $p['service_facebook'] = $service_facebook; - $p['service_tumblr'] = $service_tumblr; - $p['service_twitter'] = $service_twitter; - $p['service_wordpress'] = $service_wordpress; $p['service_xmpp'] = $service_xmpp; + $p['services'] = $services; $p['softwarename'] = $softwarename; } @@ -428,30 +423,4 @@ foreach ($pods as $pod) { echo 'Success ' . $domain; echo $newline; - echo $newline; -} - -/** - * Output a debug message and variable value - * - * @param string $label - * @param mixed $var - * @param bool $dump - */ -function _debug($label, $var = null, $dump = false) -{ - global $debug, $newline; - - if (!$debug) { - return; - } - - $output = (string) $var; - if ($dump || is_array($var)) { - $output = print_r($var, true); - } elseif (is_bool($var)) { - $output = $var ? 'true' : 'false'; - } - - printf('%s: %s%s', $label, $output, $newline); } diff --git a/db/pull.sh b/db/pull.sh index 8c53b14d5a5dd2fec16cbb5f2bbd0ba04b3dce2f..b9fe6fa346959af5ee066f2ae4b5a722895f069f 100755 --- a/db/pull.sh +++ b/db/pull.sh @@ -46,14 +46,14 @@ if [ "$HOUR" = 23 ] || [ "$1" = 'init' ]; then fi if [ "$DAY" = 23 ] || [ "$1" = 'init' ]; then printf "%s" "Updating CA..." - CACERT_FILE="$(php -r "include __DIR__ . '/../config.php'; echo \$cafullpath;")" + CACERT_FILE="$(php -r "echo (require __DIR__ . '/../config.php')['cafullpath'];")" if curl -Lss https://curl.haxx.se/ca/cacert.pem -o "$CACERT_FILE"; then echo "$HAPPY" else echo "$SAD" fi printf "%s" "Updating GeoIP2 DB..." - GEODB_FILE="$(php -r "include __DIR__ . '/../config.php'; echo \$geoip2db;")" + GEODB_FILE="$(php -r "echo (require __DIR__ . '/../config.php')['geoip2db'];")" if funzip <(curl -Lss http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz) > "$GEODB_FILE"; then echo "$HAPPY" else diff --git a/db/saverating.php b/db/saverating.php index 2ea148dc4f38f390889181c930296175068fe25c..a74e2440791fca2edfe5a63aceb9aa286c0916cd 100644 --- a/db/saverating.php +++ b/db/saverating.php @@ -15,15 +15,7 @@ use RedBeanPHP\R; ($_comment = $_POST['comment'] ?? null) || die('A comment is required'); ($_rating = $_POST['rating'] ?? null) || die('A rating is required'); -require_once __DIR__ . '/../vendor/autoload.php'; -require_once __DIR__ . '/../config.php'; - -define('PODUPTIME', microtime(true)); - -// Set up global DB connection. -R::setup("pgsql:host={$pghost};dbname={$pgdb}", $pguser, $pgpass, true); -R::testConnection() || die('Error in DB connection'); -R::usePartialBeans(true); +require_once __DIR__ . '/../boot.php'; try { $r = R::dispense('ratingcomments'); diff --git a/db/status.php b/db/status.php index 044c5a9cbf1f667cebed59d110cc49d3c99cb4e7..606bec3bf067892f5fae5d04f26fe6e035b454f8 100644 --- a/db/status.php +++ b/db/status.php @@ -6,7 +6,7 @@ declare(strict_types=1); -$dur = (time() - filemtime('last.data')); +$dur = time() - filemtime('last.data'); echo $dur; if ($dur > 4500) { http_response_code(500); diff --git a/db/tables.sql b/db/tables.sql index b413514fb35cd995340e53ae1597a5534102d809..7a99ba6445f5d9562ce16cb136f9efccbb278fbc 100644 --- a/db/tables.sql +++ b/db/tables.sql @@ -30,16 +30,14 @@ CREATE TABLE pods ( uptime_alltime numeric(5,2), status smallint DEFAULT 1, latency smallint, - service_facebook boolean, - service_twitter boolean, - service_tumblr boolean, - service_wordpress boolean, service_xmpp boolean, + services jsonb, token text, publickey text, tokenexpire timestamp, podmin_statement text, podmin_notify boolean, + podmin_notify_level int DEFAULT 50, sslexpire timestamp, dnssec boolean, comment_counts int, diff --git a/db/version.md b/db/version.md deleted file mode 100644 index bc4af00546b7a5552c0329674e9426be4bf031c5..0000000000000000000000000000000000000000 --- a/db/version.md +++ /dev/null @@ -1,17 +0,0 @@ -If new install import tables.sql and do not perform migrations - -If upgrading migrations are: - -v1.0 -> v2.0 = migration00001.sql - -v2.0 -> v2.1 = migration00002.sql - -v2.1 -> v2.1.3 = migration00003.sql - -v2.1.4 -> v2.2 = migration00004.sql - -v2.2 -> v2.3 = migrations00005.sql - -To support the original apiv1 you should import: -pods_apiv1.sql -into your db as often as you want your api updated. diff --git a/go.php b/go.php index 78d442ba8b79ca6b6acfd3c498470efaeec82fac..b63a0a3164ed5169f6eb76802d52e24b34df5cb0 100644 --- a/go.php +++ b/go.php @@ -13,15 +13,7 @@ use RedBeanPHP\R; // Other parameters. $_domain = $_GET['domain'] ?? ''; -require_once __DIR__ . '/vendor/autoload.php'; -require_once __DIR__ . '/config.php'; - -define('PODUPTIME', microtime(true)); - -// Set up global DB connection. -R::setup("pgsql:host={$pghost};dbname={$pgdb}", $pguser, $pgpass, true); -R::testConnection() || die('Error in DB connection'); -R::usePartialBeans(true); +require_once __DIR__ . '/boot.php'; try { if ($_domain) { diff --git a/images/icon-xmpp.png b/images/icon-xmpp.png deleted file mode 100644 index 471f6b621f00dfa1bbd90fcefb07958a6d2d0a2a..0000000000000000000000000000000000000000 Binary files a/images/icon-xmpp.png and /dev/null differ diff --git a/images/smlogo.png b/images/smlogo.png deleted file mode 100644 index 97ca7791b3aa9b3a19c62aa8b39b191b6922131d..0000000000000000000000000000000000000000 Binary files a/images/smlogo.png and /dev/null differ diff --git a/index.php b/index.php index 998c3681ff8d47b3a439f2f5b54b9ce19698f256..7ad124ad056d5414b0aa3522d67f682ef65a5d95 100644 --- a/index.php +++ b/index.php @@ -7,19 +7,19 @@ declare(strict_types=1); use Carbon\Carbon; -require_once __DIR__ . '/vendor/autoload.php'; -require_once __DIR__ . '/config.php'; +require_once __DIR__ . '/boot.php'; -$lastfile = 'db/last.data'; -$input = isset($_GET['input']) ? substr($_GET['input'], 1) : null; -$mapview = isset($_GET['mapview']) || $input == 'map'; -$statsview = isset($_GET['statsview']) || $input == 'stats'; -$podmin = isset($_GET['podmin']) || $input == 'podmin'; -$podminedit = isset($_GET['podminedit']) || $input == 'podminedit'; -$edit = isset($_GET['edit']) || $input == 'edit'; -$add = isset($_GET['add']) || $input == 'add'; -$gettoken = isset($_GET['gettoken']) || $input == 'gettoken'; -$simpleview = !($mapview || $podmin || $podminedit || $statsview); +$lastfile = 'db/last.data'; +$input = isset($_GET['input']) ? substr($_GET['input'], 1) : null; +$mapview = isset($_GET['mapview']) || $input === 'map'; +$statsview = isset($_GET['statsview']) || $input === 'stats'; +$podmin = isset($_GET['podmin']) || $input === 'podmin'; +$podminedit = isset($_GET['podminedit']) || $input === 'podminedit'; +$edit = isset($_GET['edit']) || $input === 'edit'; +$add = isset($_GET['add']) || $input === 'add'; +$gettoken = isset($_GET['gettoken']) || $input === 'gettoken'; +$simpleview = !($mapview || $podmin || $podminedit || $statsview); +$fullview = false; ?> @@ -34,6 +34,7 @@ $simpleview = !($mapview || $podmin || $podminedit || $statsview); + @@ -61,27 +62,27 @@ $navs = [ ]; ?>
-