Compare commits

...

171 Commits

Author SHA1 Message Date
tracer bb1a16988d moced color consts to a utility class 2024-05-02 20:18:22 +02:00
tracer f04c306f91 added chekcs for cron job 2024-05-01 18:57:37 +02:00
tracer 5d2e95ac3d added chekcs for cron job 2024-05-01 18:41:24 +02:00
tracer 4e056f6831 added chekcs for cron job 2024-05-01 18:39:55 +02:00
tracer 753e96ed85 added self for nameservers for openApi defaults. 2024-04-30 19:33:07 +02:00
tracer d31ee8bdec added self for nameservers for openApi defaults. 2024-04-30 17:27:31 +02:00
tracer 26b0b6de6b modified version update 2024-04-30 17:22:43 +02:00
tracer efb069eb5a modified version update 2024-04-30 14:11:54 +02:00
tracer 514c77de55 modified version update 2024-04-30 14:08:59 +02:00
tracer 7b40624218 modified version update 2024-04-30 13:49:59 +02:00
tracer 06df37ed3c modified version update 2024-04-30 13:35:21 +02:00
tracer c6ece08a0b changed config table 2024-04-30 13:21:01 +02:00
tracer 0f13e29fe9 changed config table 2024-04-30 13:14:05 +02:00
tracer b06128e819 changed config table 2024-04-30 13:11:54 +02:00
tracer f25e90f292 added self for nameservers for openApi defaults. 2024-04-30 11:13:24 +02:00
tracer d0224f6746 new migration 2024-04-27 15:43:37 +02:00
tracer 71a275198f added version to api 2024-04-26 19:24:04 +02:00
tracer 578f76426e added version to api 2024-04-26 19:22:44 +02:00
tracer 96689879c4 try to fix cors issues 2024-04-25 21:03:35 +02:00
tracer e9b14a11d7 try to fix cors issues 2024-04-25 20:58:01 +02:00
tracer a312ad9095 move log out of root 2024-04-23 19:53:57 +02:00
tracer 1518deee87 added a more verbose error if API key is wrong 2024-04-22 20:19:34 +02:00
tracer c9757ead13 fixed cron issues 2024-04-22 18:57:49 +02:00
tracer 3e591eee9c updated readme 2024-04-21 13:52:57 +02:00
tracer 94334694d4 added systemd service & timer 2024-04-21 13:49:02 +02:00
tracer 6fc85b8692 added semaphore fo zone creation 2024-04-21 13:04:38 +02:00
tracer 8784acbed9 made check:panel more verbose 2024-04-19 18:11:21 +02:00
tracer cc4bbbecb4 fixed change path for BindApi class 2024-04-19 16:36:00 +02:00
tracer 730ae25d63 fixed change path for BindApi class 2024-04-19 16:19:17 +02:00
tracer e4f5a4a07e modified apikeys table 2024-04-19 15:50:12 +02:00
tracer 4f52e99a92 added version handling 2024-04-19 15:11:21 +02:00
tracer 176bd9dc83 renamed doains:refresh to domains:update as former update has been dropped 2024-04-18 18:04:25 +02:00
tracer 65ea85da39 updated domain refresh 2024-04-18 17:33:07 +02:00
tracer 2c65f743e7 fixed marking oown panel bug 2024-04-18 14:20:46 +02:00
tracer eaa137291b made name mandatory for apikeys 2024-04-17 20:28:51 +02:00
tracer 17535d825d fixed .htaccess 2024-04-17 15:27:21 +02:00
tracer 93e12b9949 fixed .htaccess 2024-04-17 15:25:53 +02:00
tracer 43b8f19a7b fixed bug when in nameserver creation 2024-04-17 14:04:47 +02:00
tracer 645f3d00fe fixed bug when in nameserver creation 2024-04-17 13:52:44 +02:00
tracer fd4175987b fixed bug when in domain refresh 2024-04-17 13:34:01 +02:00
tracer 2eb96742bb fixed bug when no domains exist 2024-04-17 13:14:09 +02:00
tracer 8f946d9360 fixed controller init bug 2024-04-17 12:55:44 +02:00
tracer 43698c0fae reworked most of the check commands 2024-04-16 18:24:38 +02:00
tracer d115a5d775 some fixes 2024-04-14 20:14:41 +02:00
tracer 9e9540d351 removed phpunit cache from repo 2024-04-13 20:38:58 +02:00
tracer 3a461a5549 removed IDE settings from repo 2024-04-13 20:37:19 +02:00
tracer fdc763ba7b added support for Phinx and Phinx-Migration-Generator 2024-04-13 20:35:20 +02:00
tracer d62586feb0 before test on ns3 2024-04-09 18:45:28 +02:00
tracer 6f16cfd76c fixed a display bug listing avalable subcommands 2024-04-08 19:01:13 +02:00
tracer 4189d35c09 prepare cleanup 2024-04-07 11:15:32 +02:00
tracer 192a5a2234 bugfixed on setup 2024-04-05 17:17:33 +02:00
tracer 3571e7888f modified PHP version check 2023-09-19 19:23:24 +02:00
tracer b877c78716 made the default checkPermission always quet 2023-09-19 18:32:03 +02:00
tracer b9925f232f run checkup withput wrong assumptions 2023-09-19 18:21:42 +02:00
tracer 0f9e66bf90 read version from composer.json 2023-09-17 12:36:14 +02:00
tracer 3cfcb1e847 version system 2023-09-15 20:44:38 +02:00
tracer a861ef0ad4 Merge branch 'symfony', layed off the plan to move to symfony for now 2023-09-14 20:51:27 +02:00
tracer c644be4eb2 added first versioning 2023-09-14 20:47:05 +02:00
tracer 01409e9592 verbosity bugfix 2023-09-14 16:50:37 +02:00
tracer 79942030fa added getSelf 2022-10-08 10:58:18 +02:00
tracer 6cca02b1cf added SodiumException 2022-10-08 10:57:56 +02:00
tracer 28a9e4ac08 renamed api_token to apikey 2022-10-08 10:56:45 +02:00
tracer 9985e2e896 removed unused enum. 2022-10-08 10:56:07 +02:00
tracer 2965e9b7ce added options for testing 2022-10-08 10:55:25 +02:00
tracer 91ea53275e improves checkWebmail 2022-10-08 10:54:55 +02:00
tracer 2e1f1ac8b1 added fileGetContents 2022-10-08 10:53:31 +02:00
tracer f66298842a initial commit 2022-10-08 10:52:16 +02:00
tracer 5d6a0b426a initial commit 2022-10-08 10:52:03 +02:00
tracer 78a1f353af initial commit 2022-10-08 10:51:54 +02:00
tracer 9a59a2563d extends from BindApiControllerTest 2022-10-08 10:45:54 +02:00
tracer 620e762dfc extends from BindApiControllerTest 2022-10-08 10:45:39 +02:00
tracer 5efa996d1d initial commit 2022-10-08 10:45:09 +02:00
tracer 82018976cf added reports 2022-10-08 10:43:41 +02:00
tracer 26e2934e40 added more verbose version 2022-10-08 10:43:06 +02:00
tracer b554c751ae minor updates 2022-10-08 10:42:03 +02:00
tracer 552eeb0c25 code cleanup 2022-10-08 10:16:52 +02:00
tracer 4199faecb4 initial commit 2022-10-07 19:16:26 +02:00
tracer 059e3934f9 adapted namespace 2022-10-07 12:56:28 +02:00
tracer f45dd8fbc1 moved namespace 2022-10-07 11:33:54 +02:00
tracer c1a54aa23e initial commit 2022-10-07 11:33:08 +02:00
tracer d2f733d8c2 added test support 2022-10-06 16:21:11 +02:00
tracer 010914b7bd added test support 2022-10-06 16:18:25 +02:00
tracer c166b5774c modified constructor 2022-09-29 19:26:12 +02:00
tracer 9dca565296 renamed ApiToken to apikey 2022-09-29 19:25:18 +02:00
tracer bc1b9c1204 renamed some inline variables 2022-09-29 19:24:22 +02:00
tracer 402934f02c added encryption to the first functions 2022-09-29 19:23:47 +02:00
tracer 19576dd6b7 remove throw, catching exceptions in place 2022-09-29 19:22:33 +02:00
tracer 0268262e98 added webmail:check 2022-09-29 19:21:42 +02:00
tracer b536316a84 initial commit 2022-09-27 19:49:16 +02:00
tracer f614837729 initial commit 2022-09-27 19:41:35 +02:00
tracer e9d777ab24 initial commit 2022-09-27 19:38:01 +02:00
tracer 61ec6aaaa5 refactored command registration 2022-09-27 19:13:28 +02:00
tracer 4c80ba1543 added encryption 2022-09-22 19:31:38 +02:00
tracer be6402b4a3 removed a stale blank line ^^ 2022-09-22 19:30:45 +02:00
tracer 8f5a57ee54 made all methods use objects instead of single parameters 2022-09-22 19:11:04 +02:00
tracer 51b9e67ea9 added encryption, constructor property promotion 2022-09-22 18:57:10 +02:00
tracer 8ec1a2942d added password encryption 2022-09-22 18:54:54 +02:00
tracer 790176964d added corrected key import from config 2022-09-22 18:54:23 +02:00
tracer b2115a97a8 removed unused imports 2022-09-22 18:53:29 +02:00
tracer 3c09b4038d added encryption support 2022-09-21 16:02:42 +02:00
tracer 3bc232ef0b fixed a handling bug 2022-09-21 16:01:44 +02:00
tracer cd5361c65b refactored zone deletion 2022-09-21 16:01:14 +02:00
tracer f81b0451b4 added quiet option 2022-09-21 16:00:16 +02:00
tracer 9474a9ebef added quiet option 2022-09-21 15:59:09 +02:00
tracer ccb3479568 added quiet option 2022-09-21 15:58:48 +02:00
tracer d5bdb1bade initial commit 2022-09-21 15:52:13 +02:00
tracer 1ae9434558 initial commit 2022-09-21 15:51:48 +02:00
tracer de98f12ff5 initial commit 2022-09-21 15:51:17 +02:00
tracer 3f4bf92b62 initial commit 2022-09-21 15:44:43 +02:00
tracer 4fe29f350f removed some typos 2022-09-20 19:17:28 +02:00
tracer 18402022e2 added note that the docs are not current. 2022-09-20 19:02:35 +02:00
tracer c3221e5cbe initial commit 2022-09-19 14:12:03 +02:00
tracer 123d054c8d refactored argument handling 2022-09-17 18:57:23 +02:00
tracer b48758bf82 refactored argument handling 2022-09-17 18:56:20 +02:00
tracer 61b24edfdf checkSetup has verbose disabled if not explicitly called 2022-09-17 17:39:47 +02:00
tracer e94819ed7f added option to override verbose for automated checks 2022-09-17 17:38:55 +02:00
tracer 72e9731562 upgraded monolog 2022-09-17 16:31:35 +02:00
tracer 47ecf9ef97 made db connection ro 2022-09-17 16:31:00 +02:00
tracer 023a7e3668 added logger 2022-09-17 16:29:58 +02:00
tracer 9840fb50ff added logger 2022-09-17 16:29:23 +02:00
tracer b77e7bf348 added password property 2022-09-17 16:28:51 +02:00
tracer cce30b17ad refactored 2022-09-17 16:28:04 +02:00
tracer b25f0ab1eb added logger 2022-09-17 16:27:01 +02:00
tracer d1325202ee introduced configcontroller 2022-09-17 16:26:14 +02:00
tracer 4bff4182c8 added encryption key 2022-09-17 16:25:24 +02:00
tracer eab0c958c0 typo 2022-09-17 16:24:40 +02:00
tracer 51455ed24b attribute reminder 2022-09-17 16:24:06 +02:00
tracer 0e1941a0f0 migration reminder 2022-09-17 16:23:05 +02:00
tracer be097004ae init 2022-09-17 16:01:29 +02:00
tracer ce0d101ffe removed custom log 2022-09-17 15:54:20 +02:00
tracer c2ef0e9248 refactored DI 2022-09-17 15:50:36 +02:00
tracer 25654e720c added $error in case if missing API key 2022-09-17 15:49:24 +02:00
tracer 09c3f5c1dd first commit 2022-09-17 15:48:26 +02:00
tracer 46fdadf8e5 added check for debugging 2022-09-17 15:46:25 +02:00
tracer 051e7cbd0b Merge remote-tracking branch 'origin/master'
# Conflicts:
#	bin/console
#	src/Controller/CLIController.php
#	src/Repository/PanelRepository.php
2022-09-17 15:41:31 +02:00
tracer d8ad733d2c added find self 2022-09-17 15:40:44 +02:00
tracer e12a226b4f modified shebang behaviour 2022-09-16 15:03:19 +02:00
tracer 9716ad40d2 reworking dyndns 2022-09-16 14:59:23 +02:00
tracer ac4cb3473e Refactored, removed $config, added $verbose & $debug
Signed-off-by: tracer <tracer@24unix.net>
2022-07-21 15:46:48 +02:00
tracer 5444035a09 refacted to use bindAPi in CLIController 2022-07-20 19:09:40 +02:00
tracer 838c571d75 before refactoring BindAPI/CLIController/RequestController 2022-07-19 18:53:35 +02:00
tracer 8168b41b8c initial commit
Signed-off-by: tracer <tracer@24unix.net>
2022-05-05 13:50:22 +02:00
tracer 492c845057 changed php interpreter
Signed-off-by: tracer <tracer@24unix.net>
2022-04-06 17:19:01 +02:00
tracer c8cb2049a0 moved debug output to logger
Signed-off-by: tracer <tracer@24unix.net>
2022-04-06 17:14:23 +02:00
tracer 92e0bf6d02 added 204 if ip was not changed
Signed-off-by: tracer <tracer@24unix.net>
2022-04-06 17:13:48 +02:00
tracer 0a67c16862 added findFirst()
Signed-off-by: tracer <tracer@24unix.net>
2022-04-06 16:29:14 +02:00
tracer b90d91fda2 improved handling os dyndns endpoints
Signed-off-by: tracer <tracer@24unix.net>
2022-04-06 16:28:38 +02:00
tracer ddae287748 modified handling of slave zones
Signed-off-by: tracer <tracer@24unix.net>
2022-04-06 16:27:58 +02:00
tracer 22e2d57b61 added support for dyndns
Signed-off-by: tracer <tracer@24unix.net>
2022-04-06 16:26:35 +02:00
tracer d6922be2a4 added zone type
Signed-off-by: tracer <tracer@24unix.net>
2022-04-06 16:26:08 +02:00
tracer 2f79e39a8c changed php path
Signed-off-by: tracer <tracer@24unix.net>
2022-04-06 16:25:27 +02:00
tracer 7036633a8b fixed some typos
Signed-off-by: tracer <tracer@24unix.net>
2022-04-06 16:24:30 +02:00
tracer 69cca0c2a7 initial commit
Signed-off-by: tracer <tracer@24unix.net>
2022-04-06 16:23:57 +02:00
tracer 47585fccd4 initial commit
Signed-off-by: tracer <tracer@24unix.net>
2022-04-06 16:23:30 +02:00
tracer 8635c9625f added logger
Signed-off-by: tracer <tracer@24unix.net>
2022-04-06 16:22:56 +02:00
tracer 747b157ac3 initial commit
Signed-off-by: tracer <tracer@24unix.net>
2022-04-06 16:22:27 +02:00
tracer f803570ba7 changed get to post for dyndns
Signed-off-by: tracer <tracer@24unix.net>
2022-04-04 14:53:53 +02:00
tracer 9b2c7f3495 changed methods moved from Controller to Repository
Signed-off-by: tracer <tracer@24unix.net>
2022-03-21 14:32:10 +01:00
tracer c9b1d097c1 added check if we are master for a zone
Signed-off-by: tracer <tracer@24unix.net>
2022-03-21 14:05:00 +01:00
tracer 6b1329eb3c added logger
Signed-off-by: tracer <tracer@24unix.net>
2022-03-21 14:03:55 +01:00
tracer 5a71d5efde added 404 fpr DynDNS
Signed-off-by: tracer <tracer@24unix.net>
2022-03-10 20:05:42 +01:00
tracer 4d0be96915 added 1.0.1
Signed-off-by: tracer <tracer@24unix.net>
2022-03-08 16:17:45 +01:00
tracer 214cfd6a82 added local config
Signed-off-by: tracer <tracer@24unix.net>
2022-03-08 16:16:54 +01:00
tracer 1d5468f17e one more typo fixed
Signed-off-by: tracer <tracer@24unix.net>
2022-03-01 20:15:31 +01:00
tracer 866e1dcb9b more text, one more screenshot.
Signed-off-by: tracer <tracer@24unix.net>
2022-03-01 19:45:32 +01:00
tracer 8b6d939123 replaced print with echo
Signed-off-by: tracer <tracer@24unix.net>
2022-03-01 18:17:57 +01:00
tracer faff70eb07 colorized the output of check permissions
Signed-off-by: tracer <tracer@24unix.net>
2022-03-01 18:17:33 +01:00
tracer cf95b67948 replaced print with echo
Signed-off-by: tracer <tracer@24unix.net>
2022-03-01 18:15:51 +01:00
tracer 0410d3b3a1 replaced print with echo
Signed-off-by: tracer <tracer@24unix.net>
2022-03-01 18:15:35 +01:00
tracer f776f7d16b replaced print with echo
Signed-off-by: tracer <tracer@24unix.net>
2022-03-01 18:15:05 +01:00
tracer a953e5cc66 replaced print with echo
Signed-off-by: tracer <tracer@24unix.net>
2022-03-01 18:14:33 +01:00
88 changed files with 28663 additions and 4759 deletions

14
.gitignore vendored
View File

@ -3,3 +3,17 @@
/config.json
/scratch
/swagger-ui/
/config.json.local
/bindAPI.log
/reports/
/bindAPI.test.log
/.phpunit.result.cache
/config.json.dev
/config.json.test
/config.json.prod
keys.txt
/.phpunit.cache
/var/log/*
/public/openapi/bindapi.json
/public/openapi/bootstrap.php

8
.idea/.gitignore vendored
View File

@ -1,8 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@ -1,48 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/bindAPI/src" isTestSource="false" packagePrefix="App\" />
<sourceFolder url="file://$MODULE_DIR$/spec" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/composer" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/phplucidframe/console-table" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/phpspec/prophecy" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/sebastian/comparator" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/myclabs/deep-copy" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/symfony/polyfill-ctype" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/phpdocumentor/reflection-docblock" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/phpdocumentor/type-resolver" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/phpunit/php-file-iterator" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/phpdocumentor/reflection-common" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/phpunit/php-invoker" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/webmozart/assert" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/phpunit/php-code-coverage" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/phpunit/php-text-template" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/phpunit/phpunit" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/phpunit/php-timer" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/doctrine/instantiator" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/phar-io/version" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/phar-io/manifest" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/sebastian/resource-operations" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/sebastian/exporter" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/sebastian/environment" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/sebastian/code-unit" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/sebastian/cli-parser" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/sebastian/version" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/sebastian/type" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/sebastian/lines-of-code" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/sebastian/recursion-context" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/nikic/php-parser" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/sebastian/diff" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/sebastian/code-unit-reverse-lookup" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/sebastian/complexity" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/theseer/tokenizer" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/sebastian/object-reflector" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/sebastian/object-enumerator" />
<excludeFolder url="file://$MODULE_DIR$/bindAPI/vendor/sebastian/global-state" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -1,5 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>

View File

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PublishConfigData" autoUpload="Always" serverName="executor.24unix.net" autoUploadExternalChanges="true">
<serverData>
<paths name="executor.24unix.net">
<serverdata>
<mappings>
<mapping deploy="/home/users/tfunix/www" local="$PROJECT_DIR$" web="/public" />
</mappings>
</serverdata>
</paths>
</serverData>
<option name="myAutoUpload" value="ALWAYS" />
</component>
</project>

View File

@ -1,107 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="DuplicatedCode" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<Languages>
<language minSize="115" name="PHP" />
</Languages>
</inspection_tool>
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="JSClassNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_minLength" value="3" />
</inspection_tool>
<inspection_tool class="JSXNamespaceValidation" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="MsBuiltinInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="MsOrderByInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="MysqlLoadDataPathInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="MysqlParsingInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PhpArgumentWithoutNamedIdentifierInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PhpArrayShapeAttributeCanBeAddedInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="PhpCSValidationInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false">
<option name="CODING_STANDARD" value="Custom" />
<option name="CUSTOM_RULESET_PATH" value="$PROJECT_DIR$/phpcs.xml.dist" />
<option name="USE_INSTALLED_PATHS" value="true" />
<option name="INSTALLED_PATHS" value="$PROJECT_DIR$/vendor/doctrine/coding-standard/lib/Doctrine" />
<option name="EXTENSIONS" value="php,js,css,inc" />
</inspection_tool>
<inspection_tool class="PhpCastIsUnnecessaryInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="PhpClassNamingConventionInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_minLength" value="3" />
<option name="m_maxLength" value="24" />
</inspection_tool>
<inspection_tool class="PhpConstantNamingConventionInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PhpFunctionNamingConventionInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_regex" value="[a-z][A-Za-z\d]*" />
<option name="m_minLength" value="2" />
<option name="m_maxLength" value="50" />
</inspection_tool>
<inspection_tool class="PhpMethodNamingConventionInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_minLength" value="2" />
<option name="m_maxLength" value="48" />
</inspection_tool>
<inspection_tool class="PhpMissingDocCommentInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PhpNamedArgumentUsageInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PhpNoReturnAttributeCanBeAddedInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="PhpNonCanonicalElementsOrderInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpPropertyNamingConventionInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_regex" value="[a-z][A-Z_a-z\d]*" />
<option name="m_minLength" value="1" />
<option name="m_maxLength" value="24" />
</inspection_tool>
<inspection_tool class="PhpPureAttributeCanBeAddedInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="PhpVariableNamingConventionInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_regex" value="[a-z][A-Za-z\d]*" />
<option name="m_minLength" value="1" />
<option name="m_maxLength" value="24" />
</inspection_tool>
<inspection_tool class="SqlAddNotNullColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlAggregatesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlAmbiguousColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlAutoIncrementDuplicateInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlCallNotationInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="SqlCaseVsCoalesceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlCaseVsIfInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlCheckUsingColumnsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlConstantConditionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlConstantExpressionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlCurrentSchemaInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlDeprecateTypeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlDerivedTableAliasInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlDialectInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlDropIndexedColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlDtInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlDuplicateColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlIdentifierInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlIllegalCursorStateInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlInsertIntoGeneratedColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlInsertNullIntoNotNullInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlInsertValuesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlJoinWithoutOnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlMisleadingReferenceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlMissingReturnInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="SqlMultipleLimitClausesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlNoDataSourceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlNullComparisonInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlRedundantAliasInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlRedundantCodeInCoalesceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlRedundantElseNullInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlRedundantLimitInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlRedundantOrderingDirectionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlResolveInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="SqlShadowingAliasInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlShouldBeInGroupByInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlSideEffectsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlSignatureInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlStorageInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlStringLengthExceededInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlTransactionStatementInTriggerInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlTriggerTransitionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlTypeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlUnicodeStringLiteralInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlUnreachableCodeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlUnusedCteInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlUnusedSubqueryItemInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlUnusedVariableInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlWithoutWhereInspection" enabled="false" level="WARNING" enabled_by_default="false" />
</profile>
</component>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/bindAPI.iml" filepath="$PROJECT_DIR$/.idea/bindAPI.iml" />
</modules>
</component>
</project>

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PhpProjectSharedConfiguration" php_language_level="8.1">
<option name="suggestChangeDefaultLanguageLevel" value="false" />
</component>
<component name="PhpUnit">
<phpunit_settings>
<PhpUnitSettings custom_loader_path="$PROJECT_DIR$/vendor/autoload.php" phpunit_phar_path="" />
</phpunit_settings>
</component>
</project>

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
<mapping directory="$PROJECT_DIR$/swagger-ui" vcs="Git" />
</component>
</project>

10
LICENCE Normal file
View File

@ -0,0 +1,10 @@
In short: it's just the MIT license:
Copyright 2022 Micha Espey (tracer@24unix.net)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

BIN
NOTES Normal file

Binary file not shown.

View File

@ -3,7 +3,12 @@
3. [Installation](#3-installation)
4. [Configuration](#4-configuration)
5. [The API](#5-the-api)
6. [Conclusion](#6-conclusion)
6. [DynDNS](#6-dyndns)
7. [Conclusion](#7-conclusion)
NOTICE: This documentation is not current as of September 2022.
After I finished the refactoring I'll upgrade it.
<a name="overview"></a>
# 1. Overview
@ -39,19 +44,16 @@ The CLI is used to perform configuration and some checks:
* apikeys
- manage the keys to access this nameserver via API
# 2.2. API
## 2.2. API
![OpenAPI](https://bindapi.24unix.net/assets/bindAPI_api1.png)
The APi is a RESTful API, there is a self explaining Swagger/OpenAPI available.
The API is a RESTful API, there is a self explaining Swagger/OpenAPI available.
<a name="installation"></a>
# 3. Installation
You can install the bindAPi on either a standalone server or an existing KeyHelp Panel.
However, slave zones are only managed for masters which lie on Keyhelp panels.
You can install the bindAPI on either a standalone server or an existing KeyHelp Panel. However, slave zones are only managed for masters which lie on Keyhelp panels.
## 3.1. Installation on a KeyHelp panel
@ -94,7 +96,7 @@ Here I will install it under /usr/local/bin, in the example with the standalone
`wget https://getcomposer.org/installer`
`php composer-setup.php --install-dir=/usr/local/bin --filename=composer`
`php installer --install-dir=/usr/local/bin --filename=composer`
Now we can change into our new user, remind to give him shell access in the panel.
@ -115,7 +117,13 @@ Remove the defaults files:
`rm *`
Next, we'll need to fetch the bindAPI (currently it has no release tag, that will change later)
Next, we'll need to fetch the bindAPI. As of now, the latest release is 1.0.1:
https://git.24unix.net/tracer/bindAPI/archive/1.0.1.tar.gz
I'd suggest checking here for the latest version:
https://git.24unix.net/tracer/bindAPI/releases
Or just use git to check out the latest update:
```
git clone https://git.24unix.net/tracer/bindAPI.git
@ -132,11 +140,11 @@ We need to pull the dependencies for composer:
`/usr/bin/keyhelp-php81 /usr/local/bin/composer update`
You might notice a quite strange command.
We need to call php with full path, and explicitly the 8.1 version.
KeyHelp relies on the default PHP installation, so the php binary will always point to 7.4 when your on Debian Bullseye.
You might notice a quite strange command. We need to call php with full path, and explicitly the 8.1 version. KeyHelp
relies on the default PHP installation, so the php binary will always point to 7.4 when you're on Debian Bullseye.
So, in bin/console the path to /usr/bin/keyhelp-php81 is hardcoded after the shebang, a step we have to remind if we install the standalone version.
So, in bin/console the path to /usr/bin/keyhelp-php81 is hardcoded after the shebang, a step we have to remind if we
install the standalone version.
Now make the CLI executable:
@ -151,19 +159,19 @@ Should I create a new config based on config.json.sample? (y/N): n
You first have to setup the bindAPI. Bye.
```
So now we can head back to our panel and set the Document root to
/home/users/tfunix/ns1.24unix.net/bindAPI/public.
So now we can head back to our panel and set the Document root to /home/users/tfunix/ns1.24unix.net/bindAPI/public.
Additionally, we have to change the open_basedir directive:
##DOCROOT##/www:##DOCROOT##/files:##DOCROOT##/tmp:/etc/bind:/etc/bind/local.zones
TODO: Screenshot
`##DOCROOT##/www:##DOCROOT##/files:##DOCROOT##/tmp:/etc/bind:/etc/bind/local.zones`
![Php Interpreter](https://bindapi.24unix.net/assets/bindAPI_phpsetting.png)
and remove exec from disabled functions.
OK, we are finished with the installation and head over to the [4. Configuration](#4-configuration).
## 3.2. Installation on a plain debian Bullseye
## 3.2. Installation on a plain Debian Bullseye
So, at first you should read and understand all steps in 3.1, as we will learn only the differences.
@ -292,10 +300,10 @@ GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, INDEX, DROP, ALTER, CREATE TEMPORA
There is no need to run FLUSH PRIVILEGES when using GRANT!
```
So, now it offers us the SQL statements to create a new user and database and set permissions.
If were on plain debian, we just can copy and paste (the password is random) this as root into mysql.
So, now it offers us the SQL statements to create a new user and database and set permissions. If were on plain debian,
we just can copy and paste (the password is random) this as root into mysql.
If we're using hte panel, lets create a database and write down the credentials and update config.json.
If we're using the panel, lets create a database and write down the credentials and update config.json.
And another call to the console:
@ -306,7 +314,7 @@ Should I try to create them? (y/N): y
Tables have been created.
```
When we now call the console it displays it's options:
When we now call the console it displays its options:
![CLI Interface](https://bindapi.24unix.net/assets/bindAPI_cli.png)
@ -405,7 +413,7 @@ No second level domains found.
Keyhelp-Panel: tector.24unix.net
No second level domains found.
```
The output is a little bit ugly, maybe I'll come up with something nicer.
The output is a bit ugly, maybe I'll come up with something nicer.
So, now we have our nameservers, our panels.
@ -416,7 +424,7 @@ We create a new key:
```
$ ./bin/console apikeys:create
API key 1 has been generated. Store it in a save place, it cannot be recovered.
6213acb116613.[truncated]]
6213acb116613.[truncated]
```
And add it to our list of nameservers:
@ -559,7 +567,7 @@ Keyhelp-Panel: paz.24unix.net
Domain: tzazicke.de ns1.24unix.net OK ns2.24unix.net OK ns3.24unix.net OK
```
Yes, all our domains from the given panel have been added to out nameserver.
Yes, all our domains from the given panel have been added to our nameserver.
Voila.
@ -595,10 +603,14 @@ curl -X 'GET' \
-H 'X-API-Key: 61f27a57c9d1f.[truncated]'
```
A helpful tool when dealing with API is [Postman](https://www.postman.com/), if offers the same options as from the OpenAPI interface or via shell with curl.
A helpful tool when dealing with API is [Postman](https://www.postman.com/), if offers the same options as from the
OpenAPI interface or via shell with curl.
![Php Interpreter](https://bindapi.24unix.net/assets/bindAPI_api6.png)
<a name="conclusion"></a>
# 6. Conclusion
# 6. DynDns
# 7. Conclusion

12
TODO Normal file
View File

@ -0,0 +1,12 @@
check:cache
check:bootstrap
check:version remove option update, we have -v as option
move stuff to dev:xxx which is not needed for endusers
make use of environment, somehow, dev, prod, test
check log file location
API Endpoint cleanup
check keytype of panel/bindApi
check:configkey => update config.json
more UNIT tests

View File

@ -1,3 +1,6 @@
1.0.1 (2022-03-01)
- added /dyndns endpoint to API
1.0.0 (2022-03-01)
- official release

View File

@ -1,128 +1,20 @@
#!/usr/bin/keyhelp-php81
#!/usr/bin/env php
<?php declare(strict_types=1);
namespace App\Controller;
// & ~E_DEPRECATED is needed because of a bug in PhpStorm
use DI\DependencyException;
use DI\NotFoundException;
use Exception;
error_reporting(error_level: E_ALL & ~E_DEPRECATED);
if (php_sapi_name() !== 'cli') {
exit;
echo 'This application must be run on the command line.' . PHP_EOL;
exit;
}
// version, store that somewhere else
$version = '0.0.1';
require dirname(path: __DIR__) . '/vendor/autoload.php';
$configFile = dirname(path: __DIR__) ."/config.json.local";
if (!file_exists(filename: $configFile)) {
$configFile = dirname(path: __DIR__) ."/config.json";
}
if (!file_exists(filename: $configFile)) {
echo 'Missing config file' . PHP_EOL;
if (confirm(message: 'Should I create a new config based on config.json.sample?')) {
copy(from: 'config.json.sample', to: 'config.json');
echo 'Config file has been generated. Adjust it to your needs, then proceed to database setup.' . PHP_EOL;
} else {
echo 'You first have to setup the bindAPI. Bye.' . PHP_EOL;
exit(0);
}
exit(1);
}
$configJSON = file_get_contents(filename: $configFile);
if (!$config = json_decode(json: $configJSON, associative: true)) {
echo 'Error parsing the config file.' . PHP_EOL;
echo $configJSON;
}
$shortOpts = 'v::'; // version
$shortOpts .= "V::"; // verbose
$shortOpts .= "h::"; // help
$longOpts = [
'version::',
'verbose::',
'help::'
];
$options = getopt(short_options: $shortOpts, long_options: $longOpts, rest_index: $restIndex);
if (array_key_exists(key: 'v', array: $options) || array_key_exists(key: 'version', array: $options) ) {
print("bindAPI version: $version" . PHP_EOL);
exit(0);
}
if (array_key_exists(key: 'h', array: $options) || array_key_exists(key: 'help', array: $options) ) {
print("Help …" . PHP_EOL);
exit(0);
}
if (array_key_exists(key: 'V', array: $options) || array_key_exists(key: 'verbose', array: $options) ) {
$config['verbose'] = true;
} else {
$config['verbose'] = false;
}
$arguments = array_slice(array: $argv, offset: $restIndex);
try {
$app = new BindAPI(config: $config, argumentsCount: count(value: $arguments), arguments: $arguments);
$app->runCommand();
} catch (DependencyException|NotFoundException $e) {
echo $e->getMessage();
exit(1);
} catch (Exception $e) {
echo $e->getMessage();
}
/**
* @param String $message
* @param array $options
* @param string $default
*
* @return bool
*/
function confirm(String $message = 'Are you sure? ', array $options = ['y', 'n'], string $default ='n'): bool
{
// first $options means true, any other false
echo $message, ' (';
$first = true;
foreach ($options as $option) {
// mark default
if ($option == $default) {
$option = strtoupper(string: $option);
}
if ($first) {
echo $option;
$first = false;
} else {
echo '/', $option;
}
}
echo '): ';
$handle = fopen(filename: "php://stdin", mode: 'r');
$line = trim(string: fgetc(stream: $handle));
fclose(stream: $handle);
if ($line == '') {
// enter
$line = $default;
}
if ($line == $options[0]) {
$result = true;
} else {
$result = false;
}
return $result;
// check php version (must be >= 8.1)
/** @noinspection PhpArgumentWithoutNamedIdentifierInspection */
if (version_compare(PHP_VERSION, '8.1.0', '<')) {
echo 'This application requires PHP 8.1 or newer. You are running ' . PHP_VERSION . PHP_EOL;
echo 'If you are using KeyHelp, use keyhelp-php81 ' . $argv[0] . ' instead.' . PHP_EOL;
exit;
}
/** @noinspection PhpArgumentWithoutNamedIdentifierInspection */
require dirname(__DIR__, 1) . '/src/Util/Console.php';

148
bindapi.json Normal file
View File

@ -0,0 +1,148 @@
{
"openapi": "3.0.0",
"info": {
"title": "bindAPI",
"version": "1.0.9"
},
"servers": [
{
"url": "{schema}://{hostname}/api",
"description": "The bindAPI URL.",
"variables": {
"schema": {
"enum": [
"http",
"https"
],
"default": "https"
},
"hostname": {
"enum": [
"ns1.24unix.net",
"ns2.24unix.net"
],
"default": "ns2.24unix.net"
}
}
}
],
"paths": {
"/ping": {
"get": {
"tags": [
"Server"
],
"description": "Checks for connectivity and valid APIkey",
"operationId": "ping",
"responses": {
"200": {
"description": "OK"
},
"401": {
"description": "API key is missing or invalid."
}
},
"security": [
{
"Authorization": []
}
]
}
},
"/version": {
"get": {
"tags": [
"Server"
],
"description": "Check the API version of the nameserver.",
"operationId": "version",
"responses": {
"200": {
"description": "x.y.z, aka major, minor, patch"
},
"401": {
"description": "API key is missing or invalid."
}
},
"security": [
{
"Authorization": []
}
]
}
},
"/domains": {
"get": {
"tags": [
"Domains"
],
"summary": "List all domains.",
"description": "Returns a list of all domains on this server.",
"operationId": "getAllDomains",
"responses": {
"200": {
"description": "OK"
},
"401": {
"description": "API key is missing or invalid."
},
"404": {
"description": "Domain not found."
}
},
"security": [
{
"Authorization": []
}
]
}
},
"/domains/{name}": {
"get": {
"tags": [
"Domains"
],
"summary": "Returns a single domain.",
"description": "Returns information of a single domain specified by its domain name.",
"operationId": "getSingleDomain",
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK"
},
"401": {
"description": "API key is missing or invalid."
},
"404": {
"description": "Domain not found."
}
},
"security": []
}
}
},
"components": {
"securitySchemes": {
"Authorization": {
"type": "apiKey",
"description": "Api Authentication",
"name": "X-API-Key",
"in": "header"
}
}
},
"tags": [
{
"name": "Server"
}
]
}

View File

@ -1,44 +1,58 @@
{
"name": "tracer/bindppi",
"authors": [
{
"name": "Micha Espey",
"email": "tracer@24unix.net"
}
],
"type": "project",
"license": "proprietary",
"minimum-stability": "stable",
"prefer-stable": true,
"require": {
"php": ">=8.1",
"ext-curl": "*",
"ext-json": "*",
"ext-pdo": "*",
"arubacao/tld-checker": "^1.2",
"monolog/monolog": "^2.3",
"php-di/php-di": "^6.3",
"phplucidframe/console-table": "^1.2",
"zircote/swagger-php": "^4.2"
},
"config": {
"optimize-autoloader": true,
"preferred-install": {
"*": "dist"
},
"sort-packages": true
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Src\\": "src/"
}
},
"require-dev": {
"phpunit/phpunit": "^9.5"
"name": "24unix/bindapi",
"description": "manage Bind9 DNS server via REST API",
"version": "1.0.9",
"build_number": "375",
"authors": [
{
"name": "Micha Espey",
"email": "tracer@24unix.net"
}
],
"type": "project",
"license": "MIT",
"minimum-stability": "stable",
"prefer-stable": true,
"require": {
"php": ">=8.2",
"ext-curl": "*",
"ext-json": "*",
"ext-mbstring": "*",
"ext-openssl": "*",
"ext-pdo": "*",
"ext-posix": "*",
"ext-sodium": "*",
"arubacao/tld-checker": "^1.2",
"bartlett/php-compatinfo": "^7.1",
"monolog/monolog": "^3.1",
"netresearch/jsonmapper": "^4.4",
"php-di/php-di": "^6.3",
"phplucidframe/console-table": "^1.2",
"robmorgan/phinx": "^0.15",
"symfony/property-access": "^6.1",
"symfony/serializer": "^6.1",
"zircote/swagger-php": "^4.8"
},
"config": {
"optimize-autoloader": true,
"preferred-install": {
"*": "dist"
},
"sort-packages": true
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Src\\": "src/"
}
},
"require-dev": {
"escapestudios/symfony2-coding-standard": "3.x-dev",
"odan/phinx-migrations-generator": "^6.1",
"phpunit/phpunit": "10"
}
}

5797
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,10 @@
{
"env": "prod",
"dbHost": "localhost",
"dbPort": 3306,
"dbDatabase": "sampledb",
"dbUser": "sampleuser",
"dbPassword": "secret",
"encryptionKey": "1bad::babe",
"debug": false
}

View File

@ -0,0 +1,255 @@
<?php
use Phinx\Db\Adapter\MysqlAdapter;
class TableCreation extends Phinx\Migration\AbstractMigration
{
public function change()
{
$this->table('migrations', [
'id' => false,
'engine' => 'InnoDB',
'encoding' => 'utf8mb4',
'collation' => 'utf8mb4_general_ci',
'comment' => '',
'row_format' => 'DYNAMIC',
])
->addColumn('id', 'integer', [
'null' => false,
'limit' => MysqlAdapter::INT_REGULAR,
])
->addColumn('name', 'string', [
'null' => false,
'limit' => 255,
'collation' => 'utf8mb4_general_ci',
'encoding' => 'utf8mb4',
'after' => 'id',
])
->addColumn('executedAt', 'date', [
'null' => false,
'after' => 'name',
])
->create();
$this->table('config', [
'id' => false,
'engine' => 'InnoDB',
'encoding' => 'utf8mb4',
'collation' => 'utf8mb4_general_ci',
'comment' => '',
'row_format' => 'DYNAMIC',
])
->addColumn('version', 'string', [
'null' => false,
'limit' => 11,
'collation' => 'utf8mb4_general_ci',
'encoding' => 'utf8mb4',
])
->create();
$this->table('panels', [
'id' => false,
'primary_key' => ['id'],
'engine' => 'InnoDB',
'encoding' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'comment' => '',
'row_format' => 'DYNAMIC',
])
->addColumn('id', 'integer', [
'null' => false,
'limit' => MysqlAdapter::INT_REGULAR,
'identity' => true,
])
->addColumn('name', 'string', [
'null' => false,
'limit' => 255,
'collation' => 'utf8mb4_unicode_ci',
'encoding' => 'utf8mb4',
'after' => 'id',
])
->addColumn('a', 'varbinary', [
'null' => true,
'default' => null,
'limit' => 255,
'after' => 'name',
])
->addColumn('aaaa', 'varbinary', [
'null' => true,
'default' => null,
'limit' => 255,
'after' => 'a',
])
->addColumn('apikey', 'varbinary', [
'null' => true,
'default' => null,
'limit' => 255,
'after' => 'aaaa',
])
->addColumn('apikey_prefix', 'string', [
'null' => false,
'limit' => 8,
'collation' => 'utf8mb4_unicode_ci',
'encoding' => 'utf8mb4',
'after' => 'apikey',
])
->addColumn('self', 'enum', [
'null' => false,
'default' => 'no',
'limit' => 3,
'values' => ['yes', 'no'],
'after' => 'apikey_prefix',
])
->create();
$this->table('dyndns', [
'id' => false,
'primary_key' => ['id'],
'engine' => 'InnoDB',
'encoding' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'comment' => '',
'row_format' => 'DYNAMIC',
])
->addColumn('id', 'integer', [
'null' => false,
'limit' => MysqlAdapter::INT_REGULAR,
'identity' => true,
])
->addColumn('name', 'string', [
'null' => false,
'limit' => 255,
'collation' => 'utf8mb4_unicode_ci',
'encoding' => 'utf8mb4',
'after' => 'id',
])
->addColumn('a', 'varbinary', [
'null' => false,
'limit' => 255,
'after' => 'name',
])
->addColumn('aaaa', 'varbinary', [
'null' => false,
'limit' => 255,
'after' => 'a',
])
->addColumn('last_update', 'timestamp', [
'null' => false,
'default' => 'current_timestamp()',
'update' => 'CURRENT_TIMESTAMP',
'after' => 'aaaa',
])
->create();
$this->table('domains', [
'id' => false,
'primary_key' => ['id'],
'engine' => 'InnoDB',
'encoding' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'comment' => '',
'row_format' => 'DYNAMIC',
])
->addColumn('id', 'integer', [
'null' => false,
'limit' => MysqlAdapter::INT_REGULAR,
'identity' => true,
])
->addColumn('name', 'string', [
'null' => false,
'limit' => 255,
'collation' => 'utf8mb4_unicode_ci',
'encoding' => 'utf8mb4',
'after' => 'id',
])
->addColumn('panel', 'string', [
'null' => true,
'default' => null,
'limit' => 255,
'collation' => 'utf8mb4_unicode_ci',
'encoding' => 'utf8mb4',
'after' => 'name',
])
->create();
$this->table('apikeys', [
'id' => false,
'primary_key' => ['id'],
'engine' => 'InnoDB',
'encoding' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'comment' => '',
'row_format' => 'DYNAMIC',
])
->addColumn('id', 'integer', [
'null' => false,
'limit' => MysqlAdapter::INT_REGULAR,
'identity' => true,
])
->addColumn('name', 'string', [
'null' => true,
'default' => null,
'limit' => 255,
'collation' => 'utf8mb4_unicode_ci',
'encoding' => 'utf8mb4',
'after' => 'id',
])
->addColumn('apikey_prefix', 'string', [
'null' => false,
'limit' => 13,
'collation' => 'utf8mb4_unicode_ci',
'encoding' => 'utf8mb4',
'after' => 'name',
])
->addColumn('apikey', 'string', [
'null' => false,
'limit' => 255,
'collation' => 'utf8mb4_unicode_ci',
'encoding' => 'utf8mb4',
'after' => 'apikey_prefix',
])
->create();
$this->table('nameservers', [
'id' => false,
'primary_key' => ['id'],
'engine' => 'InnoDB',
'encoding' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'comment' => '',
'row_format' => 'DYNAMIC',
])
->addColumn('id', 'integer', [
'null' => false,
'limit' => MysqlAdapter::INT_REGULAR,
'identity' => true,
])
->addColumn('name', 'string', [
'null' => false,
'limit' => 255,
'collation' => 'utf8mb4_unicode_ci',
'encoding' => 'utf8mb4',
'after' => 'id',
])
->addColumn('a', 'varbinary', [
'null' => true,
'default' => null,
'limit' => 255,
'after' => 'name',
])
->addColumn('aaaa', 'varbinary', [
'null' => true,
'default' => null,
'limit' => 255,
'after' => 'a',
])
->addColumn('apikey', 'varbinary', [
'null' => true,
'default' => null,
'limit' => 255,
'after' => 'aaaa',
])
->addColumn('apikey_prefix', 'string', [
'null' => false,
'limit' => 13,
'collation' => 'utf8mb4_unicode_ci',
'encoding' => 'utf8mb4',
'after' => 'apikey',
])
->create();
}
}

View File

@ -0,0 +1,33 @@
<?php
use Phinx\Db\Adapter\MysqlAdapter;
class ConfigTable extends Phinx\Migration\AbstractMigration
{
public function change()
{
$this->table('config', [
'id' => false,
'engine' => 'InnoDB',
'encoding' => 'utf8mb4',
'collation' => 'utf8mb4_general_ci',
'comment' => '',
'row_format' => 'DYNAMIC',
])
->addColumn('name', 'string', [
'null' => false,
'limit' => 256,
'collation' => 'utf8mb4_general_ci',
'encoding' => 'utf8mb4',
])
->addColumn('value', 'string', [
'null' => false,
'limit' => 256,
'collation' => 'utf8mb4_general_ci',
'encoding' => 'utf8mb4',
'after' => 'name',
])
->removeColumn('version')
->save();
}
}

View File

@ -0,0 +1,24 @@
<?php
use Phinx\Db\Adapter\MysqlAdapter;
class ApiKeyCreationDate extends Phinx\Migration\AbstractMigration
{
public function change()
{
$this->table('apikeys', [
'id' => false,
'primary_key' => ['id'],
'engine' => 'InnoDB',
'encoding' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'comment' => '',
'row_format' => 'DYNAMIC',
])
->addColumn('created_at', 'timestamp', [
'null' => false,
'after' => 'apikey',
])
->save();
}
}

View File

@ -0,0 +1,24 @@
<?php
use Phinx\Db\Adapter\MysqlAdapter;
class UniqueConfigValues extends Phinx\Migration\AbstractMigration
{
public function change()
{
$this->table('config', [
'id' => false,
'primary_key' => ['name'],
'engine' => 'InnoDB',
'encoding' => 'utf8mb4',
'collation' => 'utf8mb4_general_ci',
'comment' => '',
'row_format' => 'DYNAMIC',
])
->addIndex(['name'], [
'name' => 'name',
'unique' => true,
])
->save();
}
}

View File

@ -0,0 +1,25 @@
<?php
use Phinx\Db\Adapter\MysqlAdapter;
class TimeStampDefaultforApiKeys extends Phinx\Migration\AbstractMigration
{
public function change()
{
$this->table('apikeys', [
'id' => false,
'primary_key' => ['id'],
'engine' => 'InnoDB',
'encoding' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'comment' => '',
'row_format' => 'DYNAMIC',
])
->changeColumn('created_at', 'timestamp', [
'null' => true,
'default' => 'current_timestamp()',
'after' => 'apikey',
])
->save();
}
}

View File

@ -0,0 +1,37 @@
<?php
use Phinx\Db\Adapter\MysqlAdapter;
class AddSelfToNameservers extends Phinx\Migration\AbstractMigration
{
public function change()
{
// $this->table('domains', [
// 'id' => false,
// 'primary_key' => ['id'],
// 'engine' => 'InnoDB',
// 'encoding' => 'utf8mb4',
// 'collation' => 'utf8mb4_unicode_ci',
// 'comment' => '',
// 'row_format' => 'DYNAMIC',
// ])
// ->removeColumn('self')
// ->save();
$this->table('nameservers', [
'id' => false,
'primary_key' => ['id'],
'engine' => 'InnoDB',
'encoding' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'comment' => '',
'row_format' => 'DYNAMIC',
])
->addColumn('self', 'enum', [
'null' => false,
'limit' => 3,
'values' => ['yes', 'no'],
'after' => 'apikey_prefix',
])
->save();
}
}

View File

@ -0,0 +1,41 @@
<?php
use Phinx\Db\Adapter\MysqlAdapter;
class UUIDForConfig extends Phinx\Migration\AbstractMigration
{
public function change()
{
$this->table('config', [
'id' => false,
'primary_key' => ['id'],
'engine' => 'InnoDB',
'encoding' => 'utf8mb4',
'collation' => 'utf8mb4_general_ci',
'comment' => '',
'row_format' => 'DYNAMIC',
])
->addColumn('id', 'uuid', [
'null' => false,
])
->changeColumn('name', 'string', [
'null' => false,
'limit' => 256,
'collation' => 'utf8mb4_general_ci',
'encoding' => 'utf8mb4',
'after' => 'id',
])
->changeColumn('value', 'string', [
'null' => false,
'limit' => 256,
'collation' => 'utf8mb4_general_ci',
'encoding' => 'utf8mb4',
'after' => 'name',
])
->addIndex(['id'], [
'name' => 'id',
'unique' => true,
])
->save();
}
}

View File

@ -0,0 +1,24 @@
<?php
use Phinx\Db\Adapter\MysqlAdapter;
class DefaultUUIDforConfig extends Phinx\Migration\AbstractMigration
{
public function change()
{
$this->table('config', [
'id' => false,
'primary_key' => ['id'],
'engine' => 'InnoDB',
'encoding' => 'utf8mb4',
'collation' => 'utf8mb4_general_ci',
'comment' => '',
'row_format' => 'DYNAMIC',
])
->changeColumn('id', 'uuid', [
'null' => false,
'default' => 'uuid()',
])
->save();
}
}

1238
db/migrations/schema.php Normal file

File diff suppressed because it is too large Load Diff

6
dist/systemd/README.md vendored Normal file
View File

@ -0,0 +1,6 @@
Copy these files to /etc/systems/system, adapt the path in the service unit and enable the timer by issuing:
systemctl daemon-reload
systemctl enable bindAPI.timer
systemctl start bindAPI.timer
systemctl list-timers

6
dist/systemd/bindAPI.service vendored Normal file
View File

@ -0,0 +1,6 @@
[Unit]
Description=BindAPI Service to check zone file and reload configuration
[Service]
User=<paneluser>
ExecStart=/home/users/<user>/<bindApi>/bin/console -q cron:run

10
dist/systemd/bindAPI.timer vendored Normal file
View File

@ -0,0 +1,10 @@
[Unit]
Description=Runs BindAPI every minute
[Timer]
OnBootSec=1min
OnUnitActiveSec=1min
Unit=bindAPI.service
[Install]
WantedBy=timers.target

8
hooks/post-commit Executable file
View File

@ -0,0 +1,8 @@
#!/bin/bash
# calculate build number
build_number=$(git rev-list --count HEAD)
# add build number to composer.json using jq
jq --arg bn "$build_number" '.build_number = $bn' composer.json > tmp.$$.json && mv tmp.$$.json composer.json

View File

@ -1 +0,0 @@

40
phinx.php Normal file
View File

@ -0,0 +1,40 @@
<?php
use App\Controller\ConfigController;
require 'vendor/autoload.php';
$configController = new ConfigController(quiet: true);
$dbHost = $configController->getConfig(configKey: 'dbHost');
$dbPort = $configController->getConfig(configKey: 'dbPort');
$dbDatabase = $configController->getConfig(configKey: 'dbDatabase');
$dbUser = $configController->getConfig(configKey: 'dbUser');
$dbPassword = $configController->getConfig(configKey: 'dbPassword');
// unlike the example config, we don't maintain different environments here,
// that is set globally, currently by selecting the matching config.json.
// but that might change to envfiles in the future
return
[
'paths' => [
'migrations' => '%%PHINX_CONFIG_DIR%%/db/migrations',
'seeds' => '%%PHINX_CONFIG_DIR%%/db/seeds'
],
'environments' => [
'default_migration_table' => 'phinxlog',
'default_environment' => 'default',
'default' => [
'adapter' => 'mysql',
'host' => $dbHost,
'name' => $dbDatabase,
'user' => $dbUser,
'pass' => $dbPassword,
'port' => $dbPort,
'charset' => 'utf8',
],
],
'version_order' => 'creation'
];

View File

@ -1,8 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/autoload.php">
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd"
bootstrap="vendor/autoload.php"
cacheResultFile=".phpunit.cache/test-results"
executionOrder="depends,defects"
forceCoversAnnotation="false"
beStrictAboutCoversAnnotation="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
convertDeprecationsToExceptions="true"
failOnRisky="true"
failOnWarning="true"
verbose="true">
<testsuites>
<testsuite name="bindAPI Test Suite">
<directory suffix=".php">./tests/</directory>
<testsuite name="default">
<directory>tests</directory>
</testsuite>
</testsuites>
</phpunit>
<coverage cacheDirectory=".phpunit.cache/code-coverage"
processUncoveredFiles="true">
<include>
<directory suffix=".php">src</directory>
</include>
</coverage>
</phpunit>

1
public/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
log.txt

View File

@ -1,54 +1,47 @@
<?php declare(strict_types=1);
namespace App\Controller;
use Exception;
use App\Service\BindAPI;
error_reporting(error_level: E_ALL);
require dirname(path: __DIR__) . '/vendor/autoload.php';
// read config
$configFile = dirname(path: __DIR__) . "/config.json";
$configJSON = file_get_contents(filename: $configFile);
$config = json_decode(json: $configJSON, associative: true);
$parsedUrl = parse_url(url: $_SERVER['REQUEST_URI'], component: PHP_URL_PATH);
$uri = explode(separator: '/', string: $parsedUrl);
$baseRoutes = ['app', 'api'];
$uriPrefix = $uriFirstThreeLetters = substr(string: $uri[1], offset: 0, length: 3);
// TODO make a log class
$oFile = fopen(filename: 'log.txt', mode: 'a');
$uri = parse_url(url: $_SERVER['REQUEST_URI'], component: PHP_URL_PATH);
fputs(stream: $oFile, data: $uri . PHP_EOL);
fputs(stream: $oFile, data: "here");
$uri = explode(separator: '/', string: $uri);
fclose(stream: $oFile);
if ($uri[1] !== 'api') {
if (!in_array(needle: $uriPrefix, haystack: $baseRoutes)) {
// only handle $baseRoutes, elso go to swagger ui
$scheme = $_SERVER['REQUEST_SCHEME'];
$host = $_SERVER['SERVER_NAME'];
$header = "$scheme://$host/openapi/index.html";
header(header: "Location: $header");
exit(0);
}
// TODO only valid clients?
header(header: "Access-Control-Allow-Origin: *");
header(header: "Content-Type: application/json; charset=UTF-8");
header(header: "Access-Control-Allow-Methods: OPTIONS,GET,POST,PUT,DELETE");
header(header: "Access-Control-Max-Age: 3600");
header(header: "Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
header(header: "Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With, x-api-key");
$requestMethod = $_SERVER["REQUEST_METHOD"];
if ($requestMethod === "OPTIONS") {
// Respond with OK status code for preflight requests
http_response_code(response_code: 200);
exit();
}
try {
$controller = new RequestController(config: $config, requestMethod: $requestMethod, uri: $uri);
$controller->processRequest();
$app = new BindAPI(quiet: false);
$app->handleRequest(requestMethod: $requestMethod, uri: $uri);
} catch (Exception $e) {
echo json_encode(value: [
'error' => $e->getMessage()
]);
}

949
public/matrix.php Normal file
View File

@ -0,0 +1,949 @@
nothing to do
====
[11-Oct-2022 17:47:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 17:48:02] INFO --> load tasks... nothing to do
====
[11-Oct-2022 17:49:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 17:50:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 17:51:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 17:52:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 17:53:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 17:54:02] INFO --> load tasks... nothing to do
====
[11-Oct-2022 17:55:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 17:56:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 17:57:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 17:58:02] INFO --> load tasks... nothing to do
====
[11-Oct-2022 17:59:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:00:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:01:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:02:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:03:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:04:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:05:02] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:06:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:07:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:08:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:09:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:10:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:11:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:12:02] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:13:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:14:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:15:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:16:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:17:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:18:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:19:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:20:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:21:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:22:02] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:23:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:24:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:25:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:26:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:27:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:28:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:29:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:30:02] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:31:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:32:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:33:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:34:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:35:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:36:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:37:02] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:38:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:39:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:40:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:41:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:42:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:43:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:44:02] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:45:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:46:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:47:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 18:48:01] INFO --> load tasks... notp
[PID-31506] [11-Oct-2022 20:32:01] INFO --> >>> trying to run "update"
[PID-31506] [11-Oct-2022 20:32:01] INFO --> lock "update" acquired
[PID-31506] [11-Oct-2022 20:32:01] INFO --> processing the job ...
[PID-31506] [11-Oct-2022 20:32:01] INFO --> <<< job done, releasing lock "update"
====
[PID-31633] [11-Oct-2022 20:33:01] INFO --> jobs to run: update.php
[PID-31633] [11-Oct-2022 20:33:01] INFO --> >>> trying to run "update"
[PID-31633] [11-Oct-2022 20:33:01] INFO --> lock "update" acquired
[PID-31633] [11-Oct-2022 20:33:01] INFO --> processing the job ...
[PID-31633] [11-Oct-2022 20:33:01] INFO --> <<< job done, releasing lock "update"
====
[PID-31726] [11-Oct-2022 20:34:01] INFO --> jobs to run: update.php
[PID-31726] [11-Oct-2022 20:34:01] INFO --> >>> trying to run "update"
[PID-31726] [11-Oct-2022 20:34:01] INFO --> lock "update" acquired
[PID-31726] [11-Oct-2022 20:34:01] INFO --> processing the job ...
[PID-31726] [11-Oct-2022 20:34:01] INFO --> <<< job done, releasing lock "update"
====
[PID-31803] [11-Oct-2022 20:35:01] INFO --> jobs to run: update.php
[PID-31803] [11-Oct-2022 20:35:01] INFO --> >>> trying to run "update"
[PID-31803] [11-Oct-2022 20:35:01] INFO --> lock "update" acquired
[PID-31803] [11-Oct-2022 20:35:01] INFO --> processing the job ...
[PID-31803] [11-Oct-2022 20:35:01] INFO --> <<< job done, releasing lock "update"
====
[PID-31896] [11-Oct-2022 20:36:01] INFO --> jobs to run: update.php
[PID-31896] [11-Oct-2022 20:36:01] INFO --> >>> trying to run "update"
[PID-31896] [11-Oct-2022 20:36:01] INFO --> lock "update" acquired
[PID-31896] [11-Oct-2022 20:36:01] INFO --> processing the job ...
[PID-31896] [11-Oct-2022 20:36:01] INFO --> <<< job done, releasing lock "update"
====
[PID-31978] [11-Oct-2022 20:37:01] INFO --> jobs to run: update.php
[PID-31978] [11-Oct-2022 20:37:01] INFO --> >>> trying to run "update"
[PID-31978] [11-Oct-2022 20:37:01] INFO --> lock "update" acquired
[PID-31978] [11-Oct-2022 20:37:01] INFO --> processing the job ...
[PID-31978] [11-Oct-2022 20:37:01] INFO --> <<< job done, releasing lock "update"
====
[PID-32071] [11-Oct-2022 20:38:01] INFO --> jobs to run: update.php
[PID-32071] [11-Oct-2022 20:38:01] INFO --> >>> trying to run "update"
[PID-32071] [11-Oct-2022 20:38:01] INFO --> lock "update" acquired
[PID-32071] [11-Oct-2022 20:38:01] INFO --> processing the job ...
[PID-32071] [11-Oct-2022 20:38:01] INFO --> <<< job done, releasing lock "update"
====
[PID-32160] [11-Oct-2022 20:39:02] INFO --> jobs to run: update.php
[PID-32160] [11-Oct-2022 20:39:02] INFO --> >>> trying to run "update"
[PID-32160] [11-Oct-2022 20:39:02] INFO --> lock "update" acquired
[PID-32160] [11-Oct-2022 20:39:02] INFO --> processing the job ...
[PID-32160] [11-Oct-2022 20:39:02] INFO --> <<< job done, releasing lock "update"
====
[PID-32325] [11-Oct-2022 20:40:01] INFO --> jobs to run: update.php
[PID-32325] [11-Oct-2022 20:40:01] INFO --> >>> trying to run "update"
[PID-32325] [11-Oct-2022 20:40:01] INFO --> lock "update" acquired
[PID-32325] [11-Oct-2022 20:40:01] INFO --> processing the job ...
[PID-32325] [11-Oct-2022 20:40:01] INFO --> <<< job done, releasing lock "update"
====
[PID-32420] [11-Oct-2022 20:41:01] INFO --> jobs to run: update.php
[PID-32420] [11-Oct-2022 20:41:01] INFO --> >>> trying to run "update"
[PID-32420] [11-Oct-2022 20:41:01] INFO --> lock "update" acquired
[PID-32420] [11-Oct-2022 20:41:01] INFO --> processing the job ...
[PID-32420] [11-Oct-2022 20:41:01] INFO --> <<< job done, releasing lock "update"
====
[PID-32507] [11-Oct-2022 20:42:01] INFO --> jobs to run: update.php
[PID-32507] [11-Oct-2022 20:42:01] INFO --> >>> trying to run "update"
[PID-32507] [11-Oct-2022 20:42:01] INFO --> lock "update" acquired
[PID-32507] [11-Oct-2022 20:42:01] INFO --> processing the job ...
[PID-32507] [11-Oct-2022 20:42:01] INFO --> <<< job done, releasing lock "update"
====
[PID-32590] [11-Oct-2022 20:43:01] INFO --> jobs to run: update.php
[PID-32590] [11-Oct-2022 20:43:01] INFO --> >>> trying to run "update"
[PID-32590] [11-Oct-2022 20:43:01] INFO --> lock "update" acquired
[PID-32590] [11-Oct-2022 20:43:01] INFO --> processing the job ...
[PID-32590] [11-Oct-2022 20:43:01] INFO --> <<< job done, releasing lock "update"
====
[PID-32684] [11-Oct-2022 20:44:01] INFO --> jobs to run: update.php
[PID-32684] [11-Oct-2022 20:44:01] INFO --> >>> trying to run "update"
[PID-32684] [11-Oct-2022 20:44:01] INFO --> lock "update" acquired
[PID-32684] [11-Oct-2022 20:44:01] INFO --> processing the job ...
[PID-32684] [11-Oct-2022 20:44:01] INFO --> <<< job done, releasing lock "update"
====
[PID-32775] [11-Oct-2022 20:45:01] INFO --> jobs to run: update.php
[PID-32775] [11-Oct-2022 20:45:01] INFO --> >>> trying to run "update"
[PID-32775] [11-Oct-2022 20:45:01] INFO --> lock "update" acquired
[PID-32775] [11-Oct-2022 20:45:01] INFO --> processing the job ...
[PID-32775] [11-Oct-2022 20:45:01] INFO --> <<< job done, releasing lock "update"
====
[PID-32852] [11-Oct-2022 20:46:01] INFO --> jobs to run: update.php
[PID-32852] [11-Oct-2022 20:46:01] INFO --> >>> trying to run "update"
[PID-32852] [11-Oct-2022 20:46:01] INFO --> lock "update" acquired
[PID-32852] [11-Oct-2022 20:46:01] INFO --> processing the job ...
[PID-32852] [11-Oct-2022 20:46:01] INFO --> <<< job done, releasing lock "update"
====
[PID-32944] [11-Oct-2022 20:47:01] INFO --> jobs to run: update.php
[PID-32944] [11-Oct-2022 20:47:01] INFO --> >>> trying to run "update"
[PID-32944] [11-Oct-2022 20:47:01] INFO --> lock "update" acquired
[PID-32944] [11-Oct-2022 20:47:02] INFO --> processing the job ...
[PID-32944] [11-Oct-2022 20:47:02] INFO --> <<< job done, releasing lock "update"
====
[PID-33036] [11-Oct-2022 20:48:01] INFO --> jobs to run: update.php
[PID-33036] [11-Oct-2022 20:48:01] INFO --> >>> trying to run "update"
[PID-33036] [11-Oct-2022 20:48:01] INFO --> lock "update" acquired
[PID-33036] [11-Oct-2022 20:48:01] INFO --> processing the job ...
[PID-33036] [11-Oct-2022 20:48:01] INFO --> <<< job done, releasing lock "update"
====
[PID-33113] [11-Oct-2022 20:49:01] INFO --> jobs to run: update.php
[PID-33113] [11-Oct-2022 20:49:01] INFO --> >>> trying to run "update"
[PID-33113] [11-Oct-2022 20:49:01] INFO --> lock "update" acquired
[PID-33113] [11-Oct-2022 20:49:01] INFO --> processing the job ...
[PID-33113] [11-Oct-2022 20:49:01] INFO --> <<< job done, releasing lock "update"
====
[PID-33215] [11-Oct-2022 20:50:01] INFO --> jobs to run: update.php
[PID-33215] [11-Oct-2022 20:50:01] INFO --> >>> trying to run "update"
[PID-33215] [11-Oct-2022 20:50:01] INFO --> lock "update" acquired
[PID-33215] [11-Oct-2022 20:50:01] INFO --> processing the job ...
[PID-33215] [11-Oct-2022 20:50:01] INFO --> <<< job done, releasing lock "update"
====
[PID-33295] [11-Oct-2022 20:51:01] INFO --> jobs to run: update.php
[PID-33295] [11-Oct-2022 20:51:01] INFO --> >>> trying to run "update"
[PID-33295] [11-Oct-2022 20:51:01] INFO --> lock "update" acquired
[PID-33295] [11-Oct-2022 20:51:01] INFO --> processing the job ...
[PID-33295] [11-Oct-2022 20:51:01] INFO --> <<< job done, releasing lock "update"
====
[PID-33386] [11-Oct-2022 20:52:01] INFO --> jobs to run: update.php, diskspace.php
[PID-33386] [11-Oct-2022 20:52:01] INFO --> >>> trying to run "update"
[PID-33386] [11-Oct-2022 20:52:01] INFO --> lock "update" acquired
[PID-33386] [11-Oct-2022 20:52:01] INFO --> processing the job ...
[PID-33386] [11-Oct-2022 20:52:01] INFO --> <<< job done, releasing lock "update"
[PID-33386] [11-Oct-2022 20:52:01] INFO --> >>> trying to run "diskspace"
[PID-33386] [11-Oct-2022 20:52:01] INFO --> lock "diskspace" acquired
[PID-33386] [11-Oct-2022 20:52:01] INFO --> processing the job ...
[PID-33386] [11-Oct-2022 20:52:01] INFO --> <<< job done, releasing lock "diskspace"
====
[PID-33495] [11-Oct-2022 20:53:01] INFO --> jobs to run: update.php
[PID-33495] [11-Oct-2022 20:53:01] INFO --> >>> trying to run "update"
[PID-33495] [11-Oct-2022 20:53:01] INFO --> lock "update" acquired
[PID-33495] [11-Oct-2022 20:53:01] INFO --> processing the job ...
[Pdo
====
[11-Oct-2022 20:53:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 20:54:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 20:55:02] INFO --> load tasks... nothing to do
====
[11-Oct-2022 20:56:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 20:57:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 20:58:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 20:59:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:00:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:01:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:02:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:03:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:04:02] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:05:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:06:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:07:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:08:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:09:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:10:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:11:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:12:02] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:13:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:14:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:15:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:16:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:17:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:18:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:19:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:20:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:21:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:22:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:23:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:24:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:25:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:26:02] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:27:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:28:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:29:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:30:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:31:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:32:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:33:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:34:02] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:35:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:36:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:37:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:38:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:39:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:40:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:41:02] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:42:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:43:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:44:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:45:02] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:46:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:47:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:48:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:49:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:50:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:51:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:52:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:53:02] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:54:01] INFO --> load tasks... nothing to do
=ID-33495] [11-Oct-2022 20:53:01] INFO --> <<< job done, releasing lock "update"
====
[PID-33581] [11-Oct-2022 20:54:01] INFO --> jobs to run: update.php
[PID-33581] [11-Oct-2022 20:54:01] INFO --> >>> trying to run "update"
[PID-33581] [11-Oct-2022 20:54:01] INFO --> lock "update" acquired
[PID-33581] [11-Oct-2022 20:54:01] INFO --> processing the job ...
[PID-33581] [11-Oct-2022 20:54:01] INFO --> <<< job done, releasing lock "update"
====
[PID-33663] [11-Oct-2022 20:55:02] INFO --> jobs to run: update.php
[PID-33663] [11-Oct-2022 20:55:02] INFO --> >>> trying to run "update"
[PID-33663] [11-Oct-2022 20:55:02] INFO --> lock "update" acquired
[PID-33663] [11-Oct-2022 20:55:02] INFO --> processing the job ...
[PID-33663] [11-Oct-2022 20:55:02] INFO --> <<< job done, releasing lock "update"
====
[PID-33746] [11-Oct-2022 20:56:01] INFO --> jobs to run: update.php
[PID-33746] [11-Oct-2022 20:56:01] INFO --> >>> trying to run "update"
[PID-33746] [11-Oct-2022 20:56:01] INFO --> lock "update" acquired
[PID-33746] [11-Oct-2022 20:56:01] INFO --> processing the job ...
[PID-33746] [11-Oct-2022 20:56:01] INFO --> <<< job done, releasing lock "update"
====
[PID-33838] [11-Oct-2022 20:57:01] INFO --> jobs to run: update.php
[PID-33838] [11-Oct-2022 20:57:01] INFO --> >>> trying to run "update"
[PID-33838] [11-Oct-2022 20:57:01] INFO --> lock "update" acquired
[PID-33838] [11-Oct-2022 20:57:01] INFO --> processing the job ...
[PID-33838] [11-Oct-2022 20:57:01] INFO --> <<< job done, releasing lock "update"
====
[PID-33931] [11-Oct-2022 20:58:01] INFO --> jobs to run: update.php
[PID-33931] [11-Oct-2022 20:58:01] INFO --> >>> trying to run "update"
[PID-33931] [11-Oct-2022 20:58:01] INFO --> lock "update" acquired
[PID-33931] [11-Oct-2022 20:58:01] INFO --> processing the job ...
[PID-33931] [11-Oct-2022 20:58:01] INFO --> <<< job done, releasing lock "update"
====
[PID-34011] [11-Oct-2022 20:59:01] INFO --> jobs to run: update.php
[PID-34011] [11-Oct-2022 20:59:01] INFO --> >>> trying to run "update"
[PID-34011] [11-Oct-2022 20:59:01] INFO --> lock "update" acquired
[PID-34011] [11-Oct-2022 20:59:01] INFO --> processing the job ...
[PID-34011] [11-Oct-2022 20:59:01] INFO --> <<< job done, releasing lock "update"
====
[PID-34105] [11-Oct-2022 21:00:01] INFO --> jobs to run: update.php
[PID-34105] [11-Oct-2022 21:00:01] INFO --> >>> trying to run "update"
[PID-34105] [11-Oct-2022 21:00:01] INFO --> lock "update" acquired
[PID-34105] [11-Oct-2022 21:00:01] INFO --> processing the job ...
[PID-34105] [11-Oct-2022 21:00:01] INFO --> <<< job done, releasing lock "update"
====
[PID-34199] [11-Oct-2022 21:01:01] INFO --> jobs to run: update.php
[PID-34199] [11-Oct-2022 21:01:01] INFO --> >>> trying to run "update"
[PID-34199] [11-Oct-2022 21:01:01] INFO --> lock "update" acquired
[PID-34199] [11-Oct-2022 21:01:01] INFO --> processing the job ...
[PID-34199] [11-Oct-2022 21:01:01] INFO --> <<< job done, releasing lock "update"
====
[PID-34275] [11-Oct-2022 21:02:01] INFO --> jobs to run: update.php
[PID-34275] [11-Oct-2022 21:02:01] INFO --> >>> trying to run "update"
[PID-34275] [11-Oct-2022 21:02:01] INFO --> lock "update" acquired
[PID-34275] [11-Oct-2022 21:02:01] INFO --> processing the job ...
[PID-34275] [11-Oct-2022 21:02:01] INFO --> <<< job done, releasing lock "update"
====
[PID-34417] [11-Oct-2022 21:03:01] INFO --> jobs to run: update.php
[PID-34417] [11-Oct-2022 21:03:01] INFO --> >>> trying to run "update"
[PID-34417] [11-Oct-2022 21:03:01] INFO --> lock "update" acquired
[PID-34417] [11-Oct-2022 21:03:01] INFO --> processing the job ...
[PID-34417] [11-Oct-2022 21:03:01] INFO --> <<< job done, releasing lock "update"
====
[PID-34500] [11-Oct-2022 21:04:02] INFO --> jobs to run: update.php
[PID-34500] [11-Oct-2022 21:04:02] INFO --> >>> trying to run "update"
[PID-34500] [11-Oct-2022 21:04:02] INFO --> lock "update" acquired
[PID-34500] [11-Oct-2022 21:04:02] INFO --> processing the job ...
[PID-34500] [11-Oct-2022 21:04:02] INFO --> <<< job done, releasing lock "update"
-> <<< job done, releasing lock "update"
====
[PID-37992] [11-Oct-2022 21:50:01] INFO --> jobs to run: update.php
[PID-37992] [11-Oct-2022 21:50:01] INFO --> >>> trying to run "update"
[PID-37992] [11-Oct-2022 21:50:01] INFO --> lock "update" acquired
[PID-37992] [11-Oct-2022 21:50:01] INFO --> processing the job ...
[PID-37992] [11-Oct-2022 21:50:01] INFO --> <<< job done, releasing lock "update"
====
[PID-38040] [11-Oct-2022 21:51:01] INFO --> jobs to run: update.php
[PID-38040] [11-Oct-2022 21:51:01] INFO --> >>> trying to run "update"
[PID-38040] [11-Oct-2022 21:51:01] INFO --> lock "update" acquired
[PID-38040] [11-Oct-2022 21:51:01] INFO --> processing the job ...
[PID-38040] [11-Oct-2022 21:51:01] INFO --> <<< job done, releasing lock "update"
====
[PID-38096] [11-Oct-2022 21:52:01] INFO --> jobs to run: update.php, diskspace.php
[PID-38096] [11-Oct-2022 21:52:01] INFO --> >>> trying to run "update"
[PID-38096] [11-Oct-2022 21:52:01] INFO --> lock "update" acquired
[PID-38096] [11-Oct-2022 21:52:01] INFO --> processing the job ...
[PID-38096] [11-Oct-2022 21:52:01] INFO --> <<< job done, releasing lock "update"
[PID-38096] [11-Oct-2022 21:52:01] INFO --> >>> trying to run "diskspace"
[PID-38096] [11-Oct-2022 21:52:01] INFO --> lock "diskspace" acquired
[PID-38096] [11-Oct-2022 21:52:01] INFO --> processing the job ...
[PID-38096] [11-Oct-2022 21:52:01] INFO --> <<< job done, releasing lock "diskspace"
====
[PID-38166] [11-Oct-2022 21:53:02] INFO --> jobs to run: update.php
[PID-38166] [11-Oct-2022 21:53:02] INFO --> >>> trying to run "update"
[PID-38166] [11-Oct-2022 21:53:02] INFO --> lock "update" acquired
[PID-38166] [11-Oct-2022 21:53:02] INFO --> processing the job ...
[PID-38166] [11-Oct-2022 21:53:02] INFO --> <<< job done, releasing lock "update"
====
[PID-38232] [11-Oct-2022 21:54:01] INFO --> jobs to run: update.php
[PID-38232] [11-Oct-2022 21:54:01] INFO --> >>> trying to run "update"
[PID-38232] [11-Oct-2022 21:54:01] INFO --> lock "update" acquired
[PID-38232] [11-Oct-2022 21:54:01] INFO --> processing the job ...
[PID-38232] [11-Oct-2022 21:54:01] INFO --> <<< job done, releasing lock "update"
====
[PID-38287] [11-Oct-2022 21:55:01] INFO --> jobs to run: update.php
[PID-38287] [11-Oct-2022 21:55:01] INFO --> >>> trying to run "update"
[PID-38287] [11-Oct-2022 21:55:01] INFO --> lock "update" acquired
[PID-38287] [11-Oct-2022 21:55:01] INFO --> processing the job ...
[PID-38287] [11-Oct-2022 21:55:01] INFO --> <<< job done, releasing lock "update"
====
[PID-38343] [11-Oct-2022 21:56:01] INFO --> jobs to run: update.php
[PID-38343] [11-Oct-2022 21:56:01] INFO --> >>> trying to run "update"
[PID-38343] [11-Oct-2022 21:56:01] INFO --> lock "update" acquired
[PID-38343] [11-Oct-2022 21:56:01] INFO --> processing the job ...
[PID-38343] [11-Oct-2022 21:56:01] INFO --> <<< job done, releasing lock "update"
====
[PID-38392] [11-Oct-2022 21:57:01] INFO --> jobs to run: update.php
[PID-38392] [11-Oct-2022 21:57:01] INFO --> >>> trying to run "update"
[PID-38392] [11-Oct-2022 21:57:01] INFO --> lock "update" acquired
[PID-38392] [11-Oct-2022 21:57:01] INFO --> processing the job ...
[PID-38392] [11-Oct-2022 21:57:01] INFO --> <<< job done, releasing lock "update"
====
[PID-38451] [11-Oct-2022 21:58:01] INFO --> jobs to run: update.php
[PID-38451] [11-Oct-2022 21:58:01] INFO --> >>> trying to run "update"
[PID-38451] [11-Oct-2022 21:58:01] INFO --> lock "update" acquired
[PID-38451] [11-Oct-2022 21:58:01] INFO --> processing the job ...
[PID-38451] [11-Oct-2022 21:58:01] INFO --> <<< job done, releasing lock "update"
====
[PID-38506] [11-Oct-2022 21:59:01] INFO --> jobs to run: update.php
[PID-38506] [11-Oct-2022 21:59:01] INFO --> >>> trying to run "update"
[PID-38506] [11-Oct-2022 21:59:01] INFO --> lock "update" acquired
[PID-38506] [11-Oct-2022 21:59:01] INFO --> processing the job ...
[PID-38506] [11-Oct-2022 21:59:01] INFO --> <<< job done, releasing lock "update"
====
[PID-38552] [11-Oct-2022 22:00:01] INFO --> jobs to run: update.php
[PID-38552] [11--2022 21:52:01] INFO --> = email total: 180.00 KiB
[11-Oct-2022 21:52:01] INFO --> databases
[11-Oct-2022 21:52:01] INFO --> database "tracer_db1": 112.00 KiB
[11-Oct-2022 21:52:01] INFO --> database "tracer_db2": 544.00 KiB
[11-Oct-2022 21:52:01] INFO --> database "tracer_db3": 0 B
[11-Oct-2022 21:52:01] INFO --> = database total: 656.00 KiB
[11-Oct-2022 21:52:01] INFO --> = user "tracer" total: 28.73 MiB / unlimited - 0.00 %
====
[11-Oct-2022 22:52:01] INFO --> loading user...
[11-Oct-2022 22:52:01] INFO --> select user "tracer"
[11-Oct-2022 22:52:01] INFO --> webspace
[11-Oct-2022 22:52:01] INFO --> = webspace total: 27.91 MiB
[11-Oct-2022 22:52:01] INFO --> email
[11-Oct-2022 22:52:01] INFO --> mailbox "tracer@lab.24unix.net": 180.00 KiB / 1.00 GiB - 0.02 %
[11-Oct-2022 22:52:01] INFO --> = email total: 180.00 KiB
[11-Oct-2022 22:52:01] INFO --> databases
[11-Oct-2022 22:52:01] INFO --> database "tracer_db1": 112.00 KiB
[11-Oct-2022 22:52:01] INFO --> database "tracer_db2": 544.00 KiB
[11-Oct-2022 22:52:01] INFO --> database "tracer_db3": 0 B
[11-Oct-2022 22:52:01] INFO --> = database total: 656.00 KiB
[11-Oct-2022 22:52:01] INFO --> = user "tracer" total: 28.73 MiB / unlimited - 0.00 %
====
[11-Oct-2022 23:52:02] INFO --> loading user...
[11-Oct-2022 23:52:02] INFO --> select user "tracer"
[11-Oct-2022 23:52:02] INFO --> webspace
[11-Oct-2022 23:52:02] INFO --> = webspace total: 27.91 MiB
[11-Oct-2022 23:52:02] INFO --> email
[11-Oct-2022 23:52:02] INFO --> mailbox "tracer@lab.24unix.net": 180.00 KiB / 1.00 GiB - 0.02 %
[11-Oct-2022 23:52:02] INFO --> = email total: 180.00 KiB
[11-Oct-2022 23:52:02] INFO --> databases
[11-Oct-2022 23:52:02] INFO --> database "tracer_db1": 112.00 KiB
[11-Oct-2022 23:52:02] INFO --> database "tracer_db2": 544.00 KiB
[11-Oct-2022 23:52:02] INFO --> database "tracer_db3": 0 B
[11-Oct-2022 23:52:02] INFO --> = database total: 656.00 KiB
[11-Oct-2022 23:52:02] INFO --> = user "tracer" total: 28.73 MiB / unlimited - 0.00 %
====
[12-Oct-2022 00:52:01] INFO --> loading user...
[12-Oct-2022 00:52:01] INFO --> select user "tracer"
[12-Oct-2022 00:52:01] INFO --> webspace
[12-Oct-2022 00:52:01] INFO --> = webspace total: 27.91 MiB
[12-Oct-2022 00:52:01] INFO --> email
[12-Oct-2022 00:52:01] INFO --> mailbox "tracer@lab.24unix.net": 180.00 KiB / 1.00 GiB - 0.02 %
[12-Oct-2022 00:52:01] INFO --> = email total: 180.00 KiB
[12-Oct-2022 00:52:01] INFO --> databases
[12-Oct-2022 00:52:01] INFO --> database "tracer_db1": 112.00 KiB
[12-Oct-2022 00:52:01] INFO --> database "tracer_db2": 544.00 KiB
[12-Oct-2022 00:52:01] INFO --> database "tracer_db3": 0 B
[12-Oct-2022 00:52:01] INFO --> = database total: 656.00 KiB
[12-Oct-2022 00:52:01] INFO --> = user "tracer" total: 28.73 MiB / unlimited - 0.00 %
====
[12-Oct-2022 01:52:01] INFO --> loading user...
[12-Oct-2022 01:52:01] INFO --> select user "tracer"
[12-Oct-2022 01:52:01] INFO --> webspace
[12-Oct-2022 01:52:01] INFO --> = webspace total: 27.91 MiB
[12-Oct-2022 01:52:01] INFO --> email
[12-Oct-2022 01:52:01] INFO --> mailbox "tracer@lab.24unix.net": 180.00 KiB / 1.00 GiB - 0.02 %
[12-Oct-2022 01:52:01] INFO --> = email total: 180.00 KiB
[12-Oct-2022 01:52:01] INFO --> databases
[12-Oct-2022 01:52:01] INFO --> database "tracer_db1": 112.00 KiB
[12-Oct-2022 01:52:01] INFO --> database "tracer_db2": 544.00 KiB
[12-Oct-2022 01:52:01] INFO --> database "tracer_db3": 0 B
[12-Oct-2022 01:52:01] INFO --> = database total: 656.00 KiB
[12-Oct-2022 01:52:01] INFO --> = user "tracer" total: 28.73 MiB / unlimited - 0.00 %
====
[12-Oct-2022 02:52:01] INFO --> loading user...
[12-Oct-2022 02:52:01] INFO --> select user "tracer"
[12-Oct-2022 02:52:01] INFO --> webspace
[12-Oct-2022 02:52:01] INFO --> = webspace total: 27.91 MiB
[12-Oct-2022 02:52:01] INFO --> email
[12-Oct-2022 02:52:01] INFO --> mailbox "tracer@lab.24unix.===
[11-Oct-2022 21:55:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:56:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:57:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:58:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 21:59:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:00:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:01:02] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:02:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:03:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:04:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:05:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:06:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:07:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:08:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:09:02] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:10:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:11:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:12:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:13:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:14:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:15:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:16:02] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:17:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:18:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:19:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:20:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:21:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:22:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:23:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:24:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:25:02] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:26:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:27:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:28:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:29:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:30:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:31:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:32:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:33:02] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:34:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:35:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:36:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:37:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:38:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:39:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:40:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:41:02] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:42:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:43:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:44:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:45:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:46:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:47:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:48:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:49:02] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:50:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:51:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:52:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:53:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:54:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:55:01] INFO --> load tasks... nothing to do
====
[11-Oct-2022 22:56:01] INFO --> load tasks... nothing to do
====
Oct-2022 22:00:01] INFO --> >>> trying to run "update"
[PID-38552] [11-Oct-2022 22:00:01] INFO --> lock "update" acquired
[PID-38552] [11-Oct-2022 22:00:01] INFO --> processing the job ...
[PID-38552] [11-Oct-2022 22:00:01] INFO --> <<< job done, releasing lock "update"
====
[PID-38613] [11-Oct-2022 22:01:02] INFO --> jobs to run: update.php
[PID-38613] [11-Oct-2022 22:01:02] INFO --> >>> trying to run "update"
[PID-38613] [11-Oct-2022 22:01:02] INFO --> lock "update" acquired
[PID-38613] [11-Oct-2022 22:01:02] INFO --> processing the job ...
[PID-38613] [11-Oct-2022 22:01:02] INFO --> <<< job done, releasing lock "update"
====
[PID-38660] [11-Oct-2022 22:02:01] INFO --> jobs to run: update.php
[PID-38660] [11-Oct-2022 22:02:01] INFO --> >>> trying to run "update"
[PID-38660] [11-Oct-2022 22:02:01] INFO --> lock "update" acquired
[PID-38660] [11-Oct-2022 22:02:01] INFO --> processing the job ...
[PID-38660] [11-Oct-2022 22:02:01] INFO --> <<< job done, releasing lock "update"
====
[PID-38718] [11-Oct-2022 22:03:01] INFO --> jobs to run: update.php
[PID-38718] [11-Oct-2022 22:03:01] INFO --> >>> trying to run "update"
[PID-38718] [11-Oct-2022 22:03:01] INFO --> lock "update" acquired
[PID-38718] [11-Oct-2022 22:03:01] INFO --> processing the job ...
[PID-38718] [11-Oct-2022 22:03:01] INFO --> <<< job done, releasing lock "update"
====
[PID-38764] [11-Oct-2022 22:04:01] INFO --> jobs to run: update.php
[PID-38764] [11-Oct-2022 22:04:01] INFO --> >>> trying to run "update"
[PID-38764] [11-Oct-2022 22:04:01] INFO --> lock "update" acquired
[PID-38764] [11-Oct-2022 22:04:01] INFO --> processing the job ...
[PID-38764] [11-Oct-2022 22:04:01] INFO --> <<< job done, releasing lock "update"
====
[PID-38825] [11-Oct-2022 22:05:01] INFO --> jobs to run: update.php
[PID-38825] [11-Oct-2022 22:05:01] INFO --> >>> trying to run "update"
[PID-38825] [11-Oct-2022 22:05:01] INFO --> lock "update" acquired
[PID-38825] [11-Oct-2022 22:05:01] INFO --> processing the job ...
[PID-38825] [11-Oct-2022 22:05:01] INFO --> <<< job done, releasing lock "update"
====
[PID-38883] [11-Oct-2022 22:06:01] INFO --> jobs to run: update.php
[PID-38883] [11-Oct-2022 22:06:01] INFO --> >>> trying to run "update"
[PID-38883] [11-Oct-2022 22:06:01] INFO --> lock "update" acquired
[PID-38883] [11-Oct-2022 22:06:01] INFO --> processing the job ...
[PID-38883] [11-Oct-2022 22:06:01] INFO --> <<< job done, releasing lock "update"
====
[PID-38941] [11-Oct-2022 22:07:01] INFO --> jobs to run: update.php
[PID-38941] [11-Oct-2022 22:07:01] INFO --> >>> trying to run "update"
[PID-38941] [11-Oct-2022 22:07:01] INFO --> lock "update" acquired
[PID-38941] [11-Oct-2022 22:07:01] INFO --> processing the job ...
[PID-38941] [11-Oct-2022 22:07:01] INFO --> <<< job done, releasing lock "update"
====
[PID-38987] [11-Oct-2022 22:08:01] INFO --> jobs to run: update.php
[PID-38987] [11-Oct-2022 22:08:01] INFO --> >>> trying to run "update"
[PID-38987] [11-Oct-2022 22:08:01] INFO --> lock "update" acquired
[PID-38987] [11-Oct-2022 22:08:01] INFO --> processing the job ...
[PID-38987] [11-Oct-2022 22:08:01] INFO --> <<< job done, releasing lock "update"
====
[PID-39048] [11-Oct-2022 22:09:02] INFO --> jobs to run: update.php
[PID-39048] [11-Oct-2022 22:09:02] INFO --> >>> trying to run "update"
[PID-39048] [11-Oct-2022 22:09:02] INFO --> lock "update" acquired
[PID-39048] [11-Oct-2022 22:09:02] INFO --> processing the job ...
[PID-39048] [11-Oct-2022 22:09:02] INFO --> <<< job done, releasing lock "update"
====
[PID-39168] [11-Oct-2022 22:10:01] INFO --> jobs to run: update.php
[PID-39168] [11-Oct-2022 22:10:01] INFO --> >>> trying to run "update"
[PID-39168] [11-Oct-2022 22:10:01] INFO --> lock "update" acquired
[PID-39168] [11-Oct-2022 22:10:01] INFO --> processing the job ...
[PID-39168] [11-Oct-2022 22:10:01] INFO --> <<< job done, releasing lock "update"
====
[PID-39214] [11-Oct-2022 22:11:01] INFO --> jobs to run: update.php
[PID-39214] [11-Oct-2022 22:11:01] INFO --> >>> trying to run "update"
[PID-39214] [11-Oct-2022 --> <<< job done, releasing lock "update"
====
[PID-16869] [11-Oct-2022 18:09:01] INFO --> jobs to run: update.php
[PID-16869] [11-Oct-2022 18:09:01] INFO --> >>> trying to run "update"
[PID-16869] [11-Oct-2022 18:09:01] INFO --> lock "update" acquired
[PID-16869] [11-Oct-2022 18:09:01] INFO --> processing the job ...
[PID-16869] [11-Oct-2022 18:09:01] INFO --> <<< job done, releasing lock "update"
====
[PID-17042] [11-Oct-2022 18:10:01] INFO --> jobs to run: update.php
[PID-17042] [11-Oct-2022 18:10:01] INFO --> >>> trying to run "update"
[PID-17042] [11-Oct-2022 18:10:01] INFO --> lock "update" acquired
[PID-17042] [11-Oct-2022 18:10:01] INFO --> processing the job ...
[PID-17042] [11-Oct-2022 18:10:01] INFO --> <<< job done, releasing lock "update"
====
[PID-17193] [11-Oct-2022 18:11:01] INFO --> jobs to run: update.php
[PID-17193] [11-Oct-2022 18:11:01] INFO --> >>> trying to run "update"
[PID-17193] [11-Oct-2022 18:11:01] INFO --> lock "update" acquired
[PID-17193] [11-Oct-2022 18:11:01] INFO --> processing the job ...
[PID-17193] [11-Oct-2022 18:11:01] INFO --> <<< job done, releasing lock "update"
====
[PID-17331] [11-Oct-2022 18:12:02] INFO --> jobs to run: update.php
[PID-17331] [11-Oct-2022 18:12:02] INFO --> >>> trying to run "update"
[PID-17331] [11-Oct-2022 18:12:02] INFO --> lock "update" acquired
[PID-17331] [11-Oct-2022 18:12:02] INFO --> processing the job ...
[PID-17331] [11-Oct-2022 18:12:02] INFO --> <<< job done, releasing lock "update"
====
[PID-17410] [11-Oct-2022 18:13:01] INFO --> jobs to run: update.php
[PID-17410] [11-Oct-2022 18:13:01] INFO --> >>> trying to run "update"
[PID-17410] [11-Oct-2022 18:13:01] INFO --> lock "update" acquired
[PID-17410] [11-Oct-2022 18:13:01] INFO --> processing the job ...
[PID-17410] [11-Oct-2022 18:13:01] INFO --> <<< job done, releasing lock "update"
====
[PID-17540] [11-Oct-2022 18:14:01] INFO --> jobs to run: update.php
[PID-17540] [11-Oct-2022 18:14:01] INFO --> >>> trying to run "update"
[PID-17540] [11-Oct-2022 18:14:01] INFO --> lock "update" acquired
[PID-17540] [11-Oct-2022 18:14:01] INFO --> processing the job ...
[PID-17540] [11-Oct-2022 18:14:01] INFO --> <<< job done, releasing lock "update"
====
[PID-17677] [11-Oct-2022 18:15:01] INFO --> jobs to run: update.php
[PID-17677] [11-Oct-2022 18:15:01] INFO --> >>> trying to run "update"
[PID-17677] [11-Oct-2022 18:15:01] INFO --> lock "update" acquired
[PID-17677] [11-Oct-2022 18:15:01] INFO --> processing the job ...
[PID-17677] [11-Oct-2022 18:15:01] INFO --> <<< job done, releasing lock "update"
====
[PID-17778] [11-Oct-2022 18:16:01] INFO --> jobs to run: update.php
[PID-17778] [11-Oct-2022 18:16:01] INFO --> >>> trying to run "update"
[PID-17778] [11-Oct-2022 18:16:01] INFO --> lock "update" acquired
[PID-17778] [11-Oct-2022 18:16:01] INFO --> processing the job ...
[PID-17778] [11-Oct-2022 18:16:01] INFO --> <<< job done, releasing lock "update"
====
[PID-17917] [11-Oct-2022 18:17:01] INFO --> jobs to run: update.php
[PID-17917] [11-Oct-2022 18:17:01] INFO --> >>> trying to run "update"
[PID-17917] [11-Oct-2022 18:17:01] INFO --> lock "update" acquired
[PID-17917] [11-Oct-2022 18:17:01] INFO --> processing the job ...
[PID-17917] [11-Oct-2022 18:17:01] INFO --> <<< job done, releasing lock "update"
====
[PID-18023] [11-Oct-2022 18:18:01] INFO --> jobs to run: update.php
[PID-18023] [11-Oct-2022 18:18:01] INFO --> >>> trying to run "update"
[PID-18023] [11-Oct-2022 18:18:01] INFO --> lock "update" acquired
[PID-18023] [11-Oct-2022 18:18:01] INFO --> processing the job ...
[PID-18023] [11-Oct-2022 18:18:01] INFO --> <<< job done, releasing lock "update"
====
[PID-18105] [11-Oct-2022 18:19:01] INFO --> jobs to run: update.php
[PID-18105] [11-Oct-2022 18:19:01] INFO --> >>> trying to run "update"
[PID-18105] [11-Oct-2022 18:19:01] INFO --> lock "update" acquired
[PID-18105] [11-Oct-2022 18:19:01] INFO --> processing the job ...
[PID-18105] [11-Oct-2022 18:19:01] INFO --> <<< job done, releasing lock "update"
====
[PID-18190] [11-Oct-2022 18:20:01] INFO --> jobs to run: update.php
[PID-18190] [11-Oct-2022 18:20:01] INFO --> >>> trying to run "update"
[PID-18190] [11-Oct-2022 18:20:01] INFO --> lock "update" acquired
[PID-18190] [11-Oct-2022 18:20:01] INFO --> processing the job ...
[PID-18190] [11-Oct-2022 18:20:01] INFO --> <<< job done, releasing lock "update"
====
[PID-18285] [11-Oct-2022 18:21:01] INFO --> jobs to run: update.php
[PID-18285] [11-Oct-2022 18:21:01] INFO --> >>> trying to run "update"
[PID-18285] [11-Oct-2022 18:21:01] INFO --> lock "update" acquired
[PID-18285] [11-Oct-2022 18:21:01] INFO --> processing the job ...
[PID-18285] [11-Oct-2022 18:21:01] INFO --> <<< job done, releasing lock "update"
====
[PID-18375] [11-Oct-2022 18:22:02] INFO --> jobs to run: update.php
[PID-18375] [11-Oct-2022 18:22:02] INFO --> >>> trying to run "update"
[PID-18375] [11-Oct-2022 18:22:02] INFO --> lock "update" acquired
[PID-18375] [11-Oct-2022 18:22:02] INFO --> processing the job ...
[PID-18375] [11-Oct-2022 18:22:02] INFO --> <<< job done, releasing lock "update"
====
[PID-18505] [11-Oct-2022 18:23:01] INFO --> jobs to run: update.php
[PID-18505] [11-Oct-2022 18:23:01] INFO --> >>> trying to run "update"
[PID-18505] [11-Oct-2022 18:23:01] INFO --> lock "update" acquired
[PID-18505] [11-Oct-2022 18:23:01] INFO --> processing the job ...
[PID-18505] [11-Oct-2022 18:23:01] INFO --> <<< job done, releasing lock "update"
====
[PID-18640] [11-Oct-2022 18:24:01] INFO --> jobs to run: update.php
[PID-18640] [11-Oct-2022 18:24:01] INFO --> >>> trying to run "update"
[PID-18640] [11-Oct-2022 18:24:01] INFO --> lock "update" acquired
[PID-18640] [11-Oct-2022 18:24:01] INFO --> processing the job ...
[PID-18640] [11-Oct-2022 18:24:01] INFO --> <<< job done, releasing lock "update"
====
[PID-18743] [11-Oct-2022 18:25:01] INFO --> jobs to run: update.php
[PID-18743] [11-Oct-2022 18:25:01] INFO --> >>> trying to run "update"
[PID-18743] [11-Oct-2022 18:25:01] INFO --> lock "update" acquired
[PID-18743] [11-Oct-2022 18:25:01] INFO --> processing the job ...
[PID-18743] [11-Oct-2022 18:25:01] INFO --> <<< job done, releasing lock "update"
====
[PID-18850] [11-Oct-2022 18:26:01] INFO --> jobs to run: update.php
[PID-18850] [11-Oct-2022 18:26:01] INFO --> >>> trying to run "update"
[PID-18850] [11-Oct-2022 18:26:01] INFO --> lock "update" acquired
[PID-18850] [11-Oct-2022 18:26:01] INFO --> processing the job ...
[PID-18850] [11-Oct-2022 18:26:01] INFO --> <<< job done, releasing lock "update"
====
[PID-18970] [11-Oct-2022 18:27:01] INFO --> jobs to run: update.php
[PID-18970] [11-Oct-2022 18:27:01] INFO --> >>> trying to run "update"
[PID-18970] [11-Oct-2022 18:27:01] INFO --> lock "update" acquired
[PID-18970] [11-Oct-2022 18:27:01] INFO --> processing the job ...
[PID-18970] [11-Oct-2022 18:27:01] INFO --> <<< job done, releasing lock "update"
====
[PID-19096] [11-Oct-2022 18:28:01] INFO --> jobs to run: update.php
[PID-19096] [11-Oct-2022 18:28:01] INFO --> >>> trying to run "update"
[PID-19096] [11-Oct-2022 18:28:01] INFO --> lock "update" acquired
[PID-19096] [11-Oct-2022 18:28:01] INFO --> processing the job ...
[PID-19096] [11-Oct-2022 18:28:01] INFO --> <<< job done, releasing lock "update"
====
[PID-19230] [11-Oct-2022 18:29:01] INFO --> jobs to run: update.php
[PID-19230] [11-Oct-2022 18:29:01] INFO --> >>> trying to run "update"
[PID-19230] [11-Oct-2022 18:29:01] INFO --> lock "update" acquired
[PID-19230] [11-Oct-2022 18:29:01] INFO --> processing the job ...
[PID-19230] [11-Oct-2022 18:29:01] INFO --> <<< job done, releasing lock "update"
====
[PID-19332] [11-Oct-2022 18:30:02] INFO --> jobs to run: update.php
[PID-19332] [11-Oct-2022 18:30:02] INFO --> >>> trying to run "update"
[PID-19332] [11-Oct-2022 18:30:02] INFO --> lock "update" acquired
[PID-19332] [11-Oct-2022 18:30:02] INFO --> processing the job ...
[PID-19332] [11-Oct-2022 18:30:02] INFO --> <<< job done, releasing lock "update"
====
[PID-19476] [11-Oct-2022 18:31:01] INFO --> jobs to run: update.php
[PID-19476] [11-Oct-2022 18:31:01] INFO --> >>> trying to run "update"
[PID-19476] [11-Oct-2022 18:31:01] INFO --> lock "update" acquired
[PID-19476] [11-Oct-2022 18:31:01] INFO --> processing the job ...
[PID-19476] [11-Oct-2022 18:31:01] INFO --> <<< job done, releasing lock "update"
====
[PID-19578] [11-Oct-2022 18:32:01] INFO --> jobs to run: update.php
[PID-19578] [11-Oct-2022 18:32:01] INFO --> >>> trying to run "update"
[PID-19578] [11-Oct-2022 18:32:01] INFO --> lock "update" acquired
[PID-19578] [11-Oct-2022 18:32:01] INFO --> processing the job ...
[PID-19578] [11-Oct-2022 18:32:01] INFO --> <<< job done, releasing lock "update"
====
[PID-19696] [11-Oct-2022 18:33:01] INFO --> jobs to run: update.php
[PID-19696] [11-Oct-2022 18:33:01] INFO --> >>> trying to run "update"
[PID-19696] [11-Oct-2022 18:33:01] INFO --> lock "update" acquired
[PID-19696] [11-Oct-2022 18:33:01] INFO --> processing the job ...
[PID-19696] [11-Oct-2022 18:33:01] INFO --> <<< job done, releasing lock "update"
====
[PID-19786] [11-Oct-2022 18:34:01] INFO --> jobs to run: update.php
[PID-19786] [11-Oct-2022 18:34:01] INFO --> >>> trying to run "update"
[PID-19786] [11-Oct-2022 18:34:01] INFO --> lock "update" acquired
[PID-19786] [11-Oct-2022 18:34:01] INFO --> processing the job ...
[PID-19786] [11-Oct-2022 18:34:01] INFO --> <<< job done, releasing lock "update"
====
[PID-19887] [11-Oct-2022 18:35:01] INFO --> jobs to run: update.php
[PID-19887] [11-Oct-2022 18:35:01] INFO --> >>> trying to run "update"
[PID-19887] [11-Oct-2022 18:35:01] INFO --> lock "update" acquired
[PID-19887] [11-Oct-2022 18:35:01] INFO --> processing the job ...
[PID-19887] [11-Oct-2022 18:35:01] INFO --> <<< job done, releasing lock "update"
====
[PID-19981] [11-Oct-2022 18:36:01] INFO --> jobs to run: update.php
[PID-19981] [11-Oct-2022 18:36:01] INFO --> >>> trying to run "update"
[PID-19981] [11-Oct-2022 18:36:01] INFO --> lock "update" acquired
[PID-19981] [11-Oct-2022 18:36:01] INFO --> processing the job ...
[PID-19981] [11-Oct-2022 18:36:01] INFO --> <<< job done, releasing lock "update"
====
[PID-20076] [11-Oct-2022 18:37:02] IN

View File

@ -70,7 +70,7 @@
}
},
"/dyndns/{hostname}": {
"get": {
"post": {
"tags": [
"DNS"
],
@ -94,6 +94,9 @@
"200": {
"description": "OK"
},
"204": {
"description": "No Content"
},
"401": {
"description": "API key is missing or invalid."
},
@ -123,7 +126,15 @@
"401": {
"$ref": "#/components/responses/401-unauthorized"
}
}
},
"security": [
{
"Authorization": [
"read"
]
}
]
},
"post": {
"tags": [
@ -523,4 +534,4 @@
}
}
}
}
}

View File

@ -0,0 +1,5 @@
<?php
const DEFAULT_NS = 'ns2.24unix.net';
const NAMESERVERS = ['ns1.24unix.net', 'ns2.24unix.net'];

View File

@ -19,7 +19,8 @@
<script>
window.onload = function () {
// Begin Swagger UI call region
const ui = SwaggerUIBundle({
let ui;
ui = SwaggerUIBundle({
url: "/openapi/bindapi.json",
dom_id: "#swagger-ui",
deepLinking: true,

14177
public_suffix_list.dat Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,112 +0,0 @@
<?php declare(strict_types=1);
namespace App\Controller;
use UnhandledMatchError;
error_reporting(error_level: E_ALL);
/**
*
*/
class ApiController
{
/**
* @param String $requestType
* @param String $serverName
* @param int $versionIP
* @param String $apiKey
* @param String $command
* @param String $serverType
* @param array $body
*
* @return array
*/
function sendCommand(string $requestType, string $serverName, int $versionIP, string $apiKey, string $command, string $serverType, array $body = []): array
{
$error = false;
$curl = curl_init();
try {
match ($serverType) {
'panel' => curl_setopt(handle: $curl, option: CURLOPT_URL, value: "https://$serverName/api/v2/" . $command),
'nameserver' => curl_setopt(handle: $curl, option: CURLOPT_URL, value: "https://$serverName/api/" . $command)
};
} catch (UnhandledMatchError) {
echo 'Unhandled match: ' . $serverType;
}
curl_setopt(handle: $curl, option: CURLOPT_RETURNTRANSFER, value: 1);
curl_setopt(handle: $curl, option: CURLOPT_TIMEOUT_MS, value: 19999);
curl_setopt(handle: $curl, option: CURLOPT_HTTP_VERSION, value: CURL_HTTP_VERSION_2TLS);
if ($versionIP == 4) {
curl_setopt(handle: $curl, option: CURLOPT_IPRESOLVE, value: CURL_IPRESOLVE_V4);
} else {
curl_setopt(handle: $curl, option: CURLOPT_IPRESOLVE, value: CURL_IPRESOLVE_V6);
}
curl_setopt(handle: $curl, option: CURLOPT_HTTPHEADER, value: ["X-API-Key:$apiKey"]);
if ($requestType == "POST") {
curl_setopt(handle: $curl, option: CURLOPT_POST, value: true);
curl_setopt(handle: $curl, option: CURLOPT_POSTFIELDS, value: $body);
}
if ($requestType == "PUT") {
curl_setopt(handle: $curl, option: CURLOPT_CUSTOMREQUEST, value: 'PUT');
curl_setopt(handle: $curl, option: CURLOPT_POSTFIELDS, value: json_encode(value: $body));
}
curl_setopt(handle: $curl, option: CURLOPT_CUSTOMREQUEST, value: $requestType);
if ($resultJSON = curl_exec(handle: $curl)) {
$httpResponse = curl_getinfo(handle: $curl)['http_code'];
switch ($httpResponse) {
case 200:
$apiResult = json_decode(json: $resultJSON);
if ($command == "ping") {
if ($apiResult->response == "pong") {
$result = $apiResult->response;
} else {
$result = $apiResult;
}
} else {
$result = $resultJSON;
}
break;
case 400:
$result = $resultJSON;
break;
case 401:
$result = 'Missing or wrong API Key';
break;
case 404:
$result = '404 Not Found';
break;
case 500:
$result = 'server error';
break;
default:
$result = 'Unhandled error: ' . $httpResponse;
}
} else {
$error = true;
$result = curl_error(handle: $curl);
}
$info = curl_getinfo(handle: $curl);
$responseTime = $info['total_time'];
curl_close(handle: $curl);
return [
'responseTime' => $responseTime,
'error' => $error,
'data' => $result,
'header' => $httpResponse ?? ''
];
}
}

View File

@ -1,20 +0,0 @@
<?php declare(strict_types=1);
namespace App\Controller;
error_reporting(error_level: E_ALL);
use Exception;
use PDO;
use PDOException;
/**
*
*/
class ApiKeys
{
public function __construct(private DatabaseConnection $databaseConnection)
{}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,68 @@
<?php
namespace App\Controller\Commands;
use Closure;
/**
*
*/
class Command
{
public function __construct(
private readonly string $name,
private readonly Closure $callback,
private readonly array $mandatoryParameters = [],
private readonly array $optionalParameters = [],
private readonly string $description = ''
)
{
// no body
}
/**
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* @return array
*/
public function getMandatoryParameters(): array
{
return $this->mandatoryParameters;
}
/**
* @return array
*/
public function getOptionalParameters(): array
{
return $this->optionalParameters;
}
/**
* @return string|null
*/
public function getDescription(): ?string
{
return $this->description;
}
/**
* @return Closure
*/
public function getCallback(): Closure
{
return $this->callback;
}
public function exec(): void
{
call_user_func(callback: $this->callback);
}
}

View File

@ -0,0 +1,84 @@
<?php
namespace App\Controller\Commands;
use App\Utilities\Colors;
/**
*
*/
class CommandGroup
{
private array $commands = [];
public function __construct(private readonly string $name, private readonly string $description)
{
// no body
}
public function addCommand(Command $command): ?CommandGroup
{
$this->commands[] = $command;
return $this;
}
public function getName(): string
{
return $this->name;
}
public function printCommands(int $longestCommandLength): void
{
echo Colors::YELLOW . str_pad(string: $this->name, length: $longestCommandLength + 1) . Colors::WHITE . $this->description . Colors::DEFAULT . PHP_EOL;
foreach ($this->commands as $command) {
echo Colors::GREEN . str_pad(string: ' ', length: $longestCommandLength + 1, pad_type: STR_PAD_LEFT) . $this->name . ':' . $command->getName();
foreach ($command->getMandatoryParameters() as $optionals) {
echo ' <' . $optionals . '>';
}
foreach ($command->getOptionalParameters() as $mandatory) {
echo ' {' . $mandatory . '}';
}
echo Colors::WHITE . ' ' . $command->getDescription();
echo Colors::DEFAULT . PHP_EOL;
}
}
public function findCommandByName(string $command): ?Command
{
foreach ($this->commands as $currentCommand) {
if ($command === $currentCommand->getName()) {
return $currentCommand;
}
}
return null;
}
private function findCommandGroupByName(string $command)
{
echo 'in check';
foreach ($this->commands as $currentCommand) {
print_r($currentCommand->getName());
if ($currentCommand instanceof CommandGroup) {
if ($command === $currentCommand->getName()) {
return $currentCommand;
}
}
}
return false;
}
public function exec(string $subcommand): bool
{
if ($command = $this->findCommandByName(command: $subcommand)) {
$command->exec();
return true;
} else {
return false;
}
}
}

View File

@ -0,0 +1,88 @@
<?php
namespace App\Controller\Commands;
use App\Utilities\Colors;
/**
*
*/
class CommandGroupContainer
{
private array $commandGroups = [];
public function addCommandGroup(CommandGroup $commandGroup): CommandGroupContainer
{
$this->commandGroups[] = $commandGroup;
return $this;
}
/**
* @return void
*/
public function printCommands(): void
{
$longestCommandLength = $this->getLongestCommandLength();
foreach ($this->commandGroups as $commandGroup) {
$commandGroup->printCommands($longestCommandLength);
}
}
/**
* @return int
*/
public function getLongestCommandLength(): int
{
$longest = 0;
foreach ($this->commandGroups as $group) {
$len = strlen(string: $group->getName());
if ($len > $longest) {
$longest = $len;
}
}
return $longest;
}
private function findGroupByName(string $command): ?CommandGroup
{
foreach ($this->commandGroups as $group) {
if ($group->getName() === $command) {
return $group;
}
}
return null;
}
public function run(string $command, string $subcommand): void
{
if ($subcommand !== '') {
if ($group = $this->findGroupByName(command: $command)) {
if ($group->exec(subcommand: $subcommand)) {
exit(0);
} else {
echo Colors::DEFAULT . 'Unknown subcommand ' . Colors::YELLOW . $subcommand . Colors::DEFAULT .' for ' . Colors::YELLOW . $command . Colors::DEFAULT . '.' . PHP_EOL;
exit(1);
}
} else {
echo Colors::DEFAULT . 'Unknown command group ' . Colors::YELLOW . $command . Colors::DEFAULT . '.' . PHP_EOL;
exit(1);
}
} else {
// check for command group and print available commands
foreach ($this->commandGroups as $group) {
if ($group->getName() === $command) {
echo 'Available subcommands for: ' . Colors::YELLOW . $group->getName() . Colors::DEFAULT . ':' . PHP_EOL;
$group->printCommands(strlen(string: $group->getName()));
exit(0);
}
}
}
echo Colors::DEFAULT . 'Unknown command ' . Colors::YELLOW . $command . Colors::DEFAULT . '.' . PHP_EOL;
}
}

View File

@ -0,0 +1,65 @@
<?php
namespace App\Controller;
use App\Utilities\Colors;
class ConfigController
{
private array $config;
private static $missingEncryptionShown = false;
public function __construct(private readonly bool $quiet, bool $test = false)
{
if ($test) {
$configFile = dirname(path: __DIR__, levels: 2) . "/config.json.test";
if (!file_exists(filename: $configFile)) {
echo 'No testing (config.json.test) config has benn setup.' . PHP_EOL;
exit(1);
}
} else {
$configFile = dirname(path: __DIR__, levels: 2) . "/config.json.local";
if (!file_exists(filename: $configFile)) {
$configFile = dirname(path: __DIR__, levels: 2) . "/config.json";
}
if (!file_exists(filename: $configFile)) {
echo 'Missing config file' . PHP_EOL;
if (confirm(message: 'Should I create a new config based on config.json.sample?')) {
copy(from: 'config.json.sample', to: 'config.json');
echo 'Config file has been generated. Adjust it to your needs, then proceed to database setup.' . PHP_EOL;
} else {
echo 'You first have to setup the bindAPI. Bye.' . PHP_EOL;
exit(0);
}
exit(1);
}
}
$configJSON = file_get_contents(filename: $configFile);
// first check if json is valid, after make the assignment
if (json_decode(json: $configJSON, associative: true) === null) {
echo 'Config file is not valid JSON.' . PHP_EOL;
echo $configJSON . PHP_EOL;
exit(1);
}
$this->config = json_decode(json: $configJSON, associative: true);
if (!ConfigController::$missingEncryptionShown) {
if ($this->config['encryptionKey'] === '1bad::babe') {
ConfigController::$missingEncryptionShown = true;
if (!$this->quiet) {
echo Colors::RED . 'Error: ' . Colors::DEFAULT . 'No encryption key, please run ' . Colors::YELLOW . './bin/console check:generatekey' . Colors::DEFAULT . PHP_EOL;
}
}
}
}
public function getConfig(string $configKey): string
{
return $this->config[$configKey];
}
}

View File

@ -1,125 +0,0 @@
<?php
namespace App\Controller;
error_reporting(error_level: E_ALL);
use PDO;
use PDOException;
/**
*
*/
class DatabaseConnection
{
private PDO $dbConnection;
const TABLE_PREFIX = '';
const TABLE_DOMAINS = self::TABLE_PREFIX . "domains";
const TABLE_NAMESERVERS = self::TABLE_PREFIX . "nameservers";
const TABLE_PANELS = self::TABLE_PREFIX . "panels";
const TABLE_APIKEYS = self::TABLE_PREFIX . "apikeys";
public function __construct(private array $config)
{
extract(array: $this->config);
try {
$this->dbConnection = new PDO(
dsn: "mysql:host=$dbHost;port=$dbPort;charset=utf8mb4;dbname=$dbDatabase",
username: $dbUser,
password: $dbPassword
);
$sql = "SHOW TABLES";
$statement = $this->dbConnection->prepare(query: $sql);
$statement->execute();
$result = $statement->fetch();
if (empty($result)) {
// ALTER TABLE `domains` ADD `panel_id` INT NULL AFTER `id`;
echo 'Error: Cannot find tables.' . PHP_EOL;
if (confirm(message: 'Should I try to create them?')) {
$sql = "
CREATE TABLE `apikeys` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`api_token_prefix` varchar(13) COLLATE utf8mb4_unicode_ci NOT NULL,
`api_token` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci";
$statement = $this->dbConnection->prepare(query: $sql);
$statement->execute();
$sql = "
CREATE TABLE `domains` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`panel` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci";
$statement = $this->dbConnection->prepare(query: $sql);
$statement->execute();
$sql = "
CREATE TABLE `nameservers` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`a` varbinary(255) DEFAULT NULL,
`aaaa` varbinary(255) DEFAULT NULL,
`apikey` varbinary(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci";
$statement = $this->dbConnection->prepare(query: $sql);
$statement->execute();
$sql = "
CREATE TABLE `panels` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`a` varbinary(255) DEFAULT NULL,
`aaaa` varbinary(255) DEFAULT NULL,
`apikey` varbinary(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci";
$statement = $this->dbConnection->prepare(query: $sql);
$statement->execute();
echo 'Tables have been created.' . PHP_EOL;
}
exit(1);
}
} catch (PDOException $exception) {
echo $exception->getMessage() . PHP_EOL;
echo 'Did you create the database and adjust the config file?' . PHP_EOL;
echo PHP_EOL . 'You can create database an user via a panel or manually in mysql shell:' . PHP_EOL;
$password = $this->generatePassword();
echo 'Created an initial password: ' . $password . PHP_EOL;
echo 'CREATE DATABASE bindAPI;' . PHP_EOL;
echo "CREATE USER 'bindAPI'@'localhost' IDENTIFIED BY '$password';" . PHP_EOL;
echo "GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, INDEX, DROP, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES ON bindAPI.* TO 'bindAPI'@'localhost';" . PHP_EOL;
echo 'There is no need to run FLUSH PRIVILEGES when using GRANT!' . PHP_EOL;
exit(1);
}
}
/**
* @param int $length
*
* @return string
*/
function generatePassword(int $length = 8): string
{
$chars = '23456789bcdfhkmnprstvzBCDFHJKLMNPRSTVZ';
$shuffled = str_shuffle(string: $chars);
return mb_substr(string: $shuffled, start: 0, length: $length);
}
/**
* @return \PDO
*/
public function getConnection(): PDO
{
return $this->dbConnection;
}
}

View File

@ -6,6 +6,8 @@ use App\Entity\Domain;
use App\Repository\DomainRepository;
use App\Repository\NameserverRepository;
use App\Repository\PanelRepository;
use App\Service\ApiClient;
use App\Utilities\Colors;
use Monolog\Logger;
error_reporting(error_level: E_ALL);
@ -17,51 +19,117 @@ error_reporting(error_level: E_ALL);
*/
class DomainController
{
private string $localZoneFile;
private string $localZonesDir;
private string $namedConfLocalFile;
public string $localZoneFile;
public string $localZonesDir;
public string $namedConfLocalFile;
private string $zoneCachePath;
private string $keyhelpNamedCond;
public function __construct(private NameserverRepository $nameserverRepository, private ApiController $checkController, private DomainRepository $domainRepository, private PanelRepository $panelRepository, private array $config, private Logger $log)
public function __construct(
private readonly NameserverRepository $nameserverRepository,
private readonly ApiClient $checkController,
private readonly DomainRepository $domainRepository,
private readonly PanelRepository $panelRepository,
private readonly ConfigController $configController,
private readonly Logger $logger,
private readonly bool $quiet
)
{
if ($this->config['debug']) {
$this->log->debug(message: "__construct()");
}
$this->localZoneFile = '/etc/bind/local.zones';
$this->localZonesDir = '/etc/bind/zones/';
$this->namedConfLocalFile = '/etc/bind/named.conf.local';
$this->zoneCachePath = '/var/cache/bind/';
$this->keyhelpNamedCond = '/etc/bind/named.conf.keyhelp';
}
function createIncludeFile()
function createIncludeFile(): void
{
if ($this->config['debug']) {
$this->log->debug(message: "createIncludeFile()");
}
$this->logger->debug(message: "createIncludeFile()");
$domains = $this->domainRepository->findAll();
$oFile = fopen(filename: $this->localZoneFile, mode: 'w');
foreach ($domains as $domain) {
fputs(stream: $oFile, data: 'include "' . $this->localZonesDir . $domain->getName() . '";' . PHP_EOL);
if (!$this->isMasterZone(domain: $domain)) {
fputs(stream: $oFile, data: 'include "' . $this->localZonesDir . $domain->getName() . '";' . PHP_EOL);
}
}
fclose(stream: $oFile);
exec(command: '/usr/bin/named-checkconf', output: $output, result_code: $resultCode);
if ($resultCode != 0) {
echo 'There was an error:' . PHP_EOL;
foreach ($output as $line) {
echo $line . PHP_EOL;
}
echo 'You need to fix the error before the configuration can be activated.' . PHP_EOL;
exit(1);
}
exec(command: '/usr/sbin/rndc reload');
}
function deleteOnNameservers(Domain $domain)
function updateSlaveZones(): void
{
if ($this->config['debug']) {
$this->log->debug(message: "deleteOnNameserver()");
$this->logger->debug(message: 'update slave zones');
$existingZones = glob(pattern: $this->localZonesDir . '*');
$domains = $this->domainRepository->findAll();
$longestEntry = $this->domainRepository->getLongestEntry(field: 'name');
$self = $this->panelRepository->getSelf();
foreach ($domains as $domain) {
$zoneFile = $this->localZonesDir . $domain->getName();
if (!$this->quiet) {
echo ' ' . Colors::YELLOW . str_pad(string: $domain->getName(), length: $longestEntry + 1, pad_string: " ", pad_type: STR_PAD_RIGHT) ;
}
if (strcmp(string1: $self->getName(), string2: $domain->getPanel()) !== 0) {
if (!file_exists(filename: $zoneFile)) {
if (!$this->quiet) {
echo Colors::GREEN . ' OK' . Colors::DEFAULT . PHP_EOL;
}
$this->createSlaveZoneFile(domain: $domain);
} else {
if (($key = array_search(needle: $zoneFile, haystack: $existingZones)) !== false) {
if (isset($existingZones[$key])) {
unset($existingZones[$key]);
}
} else {
echo 'missing value: ' . $zoneFile;
}
if (!$this->quiet) {
echo Colors::DEFAULT . 'Zone already exists.' . PHP_EOL;
}
}
} else {
if (!$this->quiet) {
echo Colors::DEFAULT . 'We are master for ' . Colors::YELLOW . $domain->getName() . PHP_EOL;
}
}
}
// remove stale zones
foreach ($existingZones as $zone) {
if (!$this->quiet) {
echo 'Removing stale zone: ' . Colors::YELLOW . $zone . Colors::DEFAULT . PHP_EOL;
}
echo $zone . PHP_EOL;
unlink(filename: $zone);
}
$semaphore = $this->localZonesDir . 'zones.flag';
if (file_exists(filename: $semaphore)) {
unlink(filename: $semaphore);
$this->createIncludeFile();
}
}
function deleteOnNameservers(Domain $domain): void
{
$this->logger->debug(message: "deleteOnNameserver()");
$nameservers = $this->nameserverRepository->findAll();
foreach ($nameservers as $nameserver) {
@ -69,24 +137,36 @@ class DomainController
'name' => $domain->getName()
];
if (!empty($nameserver->getAaaa())) {
$this->checkController->sendCommand(requestType: 'DELETE', serverName: $nameserver->getName(), versionIP: 6, apiKey: $nameserver->getApikey(), command: 'delete', serverType: 'nameserver', body: $body);
$this->checkController->sendCommand(
requestType: 'DELETE',
serverName: $nameserver->getName(),
versionIP: 6,
apiKey: $nameserver->getApikey(),
command: 'delete',
serverType: 'nameserver',
body: $body);
} else {
$this->checkController->sendCommand(requestType: 'DELETE', serverName: $nameserver->getName(), versionIP: 4, apiKey: $nameserver->getApikey(), command: 'delete', serverType: 'nameserver', body: $body);
$this->checkController->sendCommand(
requestType: 'DELETE',
serverName: $nameserver->getName(),
versionIP: 4,
apiKey: $nameserver->getApikey(),
command: 'delete',
serverType: 'nameserver',
body: $body);
}
}
}
/**
* @param \App\Entity\Domain $domain
* @param Domain $domain
*
* @return void
*/
function deleteZone(Domain $domain)
function deleteZone(Domain $domain): void
{
if ($this->config['debug']) {
$this->log->debug(message: "deleteZone()");
}
$this->logger->debug(message: "deleteZone()");
$zoneFile = $this->localZonesDir . $domain->getName();
if (file_exists(filename: "$zoneFile")) {
@ -95,59 +175,93 @@ class DomainController
$this->createIncludeFile();
$this->deleteOnNameservers(domain: $domain);
}
/**
* @return void
*/
function checkPermissions(): void
function checkPermissions($impersonatedUserId = null): bool
{
if ($this->config['debug']) {
$this->log->debug(message: "checkPermissions()");
$this->logger->debug(message: "checkPermissions()");
$setupIsValid = true;
if (!$this->quiet) {
echo 'Checking permissions...' . PHP_EOL;
}
if ($impersonatedUserId) {
$uid = $impersonatedUserId;
} else {
$uid = posix_geteuid();
}
if (!$this->quiet) {
echo "UID:\t" . Colors::YELLOW . $uid . PHP_EOL;
}
echo 'Checking permission:' . PHP_EOL . PHP_EOL;
$uid = posix_geteuid();
print("UID:\t" . COLOR_YELLOW . $uid . PHP_EOL);
$pwuid = posix_getpwuid(user_id: $uid);
$name = $pwuid['name'];
echo COLOR_DEFAULT . "Name:\t" . COLOR_YELLOW . $name . PHP_EOL;
$bindGroup = posix_getgrnam(name: 'bind');
$members = $bindGroup['members'];
if (!$this->quiet) {
echo Colors::DEFAULT . "Name:\t" . Colors::YELLOW . $name . PHP_EOL;
}
if (!$bindGroup = posix_getgrnam(name: 'bind')) {
$bindGroup = [];
}
$members = $bindGroup['members'] ?? [];
if (in_array(needle: $name, haystack: $members)) {
echo "\t$name" . COLOR_DEFAULT . ' is in group ' . COLOR_YELLOW . 'bind' . PHP_EOL;
} else {
echo "\t$name needs to be in group $bindGroup!" . PHP_EOL;
}
echo 'Checking file: ' . $this->localZoneFile . PHP_EOL;
$localZoneFilePermissions = fileperms(filename: $this->localZoneFile);
if ($localZoneFilePermissions & 0x0010) {
echo "\t✅ Group has write access." . PHP_EOL;
} else {
echo "\t❌Group needs write permission!" . PHP_EOL;
}
echo "Checking $this->namedConfLocalFile" . PHP_EOL;
if ($namedConfLocal = file_get_contents(filename: $this->namedConfLocalFile)) {
if (!str_contains(haystack: $namedConfLocal, needle: $this->localZoneFile)) {
echo "\t$this->localZoneFile needs to be included in $this->namedConfLocalFile . " . PHP_EOL;
} else {
echo "\t$this->localZoneFile is included in $this->namedConfLocalFile" . PHP_EOL;
if (!$this->quiet) {
echo "\t$name" . Colors::DEFAULT . ' is in group ' . Colors::YELLOW . 'bind' . PHP_EOL;
}
} else {
echo "\t❌ No access to '$this->namedConfLocalFile' . Please check permissions" . PHP_EOL;
$setupIsValid = false;
if (!$this->quiet) {
echo Colors::RED . "\t$name needs to be in group " . Colors::YELLOW . 'bind' . Colors::DEFAULT . '!' . PHP_EOL;
}
}
echo 'Checking directory: ' . $this->localZonesDir . PHP_EOL;
$localZoneDirPermissions = fileperms(filename: $this->localZonesDir);
if ($localZoneDirPermissions & 0x0010) {
echo "\t✅ Group has write access." . PHP_EOL;
if (!$this->quiet) {
echo Colors::DEFAULT . 'Checking ' . Colors::YELLOW . $this->localZoneFile . PHP_EOL;
}
$localZoneFilePermissions = @fileperms(filename: $this->localZoneFile);
if ($localZoneFilePermissions & 0x0010) {
if (!$this->quiet) {
echo Colors::DEFAULT . "\t✅ Group has write access." . PHP_EOL;
}
} else {
echo "\t❌Group needs write permission!" . PHP_EOL;
$setupIsValid = false;
if (!$this->quiet) {
echo Colors::RED . "\t❌Group needs write permission!" . Colors::DEFAULT . PHP_EOL;
}
}
if (!$this->quiet) {
echo 'Checking ' . Colors::YELLOW . $this->namedConfLocalFile . PHP_EOL;
}
if (file_exists(filename: $this->namedConfLocalFile) && $namedConfLocal = file_get_contents(filename: $this->namedConfLocalFile)) {
if (!str_contains(haystack: $namedConfLocal, needle: $this->localZoneFile)) {
$setupIsValid = false;
if (!$this->quiet) {
echo "\t$this->localZoneFile" . Colors::RED . ' needs to be included in ' . Colors::YELLOW . $this->namedConfLocalFile . PHP_EOL;
}
} else {
if (!$this->quiet) {
echo "\t$this->localZoneFile" . Colors::DEFAULT . ' is included in ' . Colors::YELLOW . $this->namedConfLocalFile . PHP_EOL;
}
}
} else {
$setupIsValid = false;
if (!$this->quiet) {
echo "\t❌ No access to '$this->namedConfLocalFile' . Please check permissions" . PHP_EOL;
}
}
if (!$this->quiet) {
echo Colors::DEFAULT . 'Checking directory: ' . Colors::YELLOW . $this->localZonesDir . PHP_EOL;
}
$localZoneDirPermissions = @fileperms(filename: $this->localZonesDir);
if ($localZoneDirPermissions & 0x0010) {
if (!$this->quiet) {
echo "\t✅ Group has write access." . PHP_EOL;
}
} else {
$setupIsValid = false;
if (!$this->quiet) {
echo Colors::RED . "\t❌Group needs write permission!" . PHP_EOL;
}
}
return $setupIsValid;
}
@ -156,77 +270,112 @@ class DomainController
*/
function checkDomains(): void
{
if (!file_exists(filename: $this->localZoneFile)) {
if (!$this->quiet) {
echo Colors::DEFAULT . 'Local Zone file ' . Colors::YELLOW . $this->localZoneFile . Colors::DEFAULT . ' does not exist.' . PHP_EOL;
}
exit(1);
}
$localZones = file_get_contents(filename: $this->localZoneFile);
$maxNameLength = $this->domainRepository->getLongestEntry(field: 'name');
$domains = $this->domainRepository->findAll();
foreach ($domains as $domain) {
echo COLOR_YELLOW . str_pad(string: $domain->getName(), length: $maxNameLength + 1) . COLOR_DEFAULT;
$idString = '(' . $domain->getId() . ') ';
if (!$this->quiet) {
echo Colors::YELLOW .
str_pad(string: $domain->getName(), length: $maxNameLength + 1)
. Colors::DEFAULT
. str_pad(string: $idString, length: 7, pad_type: STR_PAD_LEFT);
}
$hasError = false;
if ($this->isMasterZone(domain: $domain)) {
echo 'Master Zone lies on this panel.';
if (!$this->quiet) {
echo Colors::GREEN . 'Master Zone';
}
} else {
if (!str_contains(haystack: $localZones, needle: $domain->getName())) {
echo COLOR_RED . ' is missing in ' . COLOR_YELLOW . $this->localZoneFile . COLOR_DEFAULT;
if (!$this->quiet) {
echo Colors::RED . 'is missing in ' . Colors::YELLOW . $this->localZoneFile . Colors::DEFAULT;
}
$hasError = true;
} else {
echo $domain->getName() . ' exists in ' . COLOR_YELLOW . $this->localZoneFile;
if (!$this->quiet) {
echo Colors::GREEN . 'OK';
}
}
$zoneFile = $this->localZonesDir . $domain->getName();
if (!file_exists(filename: $zoneFile)) {
echo "Missing zone file for $zoneFile . Update zone to create it";
echo ' Missing zone file for ' . Colors::YELLOW . $zoneFile . Colors::DEFAULT;
$hasError = true;
}
if ($hasError) {
echo " Update zone (Domain) to create it.";
}
}
echo COLOR_DEFAULT . PHP_EOL;
if (!$this->quiet) {
echo Colors::DEFAULT . PHP_EOL;
}
}
}
/**
* @param \App\Entity\Domain $domain
* @param Domain $domain
*
* @return void
*/
public function createSlaveZoneFile(Domain $domain): void
public function createSlaveZoneFile(Domain $domain): bool
{
if ($this->config['debug']) {
$domainName = $domain->getName();
$this->log->debug(message: "createZoneFile($domainName)");
}
touch(filename: $this->localZonesDir . 'zones.flag');
$domainName = $domain->getName();
$this->logger->info(message: "createZoneFile($domainName)");
// check if we're a master zone
$keyhelpConf = file_get_contents(filename: $this->keyhelpNamedCond);
if (str_contains(haystack: $keyhelpConf, needle: $domain->getName())) {
echo 'We a zone master for ' . $domain->getName() . PHP_EOL;
exit(1);
if ($this->isMasterZone(domain: $domain)) {
//echo 'We are zone master for ' . $domainName . PHP_EOL;
return true;
}
if ($zonefile = fopen(filename: $this->localZonesDir . $domain->getName(), mode: 'w')) {
if ($zoneFile = fopen(filename: $this->localZonesDir . $domainName, mode: 'w')) {
$panelName = $domain->getPanel();
$panel = $this->panelRepository->findByName(name: $panelName);
if (!$panel = $this->panelRepository->findByName(name: $panelName)) {
if (!$this->quiet) {
echo "Error: Panel $panelName doesn't exist." . PHP_EOL;
}
return false;
}
$a = $panel->getA();
$aaaa = $panel->getAaaa();
fputs(stream: $zonefile, data: 'zone "' . $domain->getName() . '"' . ' IN {' . PHP_EOL);
fputs(stream: $zonefile, data: "\ttype slave;" . PHP_EOL);
fputs(stream: $zonefile, data: "\tfile \"" . $this->zoneCachePath . $domain->getName() . '.db";' . PHP_EOL);
fputs(stream: $zonefile, data: "\tmasters {" . PHP_EOL);
fputs(stream: $zoneFile, data: 'zone "' . $domainName . '"' . ' IN {' . PHP_EOL);
fputs(stream: $zoneFile, data: "\ttype slave;" . PHP_EOL);
fputs(stream: $zoneFile, data: "\tfile \"" . $this->zoneCachePath . $domainName . '.db";' . PHP_EOL);
fputs(stream: $zoneFile, data: "\tmasters {" . PHP_EOL);
if (!empty($a)) {
fputs(stream: $zonefile, data: "\t\t" . $a . ';' . PHP_EOL);
fputs(stream: $zoneFile, data: "\t\t" . $a . ';' . PHP_EOL);
}
if (!empty($aaaa)) {
fputs(stream: $zonefile, data: "\t\t" . $aaaa . ';' . PHP_EOL);
fputs(stream: $zoneFile, data: "\t\t" . $aaaa . ';' . PHP_EOL);
}
fputs(stream: $zonefile, data: "\t};" . PHP_EOL);
fputs(stream: $zonefile, data: "};" . PHP_EOL);
}
$this->createIncludeFile();
fputs(stream: $zoneFile, data: "\t};" . PHP_EOL);
fputs(stream: $zoneFile, data: "};" . PHP_EOL);
return true;
} else {
if (!$this->quiet) {
echo Colors::RED . ' Error: ' . Colors::DEFAULT . 'unable to create ' . Colors::YELLOW . $this->localZonesDir . $domainName . Colors::DEFAULT . PHP_EOL;
}
return false;
}
}
private function isMasterZone(Domain $domain): bool
public function isMasterZone(Domain $domain): bool
{
if (file_exists(filename: '/etc/bind/keyhelp_domains/' . $domain->getName())) {
return true;
@ -234,4 +383,5 @@ class DomainController
return false;
}
}
}
}

View File

@ -0,0 +1,71 @@
<?php
namespace App\Controller;
use Exception;
use SodiumException;
/**
*
*/
class EncryptionController
{
/**
* Encrypt a message
*
* @param string $message - message to encrypt
* @param string $key - encryption key
* @return string
*/
function safeEncrypt(string $message, string $key): string
{
try {
$binKey = sodium_hex2bin(string: $key);
$nonce = random_bytes(length: SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$cipher = base64_encode(string: $nonce . sodium_crypto_secretbox(message: $message, nonce: $nonce, key: $binKey));
sodium_memzero(string: $message);
sodium_memzero(string: $key);
sodium_memzero(string: $binKey);
return $cipher;
} catch (Exception|SodiumException $e) {
exit($e->getMessage() . PHP_EOL);
}
}
/**
* Decrypt a message
*
* @param string $encrypted - message encrypted with safeEncrypt()
* @param string $key - encryption key
* @return string
*/
function safeDecrypt(string $encrypted, string $key): string
{
try {
$binKey = sodium_hex2bin(string: $key);
$decoded = base64_decode(string: $encrypted);
if ($decoded === false) {
throw new Exception(message: 'Decoding broken. Wrong payload.');
}
if (mb_strlen(string: $decoded, encoding: '8bit') < (SODIUM_CRYPTO_SECRETBOX_NONCEBYTES + SODIUM_CRYPTO_SECRETBOX_MACBYTES)) {
throw new Exception(message: 'Decoding broken. Incomplete message.');
}
$nonce = mb_substr(string: $decoded, start: 0, length: SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, encoding: '8bit');
$ciphertext = mb_substr(string: $decoded, start: SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, length: null, encoding: '8bit');
$plain = sodium_crypto_secretbox_open(ciphertext: $ciphertext, nonce: $nonce, key: $binKey);
if ($plain === false) {
throw new Exception(message: ' Incorrect key.');
}
sodium_memzero(string: $ciphertext);
sodium_memzero(string: $key);
return $plain;
} catch(Exception|SodiumException $e) {
exit($e->getMessage());
}
}
}

View File

@ -1,18 +0,0 @@
<?php declare(strict_types=1);
namespace App\Controller;
error_reporting(error_level: E_ALL);
/**
*
*/
class NameserverController
{
public function __construct(private DatabaseConnection $databaseConnection)
{}
}

View File

@ -1,19 +0,0 @@
<?php declare(strict_types=1);
namespace App\Controller;
error_reporting(error_level: E_ALL);
/**
*
*/
class PanelController
{
public function __construct(private DatabaseConnection $databaseConnection)
{}
}

File diff suppressed because it is too large Load Diff

View File

@ -2,89 +2,73 @@
namespace App\Entity;
/**
*
*/
use App\Controller\ConfigController;
use App\Controller\EncryptionController;
use Exception;
class Apikey
{
private int $id;
private string $name;
private string $apiTokenPrefix;
private string $apiToken;
public function __construct(string $name, string $apiTokenPrefix, string $apiToken, int $id = 0)
{
$this->id = $id;
$this->name = $name;
$this->apiTokenPrefix = $apiTokenPrefix;
$this->apiToken = $apiToken;
}
/**
* @return String
*/
public function getApiToken(): string
{
return $this->apiToken;
}
/**
* @return string
*/
public function getApiTokenPrefix(): string
{
return $this->apiTokenPrefix;
}
/**
* @return int
*/
public function getId(): int
{
return $this->id;
}
/**
* @param int $id
*/
public function setId(int $id): void
{
$this->id = $id;
}
/**
* @return String
*/
public function getName(): string
{
return $this->name;
}
/**
* @param string $apiTokenPrefix
*/
public function setApiTokenPrefix(string $apiTokenPrefix): void
{
$this->apiTokenPrefix = $apiTokenPrefix;
}
/**
* @param String $apiToken
*/
public function setApiToken(string $apiToken): void
{
$this->apiToken = $apiToken;
}
/**
* @param String $name
*/
public function setName(string $name): void
{
$this->name = $name;
}
public function __construct(
private int $id = 0,
private string $name = '',
private string $apikey = '',
private string $apikeyPrefix = '',
private readonly string $passphrase = '',
private string $createdAt = ''
)
{
if ($this->passphrase) {
$configController = new ConfigController(quiet: true);
$encryptionController = new EncryptionController();
$encryptionKey = $configController->getConfig(configKey: 'encryptionKey');
$this->apikey = strtok(string: $this->passphrase, token: '.');
try {
$this->apikey = $encryptionController->safeEncrypt(message: $this->passphrase, key: $encryptionKey);
} catch (Exception $e) {
exit($e->getMessage() . PHP_EOL);
}
}
}
public function getCreatedAt(): string
{
return $this->createdAt;
}
public function getApikey(): string
{
return $this->apikey;
}
public function getApikeyPrefix(): string
{
return $this->apikeyPrefix;
}
public function getId(): int
{
return $this->id;
}
public function getName(): string
{
return $this->name;
}
public function setApikey(string $apikey): void
{
$this->apikey = $apikey;
}
public function setName(string $name): void
{
$this->name = $name;
}
}

View File

@ -2,10 +2,6 @@
namespace App\Entity;
use App\Enums\PanelType;
/**
*
*/

98
src/Entity/DynDNS.php Normal file
View File

@ -0,0 +1,98 @@
<?php declare(strict_types=1);
namespace App\Entity;
/**
*
*/
class DynDNS
{
/**
*/
public function __construct(private string $name, private string $a = '', private string $aaaa = '', private $password = '', private int $id = 0)
{
}
/**
* @return string
*/
public function getPassword(): string
{
return $this->password;
}
/**
* @param string $password
*/
public function setPassword(string $password): void
{
$this->password = $password;
}
/**
* @return String
*/
public function getA(): string
{
return $this->a;
}
/**
* @return String
*/
public function getAaaa(): string
{
return $this->aaaa;
}
/**
* @return int
*/
public function getId(): int
{
return $this->id;
}
/**
* @return String
*/
public function getName(): string
{
return $this->name;
}
/**
* @param String $a
*/
public function setA(string $a): void
{
$this->a = $a;
}
/**
* @param String $aaaa
*/
public function setAaaa(string $aaaa): void
{
$this->aaaa = $aaaa;
}
/**
* @param int $id
*/
public function setId(int $id): void
{
$this->id = $id;
}
/**
* @param String $name
*/
public function setName(string $name): void
{
$this->name = $name;
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace App\Entity\KeyHelp;
/**
*
*/
class Apache
{
private ?string $httpDirectives;
private ?string $httpsDirectives;
/**
* @return string
*/
public function getHttpDirectives(): string
{
return $this->httpDirectives;
}
/**
* @param string|null $httpDirectives
*/
public function setHttpDirectives(?string $httpDirectives): void
{
$this->httpDirectives = $httpDirectives;
}
/**
* @return string
*/
public function getHttpsDirectives(): string
{
return $this->httpsDirectives;
}
/**
* @param string|null $httpsDirectives
*/
public function setHttpsDirectives(?string $httpsDirectives): void
{
$this->httpsDirectives = $httpsDirectives;
}
}

View File

@ -0,0 +1,405 @@
<?php
namespace App\Entity\KeyHelp;
use DateTime;
/**
*
*/
class KeyHelpDomain
{
private int $id;
private int $idUser;
private int $idParentDomain;
private int $status;
private string $domain;
private string $domainUtf8;
private DateTime $createdAt;
private string $phpVersion;
private bool $isDisabled;
private ?DateTime $deleteOn;
private string $dkimTxtRecord;
private bool $isCustomDns;
private bool $isDnsDisabled;
private bool $isSubdomain;
private bool $isSystemDomain;
private bool $isEmailDomain;
private Target $target;
private Security $security;
private Apache $apache;
private string $dkimSelector;
private string $dkimRecord;
private ?string $dkimTextRecord;
public function __construct()
{
$this->dkimTextRecord = null;
}
private int $traffic;
private bool $isEmailSendingOnly;
public function isEmailSendingOnly(): bool
{
return $this->isEmailSendingOnly;
}
public function setIsEmailSendingOnly(bool $isEmailSendingOnly): void
{
$this->isEmailSendingOnly = $isEmailSendingOnly;
}
public function getTraffic(): int
{
return $this->traffic;
}
public function setTraffic(int $traffic): void
{
$this->traffic = $traffic;
}
public function getDkimTextRecord(): string
{
return $this->dkimTextRecord;
}
public function setDkimTextRecord(string $dkimTextRecord): void
{
$this->dkimTextRecord = $dkimTextRecord;
}
public function getDkimRecord(): string
{
return $this->dkimRecord;
}
public function setDkimRecord(string $dkimRecord): void
{
$this->dkimRecord = $dkimRecord;
}
public function getDkimSelector(): string
{
return $this->dkimSelector;
}
public function setDkimSelector(string $dkimSelector): void
{
$this->dkimSelector = $dkimSelector;
}
/**
* @return Apache
*/
public function getApache(): Apache
{
return $this->apache;
}
/**
* @param Apache $apache
*/
public function setApache(Apache $apache): void
{
$this->apache = $apache;
}
/**
* @return Security
*/
public function getSecurity(): Security
{
return $this->security;
}
/**
* @param Security $security
*/
public function setSecurity(Security $security): void
{
$this->security = $security;
}
/**
* @return Target
*/
public function getTarget(): Target
{
return $this->target;
}
/**
* @param Target $target
*/
public function setTarget(Target $target): void
{
$this->target = $target;
}
/**
* @return bool
*/
public function isEmailDomain(): bool
{
return $this->isEmailDomain;
}
/**
* @param bool $isEmailDomain
*/
public function setIsEmailDomain(bool $isEmailDomain): void
{
$this->isEmailDomain = $isEmailDomain;
}
/**
* @return bool
*/
public function isSystemDomain(): bool
{
return $this->isSystemDomain;
}
/**
* @param bool $isSystemDomain
*/
public function setIsSystemDomain(bool $isSystemDomain): void
{
$this->isSystemDomain = $isSystemDomain;
}
/**
* @return bool
*/
public function isSubdomain(): bool
{
return $this->isSubdomain;
}
/**
* @param bool $isSubdomain
*/
public function setIsSubdomain(bool $isSubdomain): void
{
$this->isSubdomain = $isSubdomain;
}
/**
* @return bool
*/
public function isDnsDisabled(): bool
{
return $this->isDnsDisabled;
}
/**
* @param bool $isDnsDisabled
*/
public function setIsDnsDisabled(bool $isDnsDisabled): void
{
$this->isDnsDisabled = $isDnsDisabled;
}
/**
* @return bool
*/
public function isCustomDns(): bool
{
return $this->isCustomDns;
}
/**
* @param bool $isCustomDns
*/
public function setIsCustomDns(bool $isCustomDns): void
{
$this->isCustomDns = $isCustomDns;
}
/**
* @return string
*/
public function getDkimTxtRecord(): string
{
return $this->dkimTxtRecord;
}
/**
* @param string $dkimTxtRecord
*/
public function setDkimTxtRecord(string $dkimTxtRecord): void
{
$this->dkimTxtRecord = $dkimTxtRecord;
}
/**
* @return DateTime
*/
public function getDeleteOn(): DateTime
{
return $this->deleteOn;
}
/**
* @param DateTime|null $deleteOn
*/
public function setDeleteOn(?DateTime $deleteOn): void
{
$this->deleteOn = $deleteOn;
}
/**
* @return bool
*/
public function isDisabled(): bool
{
return $this->isDisabled;
}
/**
* @param bool $isDisabled
*/
public function setIsDisabled(bool $isDisabled): void
{
$this->isDisabled = $isDisabled;
}
/**
* @return string
*/
public function getPhpVersion(): string
{
return $this->phpVersion;
}
/**
* @param string $phpVersion
*/
public function setPhpVersion(string $phpVersion): void
{
$this->phpVersion = $phpVersion;
}
/**
* @return DateTime
*/
public function getCreatedAt(): DateTime
{
return $this->createdAt;
}
/**
* @param DateTime $createdAt
*/
public function setCreatedAt(DateTime $createdAt): void
{
$this->createdAt = $createdAt;
}
/**
* @return string
*/
public function getDomainUtf8(): string
{
return $this->domainUtf8;
}
/**
* @param string $domainUtf8
*/
public function setDomainUtf8(string $domainUtf8): void
{
$this->domainUtf8 = $domainUtf8;
}
/**
* @return string
*/
public function getDomain(): string
{
return $this->domain;
}
/**
* @param string $domain
*/
public function setDomain(string $domain): void
{
$this->domain = $domain;
}
/**
* @return int
*/
public function getStatus(): int
{
return $this->status;
}
/**
* @param int $status
*/
public function setStatus(int $status): void
{
$this->status = $status;
}
/**
* @return int
*/
public function getIdParentDomain(): int
{
return $this->idParentDomain;
}
/**
* @param int $idParentDomain
*/
public function setIdParentDomain(int $idParentDomain): void
{
$this->idParentDomain = $idParentDomain;
}
/**
* @return int
*/
public function getIdUser(): int
{
return $this->idUser;
}
/**
* @param int $idUser
*/
public function setIdUser(int $idUser): void
{
$this->idUser = $idUser;
}
/**
* @return int
*/
public function getId(): int
{
return $this->id;
}
/**
* @param int $id
*/
public function setId(int $id): void
{
$this->id = $id;
}
}

View File

@ -0,0 +1,130 @@
<?php
namespace App\Entity\KeyHelp;
/**
*
*/
class Security
{
private int $idCertificate;
private bool $letsEncrypt;
private bool $forceHttps;
private bool $isHsts;
private int $hstsMaxAge;
private bool $hstsInclude;
private bool $hstsPreload;
/**
* @return int
*/
public function getIdCertificate(): int
{
return $this->idCertificate;
}
/**
* @param int $idCertificate
*/
public function setIdCertificate(int $idCertificate): void
{
$this->idCertificate = $idCertificate;
}
/**
* @return bool
*/
public function isLetsEncrypt(): bool
{
return $this->letsEncrypt;
}
/**
* @param bool $letsEncrypt
*/
public function setLetsEncrypt(bool $letsEncrypt): void
{
$this->letsEncrypt = $letsEncrypt;
}
/**
* @return bool
*/
public function isHsts(): bool
{
return $this->isHsts;
}
/**
* @param bool $isHsts
*/
public function setIsHsts(bool $isHsts): void
{
$this->isHsts = $isHsts;
}
/**
* @return int
*/
public function getHstsMaxAge(): int
{
return $this->hstsMaxAge;
}
/**
* @param int $hstsMaxAge
*/
public function setHstsMaxAge(int $hstsMaxAge): void
{
$this->hstsMaxAge = $hstsMaxAge;
}
/**
* @return bool
*/
public function isHstsInclude(): bool
{
return $this->hstsInclude;
}
/**
* @param bool $hstsInclude
*/
public function setHstsInclude(bool $hstsInclude): void
{
$this->hstsInclude = $hstsInclude;
}
/**
* @return bool
*/
public function isHstsPreload(): bool
{
return $this->hstsPreload;
}
/**
* @param bool $hstsPreload
*/
public function setHstsPreload(bool $hstsPreload): void
{
$this->hstsPreload = $hstsPreload;
}
/**
* @return bool
*/
public function isForceHttps(): bool
{
return $this->forceHttps;
}
/**
* @param bool $forceHttps
*/
public function setForceHttps(bool $forceHttps): void
{
$this->forceHttps = $forceHttps;
}
}

View File

@ -0,0 +1,61 @@
<?php
namespace App\Entity\KeyHelp;
/**
*
*/
class Target
{
private string $target;
private bool $isForwarding;
private ?string $forwardingType;
/**
* @return string
*/
public function getForwardingType(): string
{
return $this->forwardingType;
}
/**
* @param string|null $forwardingType
*/
public function setForwardingType(?string $forwardingType): void
{
$this->forwardingType = $forwardingType;
}
/**
* @return bool
*/
public function isForwarding(): bool
{
return $this->isForwarding;
}
/**
* @param bool $isForwarding
*/
public function setIsForwarding(bool $isForwarding): void
{
$this->isForwarding = $isForwarding;
}
/**
* @return string
*/
public function getTarget(): string
{
return $this->target;
}
/**
* @param string $target
*/
public function setTarget(string $target): void
{
$this->target = $target;
}
}

View File

@ -2,114 +2,173 @@
namespace App\Entity;
use App\Controller\ConfigController;
use App\Controller\EncryptionController;
use Exception;
use OpenApi\Attributes as OAT;
use SodiumException;
/**
*
*/
#[OAT\Schema(schema: 'nameserver')]
class Nameserver
{
private int $id;
private String $name;
private String $a;
private String $aaaa;
private String $apikey;
public function __construct(String $name, int $id = 0, String $a = '', String $aaaa = '', String $apikey = '')
{
$this->id = $id;
$this->name = $name;
$this->a = $a;
$this->aaaa = $aaaa;
$this->apikey = $apikey;
}
/**
* @return String
*/
#[OAT\Property(type: 'string')]
public function getA(): string
{
return $this->a;
}
/**
* @param String $a
*/
public function setA(string $a): void
{
$this->a = $a;
}
/**
* @return String
*/
#[OAT\Property(type: 'string')]
public function getAaaa(): string
{
return $this->aaaa;
}
/**
* @param String $aaaa
*/
public function setAaaa(string $aaaa): void
{
$this->aaaa = $aaaa;
}
/**
* @return String
*/
#[OAT\Property(type: 'string')]
public function getApikey(): string
{
return $this->apikey;
}
/**
* @param String $apikey
*/
public function setApikey(string $apikey): void
{
$this->apikey = $apikey;
}
/**
* @return int
*/
#[OAT\Property(type: 'int')]
public function getId(): int
{
return $this->id;
}
/**
* @param int $id
*/
public function setId(int $id): void
{
$this->id = $id;
}
/**
* @return String
*/
#[OAT\Property(type: 'string')]
public function getName(): string
{
return $this->name;
}
/**
* @param String $name
*/
public function setName(string $name): void
{
$this->name = $name;
}
/**
* @param string $name
* @param int $id
* @param string $a
* @param string $aaaa
* @param string $passphrase
* @param string $apikey
* @param string $apikeyPrefix
*/
public function __construct(
private string $name,
private int $id = 0,
private string $a = '',
private string $aaaa = '',
private readonly string $passphrase = '',
private string $apikey = '',
private string $apikeyPrefix = '',
private string $self = 'no'
)
{
if ($this->passphrase) {
$configController = new ConfigController(quiet: false);
$encryptionController = new EncryptionController();
$encryptionKey = $configController->getConfig(configKey: 'encryptionKey');
[$this->apikeyPrefix] = explode(separator: '.', string: $this->passphrase);
try {
$this->apikey = $encryptionController->safeEncrypt(message: $this->passphrase, key: $encryptionKey);
} catch (Exception|SodiumException $e) {
exit($e->getMessage() . PHP_EOL);
}
}
}
public function getSelf(): string
{
return $this->self;
}
public function setSelf(string $self): void
{
$this->self = $self;
}
/**
* @return string
*/
public function getApikeyPrefix(): string
{
return $this->apikeyPrefix;
}
/**
* @param string $apikeyPrefix
*/
public function setApikeyPrefix(string $apikeyPrefix): void
{
$this->apikeyPrefix = $apikeyPrefix;
}
/**
* @return string
*/
#[OAT\Property(type: 'string')]
public function getA(): string
{
return $this->a;
}
/**
* @param string $a
*/
public function setA(string $a): void
{
$this->a = $a;
}
/**
* @return string
*/
#[OAT\Property(type: 'string')]
public function getAaaa(): string
{
return $this->aaaa;
}
/**
* @param string $aaaa
*/
public function setAaaa(string $aaaa): void
{
$this->aaaa = $aaaa;
}
/**
* @return string
*/
#[OAT\Property(type: 'string')]
public function getApikey(): string
{
return $this->apikey;
}
/**
* @param string $apikey
*/
public function setApikey(string $apikey): void
{
$this->apikey = $apikey;
}
/**
* @return int
*/
#[OAT\Property(type: 'int')]
public function getId(): int
{
return $this->id;
}
/**
* @param int $id
*/
public function setId(int $id): void
{
$this->id = $id;
}
/**
* @return string
*/
#[OAT\Property(type: 'string')]
public function getName(): string
{
return $this->name;
}
/**
* @param string $name
*/
public function setName(string $name): void
{
$this->name = $name;
}
/**
* @return string
*/
public function getPassphrase(): string
{
return $this->passphrase;
}
}

View File

@ -2,107 +2,150 @@
namespace App\Entity;
use App\Controller\ConfigController;
use App\Controller\EncryptionController;
use Exception;
use SodiumException;
/**
*
*/
class Panel
{
private int $id;
private String $name;
private String $a;
private String $aaaa;
private String $apikey;
public function __construct(String $name, int $id = 0, String $a = '', String $aaaa = '', String $apikey = '')
{
$this->id = $id;
$this->name = $name;
$this->a = $a;
$this->aaaa = $aaaa;
$this->apikey = $apikey;
}
/**
* @return String
*/
public function getA(): string
{
return $this->a;
}
/**
* @return String
*/
public function getAaaa(): string
{
return $this->aaaa;
}
/**
* @return String
*/
public function getApikey(): string
{
return $this->apikey;
}
/**
* @return int
*/
public function getId(): int
{
return $this->id;
}
/**
* @param int $id
*/
public function setId(int $id): void
{
$this->id = $id;
}
/**
* @return String
*/
public function getName(): string
{
return $this->name;
}
/**
* @param String $apikey
*/
public function setApikey(string $apikey): void
{
$this->apikey = $apikey;
}
/**
* @param String $name
*/
public function setName(string $name): void
{
$this->name = $name;
}
/**
* @param String $a
*/
public function setA(string $a): void
{
$this->a = $a;
}
/**
* @param String $aaaa
*/
public function setAaaa(string $aaaa): void
{
$this->aaaa = $aaaa;
}
}
public function __construct(
private string $name,
private int $id = 0,
private string $a = '',
private string $aaaa = '',
private readonly string $passphrase = '',
private string $apikey = '',
private string $apikeyPrefix = '',
private string $self = 'no',
)
{
if ($this->passphrase) {
$configController = new ConfigController(quiet: false);
$encryptionController = new EncryptionController();
$encryptionKey = $configController->getConfig(configKey: 'encryptionKey');
$this->apikeyPrefix = strtok(string: $this->passphrase, token: '.');
try {
$this->apikey = $encryptionController->safeEncrypt(message: $this->passphrase, key: $encryptionKey);
} catch (Exception|SodiumException $e) {
exit($e->getMessage() . PHP_EOL);
}
}
}
/**
* @return string
*/
public function getPassphrase(): string
{
return $this->passphrase;
}
/**
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* @param string $name
*/
public function setName(string $name): void
{
$this->name = $name;
}
/**
* @return int
*/
public function getId(): int
{
return $this->id;
}
/**
* @param int $id
*/
public function setId(int $id): void
{
$this->id = $id;
}
/**
* @return string
*/
public function getA(): string
{
return $this->a;
}
/**
* @return string
*/
public function getSelf(): string
{
return $this->self;
}
/**
* @param string $self
*/
public function setSelf(string $self): void
{
$this->self = $self;
}
/**
* @return string
*/
public function getAaaa(): string
{
return $this->aaaa;
}
/**
* @return string
*/
public function getApikey(): string
{
return $this->apikey;
}
/**
* @param string $a
*/
public function setA(string $a): void
{
$this->a = $a;
}
/**
* @param string $aaaa
*/
public function setAaaa(string $aaaa): void
{
$this->aaaa = $aaaa;
}
/**
* @return string
*/
public function getApikeyPrefix(): string
{
return $this->apikeyPrefix;
}
}

View File

@ -1 +0,0 @@
<?php

View File

@ -0,0 +1,86 @@
<?php
namespace App\Provider;
//error_reporting(error_level: E_ALL);
use App\Utilities\Colors;
use PDO;
use PDOException;
use PHPUnit\Exception;
use App\Controller\ConfigController;
/**
*
*/
class DatabaseConnection
{
private PDO $dbConnection;
const TABLE_PREFIX = '';
const TABLE_DOMAINS = self::TABLE_PREFIX . "domains";
const TABLE_NAMESERVERS = self::TABLE_PREFIX . "nameservers";
const TABLE_PANELS = self::TABLE_PREFIX . "panels";
const TABLE_APIKEYS = self::TABLE_PREFIX . "apikeys";
const TABLE_DYNDNS = self::TABLE_PREFIX . "dyndns";
const TABLE_SETTINGS = self::TABLE_PREFIX . 'config';
public function __construct(private readonly ConfigController $configController)
{
$dbHost = $this->configController->getConfig(configKey: 'dbHost');
$dbPort = $this->configController->getConfig(configKey: 'dbPort');
$dbDatabase = $this->configController->getConfig(configKey: 'dbDatabase');
$dbUser = $this->configController->getConfig(configKey: 'dbUser');
$dbPassword = $this->configController->getConfig(configKey: 'dbPassword');
try {
$this->dbConnection = new PDO(
dsn: "mysql:host=$dbHost;port=$dbPort;charset=utf8mb4;dbname=$dbDatabase",
username: $dbUser,
password: $dbPassword
);
} catch (Exception $e) {
echo $e->getMessage() . PHP_EOL;
echo 'Did you create the database and adjust the config file?' . PHP_EOL;
exit(1);
}
if (!$this->configController->getConfig(configKey: 'test')) {
try {
$sql = "SHOW TABLES";
$statement = $this->dbConnection->prepare(query: $sql);
$statement->execute();
$result = $statement->fetch();
if (empty($result)) {
// ALTER TABLE `domains` ADD `panel_id` INT NULL AFTER `id`;
echo Colors::RED . 'Error: ' . Colors::DEFAULT . 'Cannot find tables.' . PHP_EOL;
echo 'Run the migration: ' . Colors::YELLOW . './bin/console migrations:migrate' . Colors::DEFAULT . PHP_EOL;
}
} catch (PDOException $exception) {
echo $exception->getMessage() . PHP_EOL;
echo 'Did you create the database and adjust the config file?' . PHP_EOL;
echo PHP_EOL . 'You can create database an user via a panel or manually in mysql shell:' . PHP_EOL;
$password = $this->generatePassword();
echo 'Created an initial password: ' . $password . PHP_EOL;
echo 'CREATE DATABASE bindAPI;' . PHP_EOL;
echo "CREATE USER 'bindAPI'@'localhost' IDENTIFIED BY '$password';" . PHP_EOL;
echo "GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, INDEX, DROP, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES ON bindAPI.* TO 'bindAPI'@'localhost';" . PHP_EOL;
echo 'There is no need to run FLUSH PRIVILEGES when using GRANT!' . PHP_EOL;
exit(1);
}
}
}
function generatePassword(int $length = 8): string
{
$chars = '23456789bcdfhkmnprstvzBCDFHJKLMNPRSTVZ';
$shuffled = str_shuffle(string: $chars);
return mb_substr(string: $shuffled, start: 0, length: $length);
}
public function getConnection(): PDO
{
return $this->dbConnection;
}
}

View File

@ -3,10 +3,9 @@ namespace App\Repository;
error_reporting(error_level: E_ALL);
use App\Controller\DatabaseConnection;
use App\Controller\PanelController;
use App\Provider\DatabaseConnection;
use App\Controller\EncryptionController;
use App\Entity\Apikey;
use Exception;
use PDO;
use PDOException;
@ -15,30 +14,28 @@ use PDOException;
*/
class ApikeyRepository
{
public function __construct(private DatabaseConnection $databaseConnection, PanelController $panelController)
public function __construct(private readonly DatabaseConnection $databaseConnection, EncryptionController $encryptionController)
{}
/**
* @return array|false
*/
public function findAll(): bool|array
{
$sql = "
SELECT id, name, api_token_prefix, api_token
SELECT id, name, apikey_prefix, apikey, created_at
FROM " . DatabaseConnection::TABLE_APIKEYS;
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->execute();
$apikeys = [];
$apiKeys = [];
while ($result = $statement->fetch()) {
$apikey = new Apikey(name: $result['name'], apiTokenPrefix: $result['api_token_prefix'], apiToken: $result['api_token'], id: $result['id']);
$apikeys[] = $apikey;
$apikey = new Apikey(id: $result['id'], name: $result['name'], apikey: $result['apikey'], apikeyPrefix: $result['apikey_prefix'], createdAt: $result['created_at']);
$apiKeys[] = $apikey;
}
return $apikeys;
return $apiKeys;
} catch (PDOException $e) {
exit($e->getMessage());
}
@ -48,12 +45,12 @@ class ApikeyRepository
/**
* @param Int $id
*
* @return \App\Entity\Apikey|bool
* @return Apikey|bool
*/
public function findByID(Int $id): Apikey|bool
{
$sql = "
SELECT id, name, api_token_prefix, api_token
SELECT id, name, apikey_prefix, apikey
FROM " . DatabaseConnection::TABLE_APIKEYS . "
WHERE id = :id;
";
@ -63,7 +60,7 @@ class ApikeyRepository
$statement->bindParam(param: ':id', var: $id);
$statement->execute();
if ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
return new Apikey(name: $result['name'], apiTokenPrefix: $result['api_token_prefix'], apiToken: $result['api_token'], id: $result['id']);
return new Apikey(id: $result['id'], name: $result['name'], apikey: $result['apikey'], apikeyPrefix: $result['apikey_prefix']);
} else {
return false;
}
@ -76,21 +73,21 @@ class ApikeyRepository
/**
* @param String $prefix
*
* @return \App\Entity\Apikey|bool
* @return Apikey|bool
*/
public function findByPrefix(String $prefix): Apikey|bool
{
$sql = "
SELECT id, name, api_token_prefix, api_token
SELECT id, name, apikey_prefix, apikey
FROM " . DatabaseConnection::TABLE_APIKEYS . "
WHERE api_token_prefix = :prefix";
WHERE apikey_prefix = :prefix";
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: ':prefix', var: $prefix);
$statement->execute();
if ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
return new Apikey(name: $result['name'], apiTokenPrefix: $result['api_token_prefix'], apiToken: $result['api_token'], id: $result['id']);
return new Apikey(id: $result['id'], name: $result['name'], apikey: $result['apikey'], apikeyPrefix: $result['apikey_prefix']);
} else {
return false;
}
@ -98,56 +95,51 @@ class ApikeyRepository
exit($e->getMessage());
}
}
/**
* @return array|void
*/
public function create(String $name = '')
{
$tokenPrefix = uniqid();
$result['tokenPrefix'] = $tokenPrefix;
try {
$key = bin2hex(string: random_bytes(length: 24));
$result['key'] = $key;
} catch (Exception $e) {
echo $e->getMessage() . PHP_EOL;
exit(1);
}
$token = password_hash(password: $tokenPrefix . '.' . $key, algo: PASSWORD_ARGON2ID);
/**
* @param Apikey $apikey
* @return int
*/
public function insert(ApiKey $apikey): int
{
$name = $apikey->getName();
$apikeyPrefix = $apikey->getApikeyPrefix();
$apikeyValue = $apikey->getApikey();
$sql = "
INSERT INTO " . DatabaseConnection::TABLE_APIKEYS . " (name, api_token_prefix, api_token)
VALUES (:name, :token_prefix, :token)";
INSERT INTO " . DatabaseConnection::TABLE_APIKEYS . " (name, apikey_prefix, apikey)
VALUES (:name, :apikey_prefix, :apikey)";
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: ':token_prefix', var: $tokenPrefix);
$statement->bindParam(param: ':token', var: $token);
$statement->bindParam(param: ':name', var: $name);
$statement->bindParam(param: ':name', var: $name);
$statement->bindParam(param: ':apikey_prefix', var: $apikeyPrefix);
$statement->bindParam(param: ':apikey', var: $apikeyValue);
$statement->execute();
$result['row'] = $this->databaseConnection->getConnection()->lastInsertId();
return $result;
return intval(value: $this->databaseConnection->getConnection()->lastInsertId());
} catch (PDOException $e) {
exit($e->getMessage());
}
}
/**
* @param Int $id
* @param String $name
*
* @return false|int
*/
public function update(int $id, string $name): bool|int
/**
* @param Apikey $apikey
* @return false|int
*/
public function update(Apikey $apikey): bool|int
{
$current = $this->findByID(id: $id);
if (empty($name)) {
$name = $current['name'];
}
$id = $apikey->getId();
$name = $apikey->getName();
$current = $this->findByID(id: $id);
if (empty($name)) {
$name = $current->getName();
}
$sql = "
UPDATE " . DatabaseConnection::TABLE_APIKEYS . " SET
name = :name
@ -161,7 +153,7 @@ class ApikeyRepository
return $statement->rowCount();
} catch (PDOException $e) {
print($e->getMessage());
echo $e->getMessage();
return false;
}
}
@ -188,4 +180,4 @@ class ApikeyRepository
}
}
}
}

View File

@ -2,7 +2,8 @@
namespace App\Repository;
use App\Controller\DatabaseConnection;
use App\Controller\ConfigController;
use App\Provider\DatabaseConnection;
use App\Entity\Domain;
use Monolog\Logger;
use PDO;
@ -11,13 +12,14 @@ use PDOException;
/**
*
*/
class DomainRepository
readonly class DomainRepository
{
public function __construct(private DatabaseConnection $databaseConnection, private array $config, private Logger $log)
public function __construct(
private DatabaseConnection $databaseConnection,
private ConfigController $configController,
private Logger $logger)
{
if ($this->config['debug']) {
$this->log->debug(message: "DomainRepository::__construct()");
}
$this->logger->debug(message: "DomainRepository::__construct()");
}
@ -27,9 +29,7 @@ class DomainRepository
*/
public function findAll(): array
{
if ($this->config['debug']) {
$this->log->debug(message: "findAll()");
}
$this->logger->debug(message: "findAll()");
$domains = [];
$sql = "
@ -41,8 +41,6 @@ class DomainRepository
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->execute();
while ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
//print_r($result);
//die();
$domain = new Domain(name: $result['name'], panel: $result['panel'], id: $result['id']);
$domains[] = $domain;
}
@ -51,18 +49,34 @@ class DomainRepository
exit($e->getMessage());
}
}
/**
* @param int $id
*
* @return bool|\App\Entity\Domain
*/
public function findByPanel(string $name): array
{
$this->logger->debug(message: "findByPanel($name)");
$domains = [];
$sql = "
SELECT id, name, panel
FROM . " . DatabaseConnection::TABLE_DOMAINS . "
WHERE panel = :panel";
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: ':panel', var: $name);
$statement->execute();
while ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
$domain = new Domain(name: $result['name'], panel: $result['panel'], id: $result['id']);
$domains[$result['name']] = $domain;
}
return $domains;
} catch (PDOException $e) {
exit($e->getMessage());
}
}
public function findByID(int $id): bool|Domain
{
if ($this->config['debug']) {
$this->log->debug(message: "findById($id)");
}
$this->logger->debug(message: "findById($id)");
$sql = "
SELECT id, name, panel
@ -85,16 +99,11 @@ class DomainRepository
}
/**
* @param String $name
*
* @return \App\Entity\Domain|bool
*/
public function findByName(string $name): Domain|bool
{
if ($this->config['debug']) {
$this->log->debug(message: "findByName($name)");
}
$this->logger->debug(message: "findByName($name)");
$sql = "
SELECT id, name, panel
FROM " . DatabaseConnection::TABLE_DOMAINS . "
@ -114,18 +123,33 @@ class DomainRepository
}
}
public function findByHost(string $host): Domain|bool
{
$this->logger->debug(message: "findByHost($host)");
$host = strtolower(string: trim(string: $host));
$count = substr_count(haystack: $host, needle: '.');
if ($count == 2) {
if (strlen(string: explode(separator: '.', string: $host)[1]) > 3) {
$host = explode(separator: '.', string: $host, limit: 2)[1];
}
} elseif ($count > 2) {
$host = $this->findByHost(host: explode(separator: '.', string: $host, limit: 2)[1]);
}
if ($domain = $this->findByName(name: $host)) {
return $domain;
} else {
return false;
}
}
/**
* @param \App\Entity\Domain $domain
*
* @return string|false
*/
public function insert(Domain $domain): bool|string
{
if ($this->config['debug']) {
$domainName = $domain->getName();
$this->log->debug(message: "insert($domainName)");
}
$domainName = $domain->getName();
$this->logger->info(message: "insert($domainName)");
$sql = "
INSERT INTO " . DatabaseConnection::TABLE_DOMAINS . " (name, panel)
@ -153,10 +177,8 @@ class DomainRepository
*/
public function update(Domain $domain): bool|int
{
if ($this->config['debug']) {
$domainName = $domain->getName();
$this->log->debug(message: "update($domainName)");
}
$domainName = $domain->getName();
$this->logger->debug(message: "update($domainName)");
$id = $domain->getId();
$current = $this->findByID(id: $id);
@ -187,24 +209,17 @@ class DomainRepository
return $statement->rowCount();
} catch (PDOException $e) {
print($e->getMessage());
echo $e->getMessage();
return false;
}
}
/**
* @param \App\Entity\Domain $domain
*
* @return int
*/
public function delete(Domain $domain): int
public function delete(Domain $domain): int
{
if ($this->config['debug']) {
$domainName = $domain->getName();
$this->log->debug(message: "delete($domainName)");
}
$domainName = $domain->getName();
$this->logger->debug(message: "delete($domainName)");
// FIXME, add force parameter, reject deletion if domains left on panel
$sql = "
DELETE FROM " . DatabaseConnection::TABLE_DOMAINS . "
WHERE id = :id";
@ -220,14 +235,9 @@ class DomainRepository
exit($e->getMessage());
}
}
/**
* @param String $field
*
* @return int
*/
public function getLongestEntry(String $field): int
// FIXME check for master/slave in config generation
public function getLongestEntry(string $field): int
{
$sql = "
SELECT MAX(LENGTH(" . $field . ")) as length FROM " . DatabaseConnection::TABLE_DOMAINS;
@ -235,10 +245,11 @@ class DomainRepository
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->execute();
$result = $statement->fetch();
return $result['length'];
$result = $statement->fetch();
// if there are not yet any domains, just return 30
return $result['length'] ?? 30;
} catch (PDOException $e) {
exit($e->getMessage());
}
}
}
}

View File

@ -0,0 +1,233 @@
<?php declare(strict_types=1);
namespace App\Repository;
use App\Provider\DatabaseConnection;
use App\Entity\DynDNS;
use Monolog\Logger;
use PDO;
use PDOException;
/**
*
*/
class DynDNSRepository
{
public function __construct(
private readonly DatabaseConnection $databaseConnection,
private readonly Logger $logger)
{
$this->logger->debug(message: "DynDNSRepository::__construct()");
}
/**
* @param \App\Entity\DynDNS $dynDNS
*
* @return int
*/
public function delete(DynDNS $dynDNS): int
{
$dynDNSName = $dynDNS->getName();
$this->logger->debug(message: "delete($dynDNSName)");
$sql = "
DELETE FROM " . DatabaseConnection::TABLE_DYNDNS . "
WHERE id = :id";
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$id = $dynDNS->getId();
$statement->bindParam(param: 'id', var: $id);
$statement->execute();
return $statement->rowCount();
} catch (PDOException $e) {
exit($e->getMessage());
}
}
/**
* @return array
*/
public function findAll(): array
{
$this->logger->debug(message: "findAll()");
$dyndns = [];
$sql = "
SELECT id, name, a, aaaa
FROM " . DatabaseConnection::TABLE_DYNDNS . "
ORDER BY name";
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->execute();
while ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
$dyndns = new DynDNS(name: $result['name'], a: $result['a'], aaaa: $result['aaaa'], id: $result['id']);
$dyndns[] = $dyndns;
}
return $dyndns;
} catch (PDOException $e) {
exit($e->getMessage());
}
}
/**
* @param String $name
*
* @return \App\Entity\Domain|bool
*/
public function findByName(string $name): DynDNS|bool
{
$this->logger->debug(message: "findByName($name)");
$sql = "
SELECT id, name, a, aaaa
FROM " . DatabaseConnection::TABLE_DYNDNS . "
WHERE name = :name";
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: ':name', var: $name);
$statement->execute();
if ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
return new DynDNS(name: $result['name'], a: $result['a'], aaaa: $result['aaaa'], id: $result['id']);
} else {
return false;
}
} catch (PDOException $e) {
exit($e->getMessage());
}
}
/**
* @param String $field
*
* @return int
*/
public function getLongestEntry(string $field): int
{
$sql = "
SELECT MAX(LENGTH(" . $field . ")) as length FROM " . DatabaseConnection::TABLE_DYNDNS;
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->execute();
$result = $statement->fetch();
return $result['length'];
} catch (PDOException $e) {
exit($e->getMessage());
}
}
/**
* @param \App\Entity\DynDNS $dynDNS
*
* @return string|false
*/
public function insert(DynDNS $dynDNS): bool|string
{
$dynDNSName = $dynDNS->getName();
$this->logger->debug(message: "insert($dynDNSName)");
$sql = "
INSERT INTO " . DatabaseConnection::TABLE_DYNDNS . " (name, a, aaaa)
VALUES (:name, :a, :aaaa)";
try {
$a = $dynDNS->getA();
$aaaa = $dynDNS->getAaaa();
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: ':name', var: $dynDNSName);
$statement->bindParam(param: ':a', var: $a);
$statement->bindParam(param: ':aaaa', var: $aaaa);
$statement->execute();
return $this->databaseConnection->getConnection()->lastInsertId();
} catch (PDOException $e) {
exit($e->getMessage());
}
}
/**
* @param \App\Entity\DynDNS $dynDNS
*
* @return false|int
*/
public function update(DynDNS $dynDNS): bool|int
{
$dynDNSnName = $dynDNS->getName();
$this->logger->debug(message: "update($dynDNSnName)");
$id = $dynDNS->getId();
$current = $this->findByID(id: $id);
if (empty($dynDNSnName)) {
$name = $current->getName();
} else {
$name = $dynDNSnName;
}
if (empty($dynDNS->getA())) {
$a = $current->getA();
} else {
$a = $dynDNS->getA();
}
if (empty($dynDNS->getAaaa())) {
$aaaa = $current->getAaaa();
} else {
$aaaa = $dynDNS->getAaaa();
}
$sql = "
UPDATE " . DatabaseConnection::TABLE_DYNDNS . " SET
name = :name,
a = :a,
aaaa = :aaaa
WHERE id = :id";
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: 'id', var: $id);
$statement->bindParam(param: 'name', var: $name);
$statement->bindParam(param: 'a', var: $a);
$statement->bindParam(param: 'aaaa', var: $aaaa);
$statement->execute();
return $statement->rowCount();
} catch (PDOException $e) {
echo $e->getMessage();
return false;
}
}
/**
* @param int $id
*
* @return bool|\App\Entity\Domain
*/
public function findByID(int $id): bool|DynDNS
{
$this->logger->debug(message: "findById($id)");
$sql = "
SELECT id, name, a, aaaa
FROM . " . DatabaseConnection::TABLE_DYNDNS . "
WHERE id = :id";
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: ':id', var: $id);
$statement->execute();
if ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
return new DynDNS(name: $result['name'], a: $result['a'], aaaa: $result['aaaa'], id: $result['id']);
} else {
return false;
}
} catch (PDOException $e) {
exit($e->getMessage());
}
}
}

View File

@ -2,228 +2,275 @@
namespace App\Repository;
use App\Controller\DatabaseConnection;
use App\Provider\DatabaseConnection;
use App\Entity\Nameserver;
use PDO;
use PDOException;
use SodiumException;
/**
*
*/
class NameserverRepository
{
public function __construct(private DatabaseConnection $databaseConnection)
{
}
/**
* @return array
*/
public function findAll(): array
{
$nameservers = [];
$sql = "
SELECT id, name, a, aaaa, apikey
public function __construct(private readonly DatabaseConnection $databaseConnection)
{
// no body
}
/**
* @return array|null
*/
public function findAll(): ?array
{
$nameservers = [];
$sql = "
SELECT id, name, a, aaaa, apikey, apikey_prefix, self
FROM " . DatabaseConnection::TABLE_NAMESERVERS . "
ORDER BY name";
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->execute();
while ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
$nameserver = new Nameserver(name: $result['name'], id: $result['id'], a: $result['a'], aaaa: $result['aaaa'], apikey: $result['apikey']);
$nameservers[] = $nameserver;
}
return $nameservers;
} catch (PDOException $e) {
exit($e->getMessage());
}
}
/**
* @param int $id
*
* @return \App\Entity\Nameserver
*/
public function findByID(int $id): Nameserver
{
$sql = "
SELECT id, name, a, aaaa, apikey
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->execute();
while ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
$nameserver = new Nameserver(name: $result['name'], id: $result['id'], a: $result['a'], aaaa: $result['aaaa'], apikey: $result['apikey'], apikeyPrefix: $result['apikey_prefix'], self: $result['self']);
$nameservers[] = $nameserver;
}
return $nameservers;
} catch (PDOException $e) {
exit($e->getMessage());
}
}
/**
* @return Nameserver|null
*/
public function findFirst(): ?Nameserver
{
$sql = "
SELECT id, name, a, aaaa, apikey, apikey_prefix, self
FROM " . DatabaseConnection::TABLE_NAMESERVERS . "
ORDER BY name";
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->execute();
$result = $statement->fetch(mode: PDO::FETCH_ASSOC);
return new Nameserver(name: $result['name'], id: $result['id'], a: $result['a'], aaaa: $result['aaaa'], apikey: $result['apikey'], apikeyPrefix: $result['apikey_prefix'], self: $result['self']);
} catch (PDOException $e) {
exit($e->getMessage());
}
}
/**
* @param int $id
*
* @return null|Nameserver
*/
public function findByID(int $id): ?Nameserver
{
$sql = "
SELECT id, name, a, aaaa, apikey, apikey_prefix, self
FROM . " . DatabaseConnection::TABLE_NAMESERVERS . "
WHERE id = :id";
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: ':id', var: $id);
$statement->execute();
$result = $statement->fetch(mode: PDO::FETCH_ASSOC);
return new Nameserver(name: $result['name'], a: $result['a'], aaaa: $result['aaaa'], apikey: $result['apikey']);
} catch (PDOException $e) {
exit($e->getMessage());
}
}
/**
* @param String $name
*
* @return \App\Entity\Nameserver|bool
*/
public function findByName(string $name): Nameserver|bool
{
$sql = "
SELECT id, name, a, aaaa, apikey
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: ':id', var: $id);
$statement->execute();
if ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
return new Nameserver(name: $result['name'], a: $result['a'], aaaa: $result['aaaa'], apikey: $result['apikey'], apikeyPrefix: $result['apikey_prefix'], self: $result['self']);
} else {
return null;
}
} catch (PDOException $e) {
exit($e->getMessage());
}
}
/**
* @param String $name
*
* @return Nameserver|null
*/
public function findByName(string $name): ?Nameserver
{
$sql = "
SELECT id, name, a, aaaa, apikey, apikey_prefix, self
FROM " . DatabaseConnection::TABLE_NAMESERVERS . "
WHERE name = :name";
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: ':name', var: $name);
$statement->execute();
if ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
return new Nameserver(name: $result['name'], a: $result['a'], aaaa: $result['aaaa']);
} else {
return false;
}
} catch (PDOException $e) {
exit($e->getMessage());
}
}
/**
* @param \App\Entity\Nameserver $nameserver
*
* @return string|false
*/
public function insert(Nameserver $nameserver): bool|string
{
$sql = "
INSERT INTO " . DatabaseConnection::TABLE_NAMESERVERS . " (name, a, aaaa, apikey)
VALUES (:name, :a, :aaaa, :apikey)";
try {
$name = $nameserver->getName();
$a = $nameserver->getA();
$aaaa = $nameserver->getAaaa();
$apikey = $nameserver->getApikey();
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: ':name', var: $name);
$statement->bindParam(param: ':a', var: $a);
$statement->bindParam(param: ':aaaa', var: $aaaa);
$statement->bindParam(param: ':apikey', var: $apikey);
$statement->execute();
return $this->databaseConnection->getConnection()->lastInsertId();
} catch (PDOException $e) {
exit($e->getMessage());
}
}
/**
* @param Int $id
* @param String $name
* @param String $a
* @param String $aaaa
* @param String $apikey
*
* @return false|int
*/
public function update(int $id, string $name, string $a, string $aaaa, string $apikey): bool|int
{
$current = $this->findByID(id: $id);
/* doesn't work
$statement = "
INSERT INTO domains(id, name, a, aaaa)
VALUES(:id, :name, :a, :aaaa)
ON DUPLICATE KEY UPDATE
name=COALESCE(VALUES(name), :name),
a=COALESCE(:a, a),
aaaa=COALESCE(:aaaa, aaaa)";
*/
if (empty($name)) {
$name = $current->getName();
}
if (empty($a)) {
$a = $current->getA();
}
if (empty($aaaa)) {
$aaaa = $current->getAaaa();
}
if (empty($apikey)) {
$apikey = $current->getApikey();
}
$sql = "
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: ':name', var: $name);
$statement->execute();
if ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
return new Nameserver(name: $result['name'], a: $result['a'], aaaa: $result['aaaa'], apikey: $result['apikey'], apikeyPrefix: $result['apikey_prefix'], self: $result['self']);
} else {
return null;
}
} catch (PDOException $e) {
exit($e->getMessage());
}
}
/**
* @param Nameserver $nameserver
*
* @return int|null
*/
public function insert(Nameserver $nameserver): ?int
{
$name = $nameserver->getName();
$a = $nameserver->getA();
$aaaa = $nameserver->getAaaa();
$apikey = $nameserver->getApikey();
$apikeyPrefix = $nameserver->getApikeyPrefix();
$self = $nameserver->getSelf();
if ($self === '') {
$selfValue = 'no';
} else {
$selfValue = $self;
}
$sql = "
INSERT INTO " . DatabaseConnection::TABLE_NAMESERVERS . " (name, a, aaaa, apikey, apikey_prefix, self)
VALUES (:name, :a, :aaaa, :apikey, :apikey_prefix, :self)";
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: ':name', var: $name);
$statement->bindParam(param: ':a', var: $a);
$statement->bindParam(param: ':aaaa', var: $aaaa);
$statement->bindParam(param: ':apikey', var: $apikey);
$statement->bindParam(param: ':apikey_prefix', var: $apikeyPrefix);
$statement->bindParam(param: ':self', var: $selfValue);
$statement->execute();
return intval(value: $this->databaseConnection->getConnection()->lastInsertId());
} catch (PDOException $e) {
exit($e->getMessage() . PHP_EOL);
}
}
/**
* @param Nameserver $nameserver
* @return false|int
*/
public function update(Nameserver $nameserver): bool|int
{
$id = $nameserver->getId();
$name = $nameserver->getName();
$a = $nameserver->getA();
$aaaa = $nameserver->getAaaa();
$apikey = $nameserver->getApikey();
$apikeyPrefix = $nameserver->getApikeyPrefix();
$passphrase = $nameserver->getPassphrase();
$self =$nameserver->getSelf();
$current = $this->findByID(id: $id);
if (empty($name)) {
$name = $current->getName();
}
if (empty($a)) {
$a = $current->getA();
}
if (empty($aaaa)) {
$aaaa = $current->getAaaa();
}
if (empty($passphrase)) {
$apikey = $current->getApikey();
$apikeyPrefix = $current->getApikeyPrefix();
}
if (empty($self)) {
$self = $current->getSelf();
}
$sql = "
UPDATE " . DatabaseConnection::TABLE_NAMESERVERS . " SET
name = :name,
a = :a,
aaaa = :aaaa,
apikey = :apikey
apikey = :apikey,
apikey_prefix = :apikey_prefix,
self = :self
WHERE id = :id";
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: 'id', var: $id);
$statement->bindParam(param: 'name', var: $name);
$statement->bindParam(param: 'a', var: $a);
$statement->bindParam(param: 'aaaa', var: $aaaa);
$statement->bindParam(param: 'apikey', var: $apikey);
$statement->execute();
return $statement->rowCount();
} catch (PDOException $e) {
print($e->getMessage());
return false;
}
}
/**
* @param $id
*
* @return int
*/
public function delete($id): int
{
$sql = "
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: 'id', var: $id);
$statement->bindParam(param: 'name', var: $name);
$statement->bindParam(param: 'a', var: $a);
$statement->bindParam(param: 'aaaa', var: $aaaa);
$statement->bindParam(param: 'apikey', var: $apikey);
$statement->bindParam(param: 'apikey_prefix', var: $apikeyPrefix);
$statement->bindParam(param: 'self', var: $self);
$statement->execute();
try {
sodium_memzero(string: $apikey);
} catch(SodiumException $e) {
exit($e->getMessage() . PHP_EOL);
}
return intval(value: $statement->rowCount());
} catch (PDOException $e) {
echo $e->getMessage();
return false;
}
}
/**
* @param $id
*
* @return int|null
*/
public function delete($id): ?int
{
$sql = "
DELETE FROM " . DatabaseConnection::TABLE_NAMESERVERS . "
WHERE id = :id";
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: 'id', var: $id);
$statement->execute();
return $statement->rowCount();
} catch (PDOException $e) {
exit($e->getMessage());
}
}
/**
* @param String $field
*
* @return int
*/
public function getLongestEntry(string $field): int
{
$sql = "
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: 'id', var: $id);
$statement->execute();
return $statement->rowCount();
} catch (PDOException $e) {
exit($e->getMessage());
}
}
/**
* @param String $field
*
* @return int
*/
public function getLongestEntry(string $field): int
{
$sql = "
SELECT MAX(LENGTH(" . $field . ")) as length FROM " . DatabaseConnection::TABLE_NAMESERVERS;
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->execute();
$result = $statement->fetch();
return $result['length'];
} catch (PDOException $e) {
exit($e->getMessage());
}
}
}
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->execute();
$result = $statement->fetch();
return $result['length'];
} catch (PDOException $e) {
exit($e->getMessage());
}
}
}

View File

@ -2,7 +2,7 @@
namespace App\Repository;
use App\Controller\DatabaseConnection;
use App\Provider\DatabaseConnection;
use App\Entity\Panel;
use PDO;
use PDOException;
@ -12,206 +12,262 @@ use PDOException;
*/
class PanelRepository
{
public function __construct(private DatabaseConnection $databaseConnection)
{}
/**
* @return array
*/
public function findAll(): array
{
$panels = [];
$sql = "
SELECT id, name, a, aaaa, apikey
public function __construct(private readonly DatabaseConnection $databaseConnection)
{
// no body
}
/**
* @return array|null
*/
public function findSelf(): ?array
{
$sql = "
SELECT id, name, a, aaaa, apikey, apikey_prefix, self
FROM " . DatabaseConnection::TABLE_PANELS . "
WHERE self = 1";
$panels = [];
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->execute();
while ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
$panel = new Panel(name: $result['name'], id: $result['id'], a: $result['a'], aaaa: $result['aaaa'], apikey: $result['apikey'], apikeyPrefix: $result['apikey_prefix'], self: $result['self']);
$panels[] = $panel;
}
return $panels;
}
public function findAll(): ?array
{
$panels = [];
$sql = "
SELECT id, name, a, aaaa, apikey, apikey_prefix, self
FROM " . DatabaseConnection::TABLE_PANELS . "
ORDER BY name";
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->execute();
while ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
$panel = new Panel(name: $result['name'], id: $result['id'], a: $result['a'], aaaa: $result['aaaa'], apikey: $result['apikey']);
$panels[] = $panel;
}
return $panels;
} catch (PDOException $e) {
exit($e->getMessage());
}
}
/**
* @param int $id
*
* @return \App\Entity\Panel
*/
public function findByID(int $id): Panel
{
$sql = "
SELECT id, name, a, aaaa, apikey
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->execute();
while ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
$panel = new Panel(name: $result['name'], id: $result['id'], a: $result['a'], aaaa: $result['aaaa'], apikey: $result['apikey'], apikeyPrefix: $result['apikey_prefix'], self: $result['self']);
$panels[] = $panel;
}
return $panels;
} catch (PDOException $e) {
exit($e->getMessage());
}
}
/**
* @param int $id
*
* @return null|Panel
*/
public function findByID(int $id): ?Panel
{
$sql = "
SELECT id, name, a, aaaa, apikey, apikey_prefix, self
FROM . " . DatabaseConnection::TABLE_PANELS . "
WHERE id = :id";
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: ':id', var: $id);
$statement->execute();
$result = $statement->fetch(mode: PDO::FETCH_ASSOC);
return new Panel(name: $result['name'], a: $result['a'], aaaa: $result['aaaa'], apikey: $result['apikey']);
} catch (PDOException $e) {
exit($e->getMessage());
}
}
/**
* @param String $name
*
* @return \App\Entity\Panel|bool
*/
public function findByName(string $name): Panel|bool
{
$sql = "
SELECT id, name, a, aaaa, apikey
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: ':id', var: $id);
$statement->execute();
if ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
return new Panel(name: $result['name'], a: $result['a'], aaaa: $result['aaaa'], apikey: $result['apikey'], apikeyPrefix: $result['apikey_prefix'], self: $result['self']);
} else {
return null;
}
} catch (PDOException $e) {
exit($e->getMessage());
}
}
/**
* @param String $name
*
* @return Panel|null
*/
public function findByName(string $name): ?Panel
{
$sql = "
SELECT id, name, a, aaaa, apikey, apikey_prefix, self
FROM " . DatabaseConnection::TABLE_PANELS . "
WHERE name = :name";
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: ':name', var: $name);
$statement->execute();
if ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
return new Panel(name: $result['name'], a: $result['a'], aaaa: $result['aaaa'], apikey: $result['apikey']);
} else {
return false;
}
} catch (PDOException $e) {
exit($e->getMessage());
}
}
/**
* @param String $name
* @param String $a
* @param String $aaaa
* @param String $apikey
*
* @return string|false
*/
public function insert(string $name, string $a, string $aaaa, String $apikey): bool|string
{
$sql = "
INSERT INTO " . DatabaseConnection::TABLE_PANELS . " (name, a, aaaa, apikey)
VALUES (:name, :a, :aaaa, :apikey)";
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: ':name', var: $name);
$statement->bindParam(param: ':a', var: $a);
$statement->bindParam(param: ':aaaa', var: $aaaa);
$statement->bindParam(param: ':apikey', var: $apikey);
$statement->execute();
return $this->databaseConnection->getConnection()->lastInsertId();
} catch (PDOException $e) {
exit($e->getMessage());
}
}
/**
* @param Int $id
* @param String $name
* @param String $a
* @param String $aaaa
* @param String $apikey
*
* @return false|int
*/
public function update(int $id, string $name, string $a, string $aaaa, String $apikey): bool|int
{
$current = $this->findByID(id: $id);
if (empty($name)) {
$name = $current->getName();
}
if (empty($a)) {
$a = $current->getA();
}
if (empty($aaaa)) {
$aaaa = $current->getAaaa();
}
if (empty($apikey)) {
$apikey = $current->getApikey();
}
$sql = "
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: ':name', var: $name);
$statement->execute();
if ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
return new Panel(name: $result['name'], a: $result['a'], aaaa: $result['aaaa'], apikey: $result['apikey'], apikeyPrefix: $result['apikey_prefix'], self: $result['self']);
} else {
return null;
}
} catch (PDOException $e) {
exit($e->getMessage());
}
}
/**
* @param Panel $panel
* @return int|null
*/
public function insert(Panel $panel): ?int
{
$name = $panel->getName();
$a = $panel->getA();
$aaaa = $panel->getAaaa();
$apikey = $panel->getApikey();
$apikeyPrefix = $panel->getApikeyPrefix();
$self = $panel->getSelf();
$sql = "
INSERT INTO " . DatabaseConnection::TABLE_PANELS . " (name, a, aaaa, apikey, apikey_prefix, self)
VALUES (:name, :a, :aaaa, :apikey, :prefix, :self)";
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: ':name', var: $name);
$statement->bindParam(param: ':a', var: $a);
$statement->bindParam(param: ':aaaa', var: $aaaa);
$statement->bindParam(param: ':apikey', var: $apikey);
$statement->bindParam(param: ':prefix', var: $apikeyPrefix);
$statement->bindParam(param: ':self', var: $self);
$statement->execute();
return intval(value: $this->databaseConnection->getConnection()->lastInsertId());
} catch (PDOException $e) {
exit($e->getMessage());
}
}
/**
* @param Panel $panel
* @return int|null
*/
public function update(Panel $panel): ?int
{
$id = $panel->getId();
$name = $panel->getName();
$a = $panel->getA();
$aaaa = $panel->getAaaa();
$apikey = $panel->getApikey();
$apikeyPrefix = $panel->getApikeyPrefix();
$passphrase = $panel->getPassphrase();
$self = $panel->getSelf();
echo 'self: ' . $self;
$current = $this->findByID(id: $id);
if (empty($name)) {
$name = $current->getName();
}
if (empty($a)) {
$a = $current->getA();
}
if (empty($aaaa)) {
$aaaa = $current->getAaaa();
}
if (empty($passphrase)) {
$apikey = $current->getApikey();
$apikeyPrefix = $current->getApikeyPrefix();
}
if (empty($self)) {
$self = $current->getSelf();
}
$sql = "
UPDATE " . DatabaseConnection::TABLE_PANELS . " SET
name = :name,
a = :a,
aaaa = :aaaa,
apikey = :apikey
apikey = :apikey,
apikey_prefix = :apikey_prefix,
self = :self
WHERE id = :id";
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: 'id', var: $id);
$statement->bindParam(param: 'name', var: $name);
$statement->bindParam(param: 'a', var: $a);
$statement->bindParam(param: 'aaaa', var: $aaaa);
$statement->bindParam(param: 'apikey', var: $apikey);
$statement->execute();
return $statement->rowCount();
} catch (PDOException $e) {
print($e->getMessage());
return false;
}
}
/**
* @param $id
*
* @return int
*/
public function delete($id): int
{
$sql = "
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: 'id', var: $id);
$statement->bindParam(param: 'name', var: $name);
$statement->bindParam(param: 'a', var: $a);
$statement->bindParam(param: 'aaaa', var: $aaaa);
$statement->bindParam(param: 'apikey', var: $apikey);
$statement->bindParam(param: 'apikey_prefix', var: $apikeyPrefix);
$statement->bindParam(param: 'self', var: $self);
$statement->execute();
return intval(value: $statement->rowCount());
} catch (PDOException $e) {
echo $e->getMessage();
return null;
}
}
/**
* @param $id
*
* @return int|null
*/
public function delete($id): ?int
{
$sql = "
DELETE FROM " . DatabaseConnection::TABLE_PANELS . "
WHERE id = :id";
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: 'id', var: $id);
$statement->execute();
return $statement->rowCount();
} catch (PDOException $e) {
exit($e->getMessage());
}
}
/**
* @param String $field
*
* @return int
*/
public function getLongestEntry(String $field): int
{
$sql = "
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: 'id', var: $id);
$statement->execute();
return intval(value: $statement->rowCount());
} catch (PDOException $e) {
exit($e->getMessage());
}
}
/**
* @param String $field
*
* @return int|null
*/
public function getLongestEntry(string $field): ?int
{
$sql = "
SELECT MAX(LENGTH(" . $field . ")) as length FROM " . DatabaseConnection::TABLE_PANELS;
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->execute();
$result = $statement->fetch();
return $result['length'];
} catch (PDOException $e) {
exit($e->getMessage());
}
}
}
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->execute();
$result = $statement->fetch();
return $result['length'];
} catch (PDOException $e) {
exit($e->getMessage());
}
}
public function getSelf(): ?Panel
{
$panels = $this->findAll();
foreach ($panels as $panel) {
if ($panel->getSelf() === 'yes') {
return $panel;
}
}
return null;
}
}

View File

@ -0,0 +1,69 @@
<?php declare(strict_types=1);
namespace App\Repository;
error_reporting(error_level: E_ALL);
use App\Provider\DatabaseConnection;
use App\Controller\EncryptionController;
use PDO;
use PDOException;
/**
*
*/
readonly class SettingsRepository
{
public function __construct(private DatabaseConnection $databaseConnection, EncryptionController $encryptionController)
{}
public function findByName(string $name): string|bool
{
$sql = "
SELECT value
FROM " . DatabaseConnection::TABLE_SETTINGS . "
WHERE name = :name;
";
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: ':name', var: $name);
$statement->execute();
if ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
return $result['value'];
} else {
return false;
}
} catch (PDOException $e) {
exit($e->getMessage());
}
}
public function set(string $name, string $value): int
{
$currentSetting = $this->findByName($name);
if ($currentSetting !== false) {
$sql = "
UPDATE " . DatabaseConnection::TABLE_SETTINGS . "
SET value = :value
WHERE name = :name
";
} else {
$sql = "
INSERT INTO " . DatabaseConnection::TABLE_SETTINGS . " (id, name, value)
VALUES (UUID(), :name, :value)
";
}
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: ':name', var: $name);
$statement->bindParam(param: ':value', var: $value);
$statement->execute();
return intval(value: $this->databaseConnection->getConnection()->lastInsertId());
} catch (PDOException $e) {
exit($e->getMessage());
}
}
}

136
src/Service/ApiClient.php Normal file
View File

@ -0,0 +1,136 @@
<?php declare(strict_types=1);
namespace App\Service;
use UnhandledMatchError;
error_reporting(error_level: E_ALL);
class ApiClient
{
function sendCommand(string $requestType, string $serverName, int $versionIP, string $apiKey, string $command, string $serverType, array $body = []): array
{
$error = false;
$curl = curl_init();
try {
match ($serverType) {
'panel' => curl_setopt(handle: $curl, option: CURLOPT_URL, value: "https://$serverName/api/v2/" . $command),
'nameserver' => curl_setopt(handle: $curl, option: CURLOPT_URL, value: "https://$serverName/api/" . $command)
};
} catch (UnhandledMatchError) {
exit('Unhandled match: ' . $serverType .' in ' . __FILE__ . ' on line ' . __LINE__ . PHP_EOL);
}
curl_setopt(handle: $curl, option: CURLOPT_RETURNTRANSFER, value: 1);
curl_setopt(handle: $curl, option: CURLOPT_TIMEOUT_MS, value: 19999);
curl_setopt(handle: $curl, option: CURLOPT_HTTP_VERSION, value: CURL_HTTP_VERSION_2TLS);
if ($versionIP == 4) {
curl_setopt(handle: $curl, option: CURLOPT_IPRESOLVE, value: CURL_IPRESOLVE_V4);
} else {
curl_setopt(handle: $curl, option: CURLOPT_IPRESOLVE, value: CURL_IPRESOLVE_V6);
}
curl_setopt(handle: $curl, option: CURLOPT_HTTPHEADER, value: ["X-API-Key:$apiKey"]);
if ($requestType == "POST") {
curl_setopt(handle: $curl, option: CURLOPT_POST, value: true);
curl_setopt(handle: $curl, option: CURLOPT_POSTFIELDS, value: $body);
}
if ($requestType == "PUT") {
curl_setopt(handle: $curl, option: CURLOPT_CUSTOMREQUEST, value: 'PUT');
curl_setopt(handle: $curl, option: CURLOPT_POSTFIELDS, value: json_encode(value: $body));
}
curl_setopt(handle: $curl, option: CURLOPT_CUSTOMREQUEST, value: $requestType);
if ($resultJSON = curl_exec(handle: $curl)) {
$httpResponse = curl_getinfo(handle: $curl)['http_code'];
switch ($httpResponse) {
case 200:
$apiResult = json_decode(json: $resultJSON);
if ($command == "ping") {
if ($apiResult->response == "pong") {
$result = $apiResult->response;
} else {
$result = $apiResult;
}
} else {
$result = $resultJSON;
}
break;
case 400:
$result = $resultJSON;
$error = true;
break;
case 401:
$result = 'Missing or wrong API Key';
$error = true;
break;
case 404:
$result = '404 Not Found';
$error = true;
break;
case 500:
$result = 'server error';
$error = true;
break;
default:
$error = true;
$result = 'Unhandled error: ' . $httpResponse;
}
} else {
$error = true;
$result = curl_error(handle: $curl);
}
$info = curl_getinfo(handle: $curl);
$responseTime = $info['total_time'];
curl_close(handle: $curl);
return [
'responseTime' => $responseTime,
'error' => $error,
'data' => $result,
'header' => $httpResponse ?? ''
];
}
function fileGetContents(string $url, int $versionIP): ?array
{
$curl = curl_init(url: $url);
$options = array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_ENCODING => '',
CURLOPT_AUTOREFERER => true,
CURLOPT_CONNECTTIMEOUT => 120,
CURLOPT_TIMEOUT => 120,
CURLOPT_MAXREDIRS => 10,
);
if ($versionIP == 4) {
curl_setopt(handle: $curl, option: CURLOPT_IPRESOLVE, value: CURL_IPRESOLVE_V4);
} else {
curl_setopt(handle: $curl, option: CURLOPT_IPRESOLVE, value: CURL_IPRESOLVE_V6);
}
curl_setopt_array(handle: $curl, options: $options);
$content = curl_exec(handle: $curl);
$error = curl_errno(handle: $curl);
$errorMessage = curl_error(handle: $curl);
$header = curl_getinfo(handle: $curl);
curl_close(handle: $curl);
$header['error'] = $error;
$header['errorMessage'] = $errorMessage;
$header['content'] = $content;
return $header;
}
}

94
src/Service/BindAPI.php Executable file
View File

@ -0,0 +1,94 @@
<?php declare(strict_types=1);
namespace App\Service;
error_reporting(error_level: E_ALL);
use App\Controller\ConfigController;
use App\Controller\CLIController;
use App\Controller\DomainController;
use App\Controller\RequestController;
use App\Repository\DomainRepository;
use App\Repository\DynDNSRepository;
use App\Service\ApiClient;
use DI\Container;
use DI\ContainerBuilder;
use DI\DependencyException;
use DI\NotFoundException;
use Exception;
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\StreamHandler;
use Monolog\Level;
use Monolog\Logger;
use function DI\autowire;
class BindAPI
{
private Logger $logger;
private Container $container;
public function __construct(bool $quiet)
{
// init the logger
$dateFormat = "Y:m:d H:i:s";
$output = "%datetime% %channel%.%level_name% %message%\n"; // %context% %extra%
$formatter = new LineFormatter(format: $output, dateFormat: $dateFormat);
$debug = (new ConfigController(quiet: $quiet))->getConfig(configKey: 'debug');
if ($debug) {
$stream = new StreamHandler(stream: dirname(path: __DIR__, levels: 2) . '/var/log/bindAPI.debug', level: Level::Debug);
} else {
$stream = new StreamHandler(stream: dirname(path: __DIR__, levels: 2) . '/var/log/bindAPI.info', level: Level::Info);
}
$stream->setFormatter(formatter: $formatter);
$this->logger = new Logger(name: 'bindAPI');
$this->logger->pushHandler(handler: $stream);
$this->logger->debug(message: 'bindAPI started');
$containerBuilder = new ContainerBuilder();
$containerBuilder->addDefinitions([
ApiClient::class => autowire(),
ConfigController::class => autowire()
->constructorParameter(parameter: 'quiet', value: $quiet),
CLIController::class => autowire()
->constructorParameter(parameter: 'logger', value: $this->logger)
->constructorParameter(parameter: 'quiet', value: $quiet),
DomainController::class => autowire()
->constructorParameter(parameter: 'logger', value: $this->logger)
->constructorParameter(parameter: 'quiet', value: $quiet),
DomainRepository::class => autowire()
->constructorParameter(parameter: 'logger', value: $this->logger),
DynDnsRepository::class => autowire()
->constructorParameter(parameter: 'logger', value: $this->logger),
RequestController::class => autowire()
->constructorParameter(parameter: 'logger', value: $this->logger)
]);
$this->container = $containerBuilder->build();
}
/**
* @throws DependencyException
* @throws NotFoundException
*/
public function runCommand(array $arguments): void
{
$this->logger->debug(message: 'runCommand()');
$cliController = $this->container->get(name: CLIController::class);
$cliController->runCommand(arguments: $arguments);
}
/**
* @throws DependencyException
* @throws NotFoundException
*/
public function handleRequest(string $requestMethod, array $uri): void
{
$this->logger->debug(message: 'handleRequest()');
$requestController = $this->container->get(name: RequestController::class);
$requestController->handleRequest(requestMethod: $requestMethod, uri: $uri);
}
}

120
src/Util/Console.php Normal file
View File

@ -0,0 +1,120 @@
<?php
use App\Service\BindAPI;
error_reporting(error_level: E_ALL & ~E_DEPRECATED);
if (!is_file(filename: dirname(path: __DIR__, levels: 2) . '/vendor/autoload.php')) {
echo 'Required runtime components are missing. Try running "' . COLOR_YELLOW . 'composer install' . COLOR_DEFAULT . '".' . PHP_EOL;
exit(1);
}
require dirname(path: __DIR__, levels: 2) . '/vendor/autoload.php';
$shortOpts = 'v::'; // version
$shortOpts .= 'q::'; // quiet
$shortOpts .= "h::"; // help
$longOpts = [
'version::',
'quiet::',
'help::'
];
$options = getopt(short_options: $shortOpts, long_options: $longOpts, rest_index: $restIndex);
$arguments = array_slice(array: $argv, offset: $restIndex);
if (array_key_exists(key: 'v', array: $options) || array_key_exists(key: 'version', array: $options)) {
$arguments = 'showVersion';
$composerJson = json_decode(json: file_get_contents(filename: dirname(path: __DIR__, levels: 2) . '/composer.json'));
$name = $composerJson->name;
$description = $composerJson->description;
$version = $composerJson->version;
$buildNumber = $composerJson->build_number;
$authors = $composerJson->authors;
// currently only one author, so just handle only first entry
$authorName = $authors[0]->name;
$authorEmail = $authors[0]->email;
echo "Name: $name" . PHP_EOL;
echo "Description: $description" . PHP_EOL;
echo "Version: $version" . PHP_EOL;
echo "Build Number: $buildNumber" . PHP_EOL;
echo "Author: $authorName ($authorEmail)" . PHP_EOL;
exit(0);
}
if (array_key_exists(key: 'h', array: $options) || array_key_exists(key: 'help', array: $options)) {
$arguments = "showUsage";
}
if (array_key_exists(key: 'q', array: $options) || array_key_exists(key: 'quiet', array: $options)) {
$quiet = true;
} else {
$quiet = false;
}
try {
$app = new BindAPI(quiet: $quiet);
} catch (Exception $e) {
echo 'Could not initialize the application: ' . $e->getMessage() . PHP_EOL;
exit(1);
}
try {
$app->runCommand(arguments: $arguments);
} catch (Exception $e) {
$exceptionMessage = $e->getMessage();
preg_match(pattern: '/\[1045]/', subject: $exceptionMessage, matches: $matches);
if (!empty($matches)) {
echo 'Access was denied for a user when trying to access the database.' . PHP_EOL;
} else {
echo 'The error message could not be parsed.';
echo $exceptionMessage . PHP_EOL;
exit(1);
}
}
function confirm(string $message = 'Are you sure? ', array $options = ['y', 'n'], string $default = 'n'): bool
{
// first $options means true, any other false
echo $message, ' (';
$first = true;
foreach ($options as $option) {
// mark default
if ($option === $default) {
$option = strtoupper(string: $option);
}
if ($first) {
echo $option;
$first = false;
} else {
echo '/', $option;
}
}
echo '): ';
$handle = fopen(filename: "php://stdin", mode: 'r');
$line = trim(string: fgetc(stream: $handle));
fclose(stream: $handle);
if ($line == '') {
// enter
$line = $default;
}
if ($line == $options[0]) {
$result = true;
} else {
$result = false;
}
return $result;
}

13
src/Utilities/Colors.php Normal file
View File

@ -0,0 +1,13 @@
<?php
namespace App\Utilities;
class Colors
{
const RED = "\033[31m";
const GREEN = "\033[32m";
const YELLOW = "\033[33m";
const BLUE = "\033[34m";
const WHITE = "\033[37m";
const DEFAULT = "\033[39m";
}

View File

@ -1,42 +0,0 @@
<?php
namespace App\Controller;
use App\Repository\NameserverRepository;
use DI\Container;
use DI\ContainerBuilder;
use PHPUnit\Framework\TestCase;
use function DI\autowire;
/**
*
*/
class BindApiTestController extends TestCase
{
protected Container $container;
protected NameserverRepository $nameserverRepository;
/**
* @param int|string $dataName
*
* @throws \Exception
* @internal This method is not covered by the backward compatibility promise for PHPUnit
*/
public function __construct(?string $name = null, array $data = [], $dataName = '')
{
parent::__construct(name: $name, data: $data, dataName: $dataName);
// read config TODO use .env file instead?
$configFile = dirname(path: __DIR__) . "/config.json";
$configJSON = file_get_contents(filename: $configFile);
$config = json_decode(json: $configJSON, associative: true);
$containerBuilder = new ContainerBuilder();
$containerBuilder->addDefinitions([
DatabaseConnection::class => autowire()->constructorParameter(parameter: 'config', value: $config),
]);
$this->container = $containerBuilder->build();
$this->nameserverRepository = $this->container->get(name: NameserverRepository::class);
}
}

View File

@ -1,161 +0,0 @@
<?php
namespace App\Repository;
use App\Controller\DatabaseConnection;
use App\Controller\DomainController;
use App\Entity\Domain;
use DI\Container;
use DI\ContainerBuilder;
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use PHPUnit\Framework\TestCase;
use function DI\autowire;
/**
*
*/
class DomainRepositoryTest extends TestCase
{
private Container $container;
private DomainRepository $domainRepository;
private DomainController $domainController;
private string $localZoneFile;
private string $localZonesDir;
private string $namedConfLocalFile;
private Logger $log;
/**
* @param int|string $dataName
*
* @throws \Exception
* @internal This method is not covered by the backward compatibility promise for PHPUnit
*/
public function __construct(?string $name = null, array $data = [], $dataName = '')
{
parent::__construct(name: $name, data: $data, dataName: $dataName);
$dateFormat = "Y-m-d H:i:s";
$output = "%datetime% %channel%.%level_name% %message%\n"; // %context% %extra%
$formatter = new LineFormatter(format: $output, dateFormat: $dateFormat);
$stream = new StreamHandler(stream: dirname(path: __DIR__, levels: 3) . '/bindAPI.test.log');
$stream->setFormatter(formatter: $formatter);
$this->log = new Logger(name: 'bindAPI');
$this->log->pushHandler(handler: $stream);
$this->localZoneFile = '/etc/bind/local.zones';
$this->localZonesDir = '/etc/bind/zones/';
$this->namedConfLocalFile = '/etc/bind/named.conf.local';
//$this->zoneCachePath = '/var/cache/bind/';
// read config TODO use .env file instead?
$configFile = dirname(path: __DIR__, levels: 3) . "/config.json";
$configJSON = file_get_contents(filename: $configFile);
$config = json_decode(json: $configJSON, associative: true);
$containerBuilder = new ContainerBuilder();
$containerBuilder->addDefinitions([
DatabaseConnection::class => autowire()->constructorParameter(parameter: 'config', value: $config),
DomainController::class => autowire()
->constructorParameter(parameter: 'config', value: $config)
->constructorParameter(parameter: 'log', value: $this->log),
DomainRepository::class => autowire()
->constructorParameter(parameter: 'config', value: $config)
->constructorParameter(parameter: 'log', value: $this->log),
]);
$this->container = $containerBuilder->build();
$this->domainRepository = $this->container->get(name: DomainRepository::class);
$this->domainController = $this->container->get(name: DomainController::class);
}
public function setUp(): void
{
$this->log->info(message: 'Started DomainRepositoryTest');
}
public function tearDown(): void
{
$this->log->info(message: 'Finished DomainRepositoryTest');
}
/**
* @throws \DI\NotFoundException
* @throws \DI\DependencyException
*/
public function testInsert()
{
$domain = new Domain(name: 'inserttest.org', a: '1.2.3.4', aaaa: '1bad::babe');
$this->domainRepository->insert(domain: $domain);
$this->domainController->createZoneFile(domain: $domain);
// now get the persisted domain with id
$domainTest = $this->domainRepository->findByName(name: 'inserttest.org');
$this->assertIsNotBool(actual: $domainTest);
$this->assertEquals(expected: 'inserttest.org', actual: $domainTest->getName());
if ($namedConfLocal = file_get_contents(filename: $this->namedConfLocalFile)) {
$this->assertStringContainsString(needle: $this->localZoneFile, haystack: $namedConfLocal);
} else {
$this->fail(message: 'No permissions: ' . $this->namedConfLocalFile);
}
$this->assertNotFalse(condition: fileperms(filename: $this->localZoneFile));
$localZones = file_get_contents(filename: $this->localZoneFile);
$this->assertStringContainsString(needle: $domainTest->getName(), haystack: $localZones);
$zoneFile = $this->localZonesDir . $domain->getName();
$this->assertFileExists(filename: $zoneFile);
// clean up
$this->domainRepository->delete(domain: $domainTest);
}
/**
* @throws \DI\NotFoundException
* @throws \DI\DependencyException
*/
public function testDelete()
{
$domain = new Domain(name: 'inserttest.org', a: '1.2.3.4', aaaa: '1bad::babe');
$this->domainRepository->insert(domain: $domain);
$this->domainController->createZoneFile(domain: $domain);
$domainTest = $this->domainRepository->findByName(name: 'inserttest.org');
$this->assertIsNotBool(actual: $domainTest);
$this->assertEquals(expected: 'inserttest.org', actual: $domainTest->getName());
// domain is valid and created
// now delete and check for cleanup
$this->domainRepository->delete(domain: $domainTest);
$this->domainController->deleteZone(domain: $domainTest);
// check zone is removed
$this->assertNotFalse(condition: fileperms(filename: $this->localZoneFile));
$localZones = file_get_contents(filename: $this->localZoneFile);
$this->assertStringNotContainsString(needle: $domainTest->getName(), haystack: $localZones);
$zoneFile = $this->localZonesDir . $domain->getName();
$this->assertFileDoesNotExist(filename: $zoneFile);
}
}

View File

@ -1,61 +0,0 @@
<?php
namespace App\Repository;
use App\Controller\DatabaseConnection;
use App\Entity\Nameserver;
use DI\Container;
use DI\ContainerBuilder;
use PHPUnit\Framework\TestCase;
use function DI\autowire;
/**
*
*/
class NameserverRepositoryTest extends TestCase
{
private Container $container;
private NameserverRepository $nameserverRepository;
/**
* @param int|string $dataName
*
* @throws \Exception
* @internal This method is not covered by the backward compatibility promise for PHPUnit
*/
public function __construct(?string $name = null, array $data = [], $dataName = '')
{
parent::__construct(name: $name, data: $data, dataName: $dataName);
// read config TODO use .env file instead?
$configFile = dirname(path: __DIR__, levels: 3) . "/config.json";
$configJSON = file_get_contents(filename: $configFile);
$config = json_decode(json: $configJSON, associative: true);
$containerBuilder = new ContainerBuilder();
$containerBuilder->addDefinitions([
DatabaseConnection::class => autowire()->constructorParameter(parameter: 'config', value: $config),
]);
$this->container = $containerBuilder->build();
$this->nameserverRepository = $this->container->get(name: NameserverRepository::class);
}
/**
* @throws \DI\NotFoundException
* @throws \DI\DependencyException
*/
public function testInsert()
{
$nameserver = new Nameserver(name: 'inserttest.org', a: '1.2.3.4', aaaa: '1bad::babe');
$this->nameserverRepository->insert(nameserver: $nameserver);
$nameservertest = $this->nameserverRepository->findByName(name: 'inserttest.org');
$this->assertIsNotBool(actual: $nameserver);
$this->assertEquals(expected: 'inserttest.org', actual: $nameservertest->getName());
// clean up
$this->nameserverRepository->delete(id: $nameservertest->getId());
}
}

View File

@ -1,17 +0,0 @@
<?php
namespace App\Controller;
use PHPUnit\Framework\TestCase;
/**
*
*/
class DatabaseConnectionTest extends TestCase
{
public function testGetConnection()
{
}
}

View File

@ -0,0 +1,83 @@
<?php
namespace Unit\Controller;
use App\Controller\ConfigController;
use App\Controller\DatabaseConnection;
use App\Controller\DomainController;
use App\Repository\DomainRepository;
use App\Repository\NameserverRepository;
use DI\Container;
use DI\ContainerBuilder;
use Exception;
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\StreamHandler;
use Monolog\Level;
use Monolog\Logger;
use PHPUnit\Framework\TestCase;
use function DI\autowire;
/**
*
*/
class BindApiControllerTest extends TestCase
{
protected Container $container;
protected NameserverRepository $nameserverRepository;
protected DomainRepository $domainRepository;
protected DomainController $domainController;
protected Logger $logger;
/**
* @param int|string $dataName
*
* @throws Exception
* @internal This method is not covered by the backward compatibility promise for PHPUnit
*/
public function __construct(?string $name = null, array $data = [], $dataName = '')
{
parent::__construct(name: $name, data: $data, dataName: $dataName);
// init the logger
$dateFormat = "Y:m:d H:i:s";
$output = "%datetime% %channel%.%level_name% %message%\n"; // %context% %extra%
$formatter = new LineFormatter(format: $output, dateFormat: $dateFormat);
$debug = (new ConfigController)->getConfig(configKey: 'debug');
if ($debug) {
$stream = new StreamHandler(stream: dirname(path: __DIR__, levels: 3) . '/bindAPI.test.log', level: Level::Debug);
} else {
$stream = new StreamHandler(stream: dirname(path: __DIR__, levels: 3) . '/bindAPI.test.log', level: Level::Info);
}
$stream->setFormatter(formatter: $formatter);
$this->logger = new Logger(name: 'bindAPI');
$this->logger->pushHandler(handler: $stream);
$this->logger->debug(message: 'bindAPI started');
$containerBuilder = new ContainerBuilder();
$containerBuilder->addDefinitions([
//DatabaseConnection::class => autowire()->constructorParameter(parameter: 'config', value: $config),
DomainController::class => autowire()
->constructorParameter(parameter: 'logger', value: $this->logger),
DomainRepository::class => autowire()
->constructorParameter(parameter: 'logger', value: $this->logger),
]);
$this->container = $containerBuilder->build();
$this->nameserverRepository = $this->container->get(name: NameserverRepository::class);
$this->domainRepository = $this->container->get(name: DomainRepository::class);
$this->domainController = $this->container->get(name: DomainController::class);
}
public function testFoo(): void
{
self::assertEquals(expected: true, actual: true);
}
}

View File

@ -0,0 +1,42 @@
<?php
namespace Unit\Controller;
use App\Controller\ConfigController;
use App\Controller\DatabaseConnection;
use PDO;
use PDOException;
/**
* @covers \App\Controller\DatabaseConnection
* @covers \App\Controller\ConfigController
*/
class DatabaseConnectionTest extends BindApiControllerTest
{
private PDO $dbConnection;
public function testGetConnection()
{
$configController = new ConfigController(test: true);
$dbHost = $configController->getConfig(configKey: 'dbHost');
$dbPort = $configController->getConfig(configKey: 'dbPort');
$dbDatabase = $configController->getConfig(configKey: 'dbDatabase');
$dbUser = $configController->getConfig(configKey: 'dbUser');
$dbPassword = $configController->getConfig(configKey: 'dbPassword');
try {
$this->dbConnection = new PDO(
dsn: "mysql:host=$dbHost;port=$dbPort;charset=utf8mb4;dbname=$dbDatabase",
username: $dbUser,
password: $dbPassword
);
} catch (PDOException $e) {
$this->fail(message: $e->getMessage());
}
$databaseConnection = new DatabaseConnection(configController: $configController);
self::assertEquals(expected: $databaseConnection->getConnection(), actual: $this->dbConnection);
}
}

View File

@ -1,28 +1,28 @@
<?php
namespace App\Controller;
namespace Unit\Controller;
use PHPUnit\Framework\TestCase;
/**
*
*/
class NameserverControllerTest extends TestCase
class NameserverControllerTest extends BindApiControllerTest
{
public function setUp(): void
{
//$this->fixture =
}
public function tearDown(): void
{
}
public function testUpdate()
{
self::assertEquals(expected: true, actual: true);
}
}

View File

@ -1,6 +1,6 @@
<?php
namespace App\Controller;
namespace Unit\Controller;
use PHPUnit\Framework\TestCase;
@ -8,7 +8,7 @@ use PHPUnit\Framework\TestCase;
/**
*
*/
class RequestControllerTest extends TestCase
class RequestControllerTest extends BindApiControllerTest
{
public function setUp(): void

View File

@ -0,0 +1,124 @@
<?php
namespace Unit\Repository;
use App\Controller\ConfigController;
use App\Controller\DomainController;
use App\Entity\Domain;
use App\Repository\DomainRepository;
use DI\Container;
use DI\ContainerBuilder;
use Exception;
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use PHPUnit\Framework\TestCase;
use Unit\Controller\BindApiControllerTest;
use function DI\autowire;
/**
*
*/
class DomainRepositoryTest extends BindApiControllerTest
{
private string $localZoneFile;
private string $localZonesDir;
private string $namedConfLocalFile;
/**
* @param int|string $dataName
*
* @throws Exception
* @internal This method is not covered by the backward compatibility promise for PHPUnit
*/
public function __construct(?string $name = null, array $data = [], $dataName = '')
{
parent::__construct(name: $name, data: $data, dataName: $dataName);
}
public function setUp(): void
{
$this->logger->info(message: 'Started DomainRepositoryTest');
}
public function tearDown(): void
{
$this->logger->info(message: 'Finished DomainRepositoryTest');
}
/**
*/
public function testInsert()
{
self::assertEquals(expected: true, actual: true);
/*
$domain = new Domain(name: 'inserttest.org', panel: 'keyhelp.lab.24unix.net');
$this->domainRepository->insert(domain: $domain);
$this->domainController->createSlaveZoneFile(domain: $domain);
// now get the persisted domain with id
$domainTest = $this->domainRepository->findByName(name: 'inserttest.org');
$this->assertIsNotBool(actual: $domainTest);
$this->assertEquals(expected: 'inserttest.org', actual: $domainTest->getName());
if ($namedConfLocal = file_get_contents(filename: $this->namedConfLocalFile)) {
$this->assertStringContainsString(needle: $this->localZoneFile, haystack: $namedConfLocal);
} else {
$this->fail(message: 'No permissions: ' . $this->namedConfLocalFile);
}
$this->assertNotFalse(condition: fileperms(filename: $this->localZoneFile));
$localZones = file_get_contents(filename: $this->localZoneFile);
$this->assertStringContainsString(needle: $domainTest->getName(), haystack: $localZones);
$zoneFile = $this->localZonesDir . $domain->getName();
$this->assertFileExists(filename: $zoneFile);
// clean up
$this->domainRepository->delete(domain: $domainTest);
*/
}
/**
*/
public function testDelete()
{
self::assertEquals(expected: true, actual: true);
/*
$domain = new Domain(name: 'inserttest.org', panel: 'keyhelp.lab.24unix.net');
$this->domainRepository->insert(domain: $domain);
$this->domainController->createSlaveZoneFile(domain: $domain);
$domainTest = $this->domainRepository->findByName(name: 'inserttest.org');
$this->assertIsNotBool(actual: $domainTest);
$this->assertEquals(expected: 'inserttest.org', actual: $domainTest->getName());
// domain is valid and created
// now delete and check for cleanup
$this->domainRepository->delete(domain: $domainTest);
$this->domainController->deleteZone(domain: $domainTest);
// check zone is removed
$this->assertNotFalse(condition: fileperms(filename: $this->localZoneFile));
$localZones = file_get_contents(filename: $this->localZoneFile);
$this->assertStringNotContainsString(needle: $domainTest->getName(), haystack: $localZones);
$zoneFile = $this->localZonesDir . $domain->getName();
$this->assertFileDoesNotExist(filename: $zoneFile);
*/
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace Unit\Repository;
use App\Entity\Nameserver;
use Unit\Controller\BindApiControllerTest;
/**
*
*/
class NameserverRepositoryTest extends BindApiControllerTest
{
/**
*/
public function testInsert()
{
$nameserver = new Nameserver(name: 'inserttest.org', a: '1.2.3.4', aaaa: '1bad::babe');
$this->nameserverRepository->insert(nameserver: $nameserver);
$nameserverTest = $this->nameserverRepository->findByName(name: 'inserttest.org');
$this->assertIsNotBool(actual: $nameserver);
$this->assertEquals(expected: 'inserttest.org', actual: $nameserverTest->getName());
// clean up
$this->nameserverRepository->delete(id: $nameserverTest->getId());
}
}

View File

@ -1,11 +1,15 @@
<?php
namespace App\Repository;
namespace Unit\Repository;
use App\Controller\BindApiTestController;
use PHPUnit\Framework\TestCase;
use Unit\Controller\BindApiControllerTest;
class PanelRepositoryTest extends BindApiTestController
/**
*
*/
class PanelRepositoryTest extends BindApiControllerTest
{
@ -20,6 +24,7 @@ class PanelRepositoryTest extends BindApiTestController
public function testInsert()
{
}
self::assertEquals(expected: true, actual: true);
}
}