Compare commits
No commits in common. "master" and "1.0.9" have entirely different histories.
|
@ -14,6 +14,3 @@
|
||||||
/config.json.prod
|
/config.json.prod
|
||||||
keys.txt
|
keys.txt
|
||||||
/.phpunit.cache
|
/.phpunit.cache
|
||||||
/var/log/*
|
|
||||||
/public/openapi/bindapi.json
|
|
||||||
/public/openapi/bootstrap.php
|
|
||||||
|
|
6
TODO
6
TODO
|
@ -1,7 +1,3 @@
|
||||||
API Endpoint cleanup
|
check keytype of panel/bindApi
|
||||||
check keytype of panel
|
|
||||||
check keytype of 1bindApi
|
|
||||||
check:configkey => update config.json
|
|
||||||
more UNIT tests
|
more UNIT tests
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,11 @@ if (php_sapi_name() !== 'cli') {
|
||||||
|
|
||||||
// check php version (must be >= 8.1)
|
// check php version (must be >= 8.1)
|
||||||
/** @noinspection PhpArgumentWithoutNamedIdentifierInspection */
|
/** @noinspection PhpArgumentWithoutNamedIdentifierInspection */
|
||||||
if (version_compare(PHP_VERSION, '8.2.0', '<')) {
|
if (version_compare(PHP_VERSION, '8.1.0', '<')) {
|
||||||
echo 'This application requires PHP 8.2 or newer. You are running ' . PHP_VERSION . PHP_EOL;
|
echo 'This application requires PHP 8.1 or newer. You are running ' . PHP_VERSION . PHP_EOL;
|
||||||
echo 'If you are using KeyHelp, use keyhelp-php82 ' . $argv[0] . ' instead.' . PHP_EOL;
|
echo 'If you are using KeyHelp, use keyhelp-php81 ' . $argv[0] . ' instead.' . PHP_EOL;
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @noinspection PhpArgumentWithoutNamedIdentifierInspection */
|
/** @noinspection PhpArgumentWithoutNamedIdentifierInspection */
|
||||||
require dirname(__DIR__, 1) . '/src/Utilities/Console.php';
|
require dirname(__DIR__, 1) . '/src/Util/Console.php';
|
||||||
|
|
148
bindapi.json
148
bindapi.json
|
@ -1,148 +0,0 @@
|
||||||
{
|
|
||||||
"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"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,8 +1,8 @@
|
||||||
{
|
{
|
||||||
"name": "tracer/bindapi",
|
"name": "24unix/bindapi",
|
||||||
"description": "manage Bind9 client zones for KeyHelp",
|
"description": "manage Bind9 DNS server via REST API",
|
||||||
"version": "1.1.2",
|
"version": "1.0.8",
|
||||||
"build_number": "380",
|
"build_number": "354",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Micha Espey",
|
"name": "Micha Espey",
|
||||||
|
@ -23,7 +23,6 @@
|
||||||
"ext-posix": "*",
|
"ext-posix": "*",
|
||||||
"ext-sodium": "*",
|
"ext-sodium": "*",
|
||||||
"arubacao/tld-checker": "^1.2",
|
"arubacao/tld-checker": "^1.2",
|
||||||
"bartlett/php-compatinfo": "^7.1",
|
|
||||||
"monolog/monolog": "^3.1",
|
"monolog/monolog": "^3.1",
|
||||||
"netresearch/jsonmapper": "^4.4",
|
"netresearch/jsonmapper": "^4.4",
|
||||||
"php-di/php-di": "^6.3",
|
"php-di/php-di": "^6.3",
|
||||||
|
@ -31,7 +30,7 @@
|
||||||
"robmorgan/phinx": "^0.15",
|
"robmorgan/phinx": "^0.15",
|
||||||
"symfony/property-access": "^6.1",
|
"symfony/property-access": "^6.1",
|
||||||
"symfony/serializer": "^6.1",
|
"symfony/serializer": "^6.1",
|
||||||
"zircote/swagger-php": "^4.8"
|
"zircote/swagger-php": "^4.2"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"optimize-autoloader": true,
|
"optimize-autoloader": true,
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,10 +1,9 @@
|
||||||
{
|
{
|
||||||
"env": "prod",
|
|
||||||
"dbHost": "localhost",
|
"dbHost": "localhost",
|
||||||
"dbPort": 3306,
|
"dbPort": 3306,
|
||||||
"dbDatabase": "sampledb",
|
"dbDatabase": "sampledb",
|
||||||
"dbUser": "sampleuser",
|
"dbUser": "sampleuser",
|
||||||
"dbPassword": "secret",
|
"dbPassword": "secret",
|
||||||
"encryptionKey": "1bad::babe",
|
"encryptionKey": "changeme",
|
||||||
"debug": false
|
"debug": false
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
<?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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
<?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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
<?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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -112,36 +112,12 @@ return array (
|
||||||
),
|
),
|
||||||
'columns' =>
|
'columns' =>
|
||||||
array (
|
array (
|
||||||
'id' =>
|
|
||||||
array (
|
|
||||||
'TABLE_CATALOG' => 'def',
|
|
||||||
'TABLE_NAME' => 'config',
|
|
||||||
'COLUMN_NAME' => 'id',
|
|
||||||
'ORDINAL_POSITION' => 1,
|
|
||||||
'COLUMN_DEFAULT' => 'uuid()',
|
|
||||||
'IS_NULLABLE' => 'NO',
|
|
||||||
'DATA_TYPE' => 'uuid',
|
|
||||||
'CHARACTER_MAXIMUM_LENGTH' => NULL,
|
|
||||||
'CHARACTER_OCTET_LENGTH' => NULL,
|
|
||||||
'NUMERIC_PRECISION' => NULL,
|
|
||||||
'NUMERIC_SCALE' => NULL,
|
|
||||||
'DATETIME_PRECISION' => NULL,
|
|
||||||
'CHARACTER_SET_NAME' => NULL,
|
|
||||||
'COLLATION_NAME' => NULL,
|
|
||||||
'COLUMN_TYPE' => 'uuid',
|
|
||||||
'COLUMN_KEY' => 'PRI',
|
|
||||||
'EXTRA' => '',
|
|
||||||
'PRIVILEGES' => 'select,insert,update,references',
|
|
||||||
'COLUMN_COMMENT' => '',
|
|
||||||
'IS_GENERATED' => 'NEVER',
|
|
||||||
'GENERATION_EXPRESSION' => NULL,
|
|
||||||
),
|
|
||||||
'name' =>
|
'name' =>
|
||||||
array (
|
array (
|
||||||
'TABLE_CATALOG' => 'def',
|
'TABLE_CATALOG' => 'def',
|
||||||
'TABLE_NAME' => 'config',
|
'TABLE_NAME' => 'config',
|
||||||
'COLUMN_NAME' => 'name',
|
'COLUMN_NAME' => 'name',
|
||||||
'ORDINAL_POSITION' => 2,
|
'ORDINAL_POSITION' => 1,
|
||||||
'COLUMN_DEFAULT' => NULL,
|
'COLUMN_DEFAULT' => NULL,
|
||||||
'IS_NULLABLE' => 'NO',
|
'IS_NULLABLE' => 'NO',
|
||||||
'DATA_TYPE' => 'varchar',
|
'DATA_TYPE' => 'varchar',
|
||||||
|
@ -153,7 +129,7 @@ return array (
|
||||||
'CHARACTER_SET_NAME' => 'utf8mb4',
|
'CHARACTER_SET_NAME' => 'utf8mb4',
|
||||||
'COLLATION_NAME' => 'utf8mb4_general_ci',
|
'COLLATION_NAME' => 'utf8mb4_general_ci',
|
||||||
'COLUMN_TYPE' => 'varchar(256)',
|
'COLUMN_TYPE' => 'varchar(256)',
|
||||||
'COLUMN_KEY' => 'UNI',
|
'COLUMN_KEY' => 'PRI',
|
||||||
'EXTRA' => '',
|
'EXTRA' => '',
|
||||||
'PRIVILEGES' => 'select,insert,update,references',
|
'PRIVILEGES' => 'select,insert,update,references',
|
||||||
'COLUMN_COMMENT' => '',
|
'COLUMN_COMMENT' => '',
|
||||||
|
@ -165,7 +141,7 @@ return array (
|
||||||
'TABLE_CATALOG' => 'def',
|
'TABLE_CATALOG' => 'def',
|
||||||
'TABLE_NAME' => 'config',
|
'TABLE_NAME' => 'config',
|
||||||
'COLUMN_NAME' => 'value',
|
'COLUMN_NAME' => 'value',
|
||||||
'ORDINAL_POSITION' => 3,
|
'ORDINAL_POSITION' => 2,
|
||||||
'COLUMN_DEFAULT' => NULL,
|
'COLUMN_DEFAULT' => NULL,
|
||||||
'IS_NULLABLE' => 'NO',
|
'IS_NULLABLE' => 'NO',
|
||||||
'DATA_TYPE' => 'varchar',
|
'DATA_TYPE' => 'varchar',
|
||||||
|
@ -187,24 +163,6 @@ return array (
|
||||||
),
|
),
|
||||||
'indexes' =>
|
'indexes' =>
|
||||||
array (
|
array (
|
||||||
'PRIMARY' =>
|
|
||||||
array (
|
|
||||||
1 =>
|
|
||||||
array (
|
|
||||||
'Table' => 'config',
|
|
||||||
'Non_unique' => 0,
|
|
||||||
'Key_name' => 'PRIMARY',
|
|
||||||
'Seq_in_index' => 1,
|
|
||||||
'Column_name' => 'id',
|
|
||||||
'Collation' => 'A',
|
|
||||||
'Sub_part' => NULL,
|
|
||||||
'Packed' => NULL,
|
|
||||||
'Null' => '',
|
|
||||||
'Index_type' => 'BTREE',
|
|
||||||
'Comment' => '',
|
|
||||||
'Index_comment' => '',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'name' =>
|
'name' =>
|
||||||
array (
|
array (
|
||||||
1 =>
|
1 =>
|
||||||
|
@ -223,24 +181,6 @@ return array (
|
||||||
'Index_comment' => '',
|
'Index_comment' => '',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
'id' =>
|
|
||||||
array (
|
|
||||||
1 =>
|
|
||||||
array (
|
|
||||||
'Table' => 'config',
|
|
||||||
'Non_unique' => 0,
|
|
||||||
'Key_name' => 'id',
|
|
||||||
'Seq_in_index' => 1,
|
|
||||||
'Column_name' => 'id',
|
|
||||||
'Collation' => 'A',
|
|
||||||
'Sub_part' => NULL,
|
|
||||||
'Packed' => NULL,
|
|
||||||
'Null' => '',
|
|
||||||
'Index_type' => 'BTREE',
|
|
||||||
'Comment' => '',
|
|
||||||
'Index_comment' => '',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
'foreign_keys' => NULL,
|
'foreign_keys' => NULL,
|
||||||
),
|
),
|
||||||
|
@ -1186,30 +1126,6 @@ return array (
|
||||||
'IS_GENERATED' => 'NEVER',
|
'IS_GENERATED' => 'NEVER',
|
||||||
'GENERATION_EXPRESSION' => NULL,
|
'GENERATION_EXPRESSION' => NULL,
|
||||||
),
|
),
|
||||||
'self' =>
|
|
||||||
array (
|
|
||||||
'TABLE_CATALOG' => 'def',
|
|
||||||
'TABLE_NAME' => 'nameservers',
|
|
||||||
'COLUMN_NAME' => 'self',
|
|
||||||
'ORDINAL_POSITION' => 7,
|
|
||||||
'COLUMN_DEFAULT' => NULL,
|
|
||||||
'IS_NULLABLE' => 'NO',
|
|
||||||
'DATA_TYPE' => 'enum',
|
|
||||||
'CHARACTER_MAXIMUM_LENGTH' => 3,
|
|
||||||
'CHARACTER_OCTET_LENGTH' => 12,
|
|
||||||
'NUMERIC_PRECISION' => NULL,
|
|
||||||
'NUMERIC_SCALE' => NULL,
|
|
||||||
'DATETIME_PRECISION' => NULL,
|
|
||||||
'CHARACTER_SET_NAME' => 'utf8mb4',
|
|
||||||
'COLLATION_NAME' => 'utf8mb4_unicode_ci',
|
|
||||||
'COLUMN_TYPE' => 'enum(\'yes\',\'no\')',
|
|
||||||
'COLUMN_KEY' => '',
|
|
||||||
'EXTRA' => '',
|
|
||||||
'PRIVILEGES' => 'select,insert,update,references',
|
|
||||||
'COLUMN_COMMENT' => '',
|
|
||||||
'IS_GENERATED' => 'NEVER',
|
|
||||||
'GENERATION_EXPRESSION' => NULL,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
'indexes' =>
|
'indexes' =>
|
||||||
array (
|
array (
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Copy these files to /etc/systems/system, adapt the path in the service unit and enable the timer by issuing:
|
Copy this files to /etc/systems/system, adapt the path in the service unit and enable the timer by issuing:
|
||||||
|
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
systemctl enable bindAPI.timer
|
systemctl enable bindAPI.timer
|
||||||
|
|
|
@ -2,5 +2,4 @@
|
||||||
Description=BindAPI Service to check zone file and reload configuration
|
Description=BindAPI Service to check zone file and reload configuration
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
User=<paneluser>
|
|
||||||
ExecStart=/home/users/<user>/<bindApi>/bin/console -q cron:run
|
ExecStart=/home/users/<user>/<bindApi>/bin/console -q cron:run
|
||||||
|
|
|
@ -6,15 +6,10 @@ error_reporting(error_level: E_ALL);
|
||||||
|
|
||||||
require dirname(path: __DIR__) . '/vendor/autoload.php';
|
require dirname(path: __DIR__) . '/vendor/autoload.php';
|
||||||
|
|
||||||
$parsedUrl = parse_url(url: $_SERVER['REQUEST_URI'], component: PHP_URL_PATH);
|
$uri = parse_url(url: $_SERVER['REQUEST_URI'], component: PHP_URL_PATH);
|
||||||
$uri = explode(separator: '/', string: $parsedUrl);
|
$uri = explode(separator: '/', string: $uri);
|
||||||
|
|
||||||
$baseRoutes = ['app', 'api'];
|
if ($uri[1] !== 'api') {
|
||||||
$uriPrefix = $uriFirstThreeLetters = substr(string: $uri[1], offset: 0, length: 3);
|
|
||||||
|
|
||||||
|
|
||||||
if (!in_array(needle: $uriPrefix, haystack: $baseRoutes)) {
|
|
||||||
// only handle $baseRoutes, elso go to swagger ui
|
|
||||||
$scheme = $_SERVER['REQUEST_SCHEME'];
|
$scheme = $_SERVER['REQUEST_SCHEME'];
|
||||||
$host = $_SERVER['SERVER_NAME'];
|
$host = $_SERVER['SERVER_NAME'];
|
||||||
$header = "$scheme://$host/openapi/index.html";
|
$header = "$scheme://$host/openapi/index.html";
|
||||||
|
@ -26,16 +21,10 @@ header(header: "Access-Control-Allow-Origin: *");
|
||||||
header(header: "Content-Type: application/json; charset=UTF-8");
|
header(header: "Content-Type: application/json; charset=UTF-8");
|
||||||
header(header: "Access-Control-Allow-Methods: OPTIONS,GET,POST,PUT,DELETE");
|
header(header: "Access-Control-Allow-Methods: OPTIONS,GET,POST,PUT,DELETE");
|
||||||
header(header: "Access-Control-Max-Age: 3600");
|
header(header: "Access-Control-Max-Age: 3600");
|
||||||
header(header: "Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With, x-api-key");
|
header(header: "Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
|
||||||
|
|
||||||
$requestMethod = $_SERVER["REQUEST_METHOD"];
|
$requestMethod = $_SERVER["REQUEST_METHOD"];
|
||||||
|
|
||||||
if ($requestMethod === "OPTIONS") {
|
|
||||||
// Respond with OK status code for preflight requests
|
|
||||||
http_response_code(response_code: 200);
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$app = new BindAPI(quiet: false);
|
$app = new BindAPI(quiet: false);
|
||||||
$app->handleRequest(requestMethod: $requestMethod, uri: $uri);
|
$app->handleRequest(requestMethod: $requestMethod, uri: $uri);
|
||||||
|
@ -44,4 +33,3 @@ try {
|
||||||
'error' => $e->getMessage()
|
'error' => $e->getMessage()
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
const DEFAULT_NS = 'ns2.24unix.net';
|
|
||||||
|
|
||||||
const NAMESERVERS = ['ns1.24unix.net', 'ns2.24unix.net'];
|
|
|
@ -19,8 +19,7 @@
|
||||||
<script>
|
<script>
|
||||||
window.onload = function () {
|
window.onload = function () {
|
||||||
// Begin Swagger UI call region
|
// Begin Swagger UI call region
|
||||||
let ui;
|
const ui = SwaggerUIBundle({
|
||||||
ui = SwaggerUIBundle({
|
|
||||||
url: "/openapi/bindapi.json",
|
url: "/openapi/bindapi.json",
|
||||||
dom_id: "#swagger-ui",
|
dom_id: "#swagger-ui",
|
||||||
deepLinking: true,
|
deepLinking: true,
|
||||||
|
|
|
@ -1,13 +1,25 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Service;
|
namespace App\Controller;
|
||||||
|
|
||||||
use UnhandledMatchError;
|
use UnhandledMatchError;
|
||||||
|
|
||||||
error_reporting(error_level: E_ALL);
|
error_reporting(error_level: E_ALL);
|
||||||
|
|
||||||
class ApiClient
|
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
|
function sendCommand(string $requestType, string $serverName, int $versionIP, string $apiKey, string $command, string $serverType, array $body = []): array
|
||||||
{
|
{
|
||||||
$error = false;
|
$error = false;
|
||||||
|
@ -63,7 +75,6 @@ class ApiClient
|
||||||
break;
|
break;
|
||||||
case 400:
|
case 400:
|
||||||
$result = $resultJSON;
|
$result = $resultJSON;
|
||||||
$error = true;
|
|
||||||
break;
|
break;
|
||||||
case 401:
|
case 401:
|
||||||
$result = 'Missing or wrong API Key';
|
$result = 'Missing or wrong API Key';
|
||||||
|
@ -71,14 +82,11 @@ class ApiClient
|
||||||
break;
|
break;
|
||||||
case 404:
|
case 404:
|
||||||
$result = '404 Not Found';
|
$result = '404 Not Found';
|
||||||
$error = true;
|
|
||||||
break;
|
break;
|
||||||
case 500:
|
case 500:
|
||||||
$result = 'server error';
|
$result = 'server error';
|
||||||
$error = true;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$error = true;
|
|
||||||
$result = 'Unhandled error: ' . $httpResponse;
|
$result = 'Unhandled error: ' . $httpResponse;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -105,7 +113,7 @@ class ApiClient
|
||||||
$options = array(
|
$options = array(
|
||||||
CURLOPT_RETURNTRANSFER => true,
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
CURLOPT_FOLLOWLOCATION => true,
|
CURLOPT_FOLLOWLOCATION => true,
|
||||||
CURLOPT_ENCODING => '',
|
CURLOPT_ENCODING => "",
|
||||||
CURLOPT_AUTOREFERER => true,
|
CURLOPT_AUTOREFERER => true,
|
||||||
CURLOPT_CONNECTTIMEOUT => 120,
|
CURLOPT_CONNECTTIMEOUT => 120,
|
||||||
CURLOPT_TIMEOUT => 120,
|
CURLOPT_TIMEOUT => 120,
|
||||||
|
@ -131,6 +139,4 @@ class ApiClient
|
||||||
|
|
||||||
return $header;
|
return $header;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
namespace App\Controller\Commands;
|
namespace App\Controller\Commands;
|
||||||
|
|
||||||
use App\Utilities\Colors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -33,17 +31,17 @@ class CommandGroup
|
||||||
|
|
||||||
public function printCommands(int $longestCommandLength): void
|
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;
|
echo COLOR_YELLOW . str_pad(string: $this->name, length: $longestCommandLength + 1) . COLOR_WHITE . $this->description . COLOR_DEFAULT . PHP_EOL;
|
||||||
foreach ($this->commands as $command) {
|
foreach ($this->commands as $command) {
|
||||||
echo Colors::GREEN . str_pad(string: ' ', length: $longestCommandLength + 1, pad_type: STR_PAD_LEFT) . $this->name . ':' . $command->getName();
|
echo COLOR_GREEN . str_pad(string: ' ', length: $longestCommandLength + 1, pad_type: STR_PAD_LEFT) . $this->name . ':' . $command->getName();
|
||||||
foreach ($command->getMandatoryParameters() as $optionals) {
|
foreach ($command->getMandatoryParameters() as $optionals) {
|
||||||
echo ' <' . $optionals . '>';
|
echo ' <' . $optionals . '>';
|
||||||
}
|
}
|
||||||
foreach ($command->getOptionalParameters() as $mandatory) {
|
foreach ($command->getOptionalParameters() as $mandatory) {
|
||||||
echo ' {' . $mandatory . '}';
|
echo ' {' . $mandatory . '}';
|
||||||
}
|
}
|
||||||
echo Colors::WHITE . ' ' . $command->getDescription();
|
echo COLOR_WHITE . ' ' . $command->getDescription();
|
||||||
echo Colors::DEFAULT . PHP_EOL;
|
echo COLOR_DEFAULT . PHP_EOL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
namespace App\Controller\Commands;
|
namespace App\Controller\Commands;
|
||||||
|
|
||||||
use App\Utilities\Colors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -66,23 +64,23 @@ class CommandGroupContainer
|
||||||
if ($group->exec(subcommand: $subcommand)) {
|
if ($group->exec(subcommand: $subcommand)) {
|
||||||
exit(0);
|
exit(0);
|
||||||
} else {
|
} else {
|
||||||
echo Colors::DEFAULT . 'Unknown subcommand ' . Colors::YELLOW . $subcommand . Colors::DEFAULT .' for ' . Colors::YELLOW . $command . Colors::DEFAULT . '.' . PHP_EOL;
|
echo COLOR_DEFAULT . 'Unknown subcommand ' . COLOR_YELLOW . $subcommand . COLOR_DEFAULT .' for ' . COLOR_YELLOW . $command . COLOR_DEFAULT . '.' . PHP_EOL;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
echo Colors::DEFAULT . 'Unknown command group ' . Colors::YELLOW . $command . Colors::DEFAULT . '.' . PHP_EOL;
|
echo COLOR_DEFAULT . 'Unknown command group ' . COLOR_YELLOW . $command . COLOR_DEFAULT . '.' . PHP_EOL;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// check for command group and print available commands
|
// check for command group and print available commands
|
||||||
foreach ($this->commandGroups as $group) {
|
foreach ($this->commandGroups as $group) {
|
||||||
if ($group->getName() === $command) {
|
if ($group->getName() === $command) {
|
||||||
echo 'Available subcommands for: ' . Colors::YELLOW . $group->getName() . Colors::DEFAULT . ':' . PHP_EOL;
|
echo 'Available subcommands for: ' . COLOR_YELLOW . $group->getName() . COLOR_DEFAULT . ':' . PHP_EOL;
|
||||||
$group->printCommands(strlen(string: $group->getName()));
|
$group->printCommands(strlen(string: $group->getName()));
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
echo Colors::DEFAULT . 'Unknown command ' . Colors::YELLOW . $command . Colors::DEFAULT . '.' . PHP_EOL;
|
echo COLOR_DEFAULT . 'Unknown command ' . COLOR_YELLOW . $command . COLOR_DEFAULT . '.' . PHP_EOL;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,14 +2,11 @@
|
||||||
|
|
||||||
namespace App\Controller;
|
namespace App\Controller;
|
||||||
|
|
||||||
use App\Utilities\Colors;
|
|
||||||
|
|
||||||
class ConfigController
|
class ConfigController
|
||||||
{
|
{
|
||||||
private array $config;
|
private array $config;
|
||||||
private static $missingEncryptionShown = false;
|
|
||||||
|
|
||||||
public function __construct(private readonly bool $quiet, bool $test = false)
|
public function __construct(bool $quiet, bool $test = false)
|
||||||
{
|
{
|
||||||
|
|
||||||
if ($test) {
|
if ($test) {
|
||||||
|
@ -38,33 +35,21 @@ class ConfigController
|
||||||
}
|
}
|
||||||
$configJSON = file_get_contents(filename: $configFile);
|
$configJSON = file_get_contents(filename: $configFile);
|
||||||
|
|
||||||
// first check if json is valid, after make the assignment
|
if (json_decode(json: $configJSON) === null) {
|
||||||
if (json_decode(json: $configJSON, associative: true) === null) {
|
|
||||||
echo 'Config file is not valid JSON.' . PHP_EOL;
|
echo 'Config file is not valid JSON.' . PHP_EOL;
|
||||||
echo $configJSON . PHP_EOL;
|
echo $configJSON . PHP_EOL;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->config = json_decode(json: $configJSON, associative: true);
|
$this->config = json_decode(json: $configJSON, associative: true);
|
||||||
if (!ConfigController::$missingEncryptionShown) {
|
|
||||||
if (!isset($this->config['encryptionKey']) || ($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;
|
|
||||||
}
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
$this->config['quiet'] = (bool)$quiet;
|
||||||
|
$this->config['test'] = (bool)$test;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getConfig(string $configKey): ?string
|
public function getConfig(string $configKey): string
|
||||||
{
|
{
|
||||||
if (isset($this->config[$configKey])) {
|
return $this->config[$configKey];
|
||||||
return $this->config[$configKey];
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,6 @@ use App\Entity\Domain;
|
||||||
use App\Repository\DomainRepository;
|
use App\Repository\DomainRepository;
|
||||||
use App\Repository\NameserverRepository;
|
use App\Repository\NameserverRepository;
|
||||||
use App\Repository\PanelRepository;
|
use App\Repository\PanelRepository;
|
||||||
use App\Service\ApiClient;
|
|
||||||
use App\Utilities\Colors;
|
|
||||||
use Monolog\Logger;
|
use Monolog\Logger;
|
||||||
|
|
||||||
error_reporting(error_level: E_ALL);
|
error_reporting(error_level: E_ALL);
|
||||||
|
@ -27,7 +25,7 @@ class DomainController
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly NameserverRepository $nameserverRepository,
|
private readonly NameserverRepository $nameserverRepository,
|
||||||
private readonly ApiClient $checkController,
|
private readonly ApiController $checkController,
|
||||||
private readonly DomainRepository $domainRepository,
|
private readonly DomainRepository $domainRepository,
|
||||||
private readonly PanelRepository $panelRepository,
|
private readonly PanelRepository $panelRepository,
|
||||||
private readonly ConfigController $configController,
|
private readonly ConfigController $configController,
|
||||||
|
@ -83,13 +81,13 @@ class DomainController
|
||||||
foreach ($domains as $domain) {
|
foreach ($domains as $domain) {
|
||||||
$zoneFile = $this->localZonesDir . $domain->getName();
|
$zoneFile = $this->localZonesDir . $domain->getName();
|
||||||
if (!$this->quiet) {
|
if (!$this->quiet) {
|
||||||
echo ' ' . Colors::YELLOW . str_pad(string: $domain->getName(), length: $longestEntry + 1, pad_string: " ", pad_type: STR_PAD_RIGHT) ;
|
echo ' ' . COLOR_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 (strcmp(string1: $self->getName(), string2: $domain->getPanel()) !== 0) {
|
||||||
if (!file_exists(filename: $zoneFile)) {
|
if (!file_exists(filename: $zoneFile)) {
|
||||||
if (!$this->quiet) {
|
if (!$this->quiet) {
|
||||||
echo Colors::GREEN . ' OK' . Colors::DEFAULT . PHP_EOL;
|
echo COLOR_GREEN . ' OK' . COLOR_DEFAULT . PHP_EOL;
|
||||||
}
|
}
|
||||||
$this->createSlaveZoneFile(domain: $domain);
|
$this->createSlaveZoneFile(domain: $domain);
|
||||||
} else {
|
} else {
|
||||||
|
@ -101,19 +99,19 @@ class DomainController
|
||||||
echo 'missing value: ' . $zoneFile;
|
echo 'missing value: ' . $zoneFile;
|
||||||
}
|
}
|
||||||
if (!$this->quiet) {
|
if (!$this->quiet) {
|
||||||
echo Colors::DEFAULT . 'Zone already exists.' . PHP_EOL;
|
echo COLOR_DEFAULT . 'Zone already exists.' . PHP_EOL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!$this->quiet) {
|
if (!$this->quiet) {
|
||||||
echo Colors::DEFAULT . 'We are master for ' . Colors::YELLOW . $domain->getName() . PHP_EOL;
|
echo COLOR_DEFAULT . 'We are master for ' . COLOR_YELLOW . $domain->getName() . PHP_EOL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// remove stale zones
|
// remove stale zones
|
||||||
foreach ($existingZones as $zone) {
|
foreach ($existingZones as $zone) {
|
||||||
if (!$this->quiet) {
|
if (!$this->quiet) {
|
||||||
echo 'Removing stale zone: ' . Colors::YELLOW . $zone . Colors::DEFAULT . PHP_EOL;
|
echo 'Removing stale zone: ' . COLOR_YELLOW . $zone . COLOR_DEFAULT . PHP_EOL;
|
||||||
}
|
}
|
||||||
echo $zone . PHP_EOL;
|
echo $zone . PHP_EOL;
|
||||||
unlink(filename: $zone);
|
unlink(filename: $zone);
|
||||||
|
@ -191,12 +189,12 @@ class DomainController
|
||||||
$uid = posix_geteuid();
|
$uid = posix_geteuid();
|
||||||
}
|
}
|
||||||
if (!$this->quiet) {
|
if (!$this->quiet) {
|
||||||
echo "UID:\t" . Colors::YELLOW . $uid . PHP_EOL;
|
echo "UID:\t" . COLOR_YELLOW . $uid . PHP_EOL;
|
||||||
}
|
}
|
||||||
$pwuid = posix_getpwuid(user_id: $uid);
|
$pwuid = posix_getpwuid(user_id: $uid);
|
||||||
$name = $pwuid['name'];
|
$name = $pwuid['name'];
|
||||||
if (!$this->quiet) {
|
if (!$this->quiet) {
|
||||||
echo Colors::DEFAULT . "Name:\t" . Colors::YELLOW . $name . PHP_EOL;
|
echo COLOR_DEFAULT . "Name:\t" . COLOR_YELLOW . $name . PHP_EOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$bindGroup = posix_getgrnam(name: 'bind')) {
|
if (!$bindGroup = posix_getgrnam(name: 'bind')) {
|
||||||
|
@ -205,40 +203,40 @@ class DomainController
|
||||||
$members = $bindGroup['members'] ?? [];
|
$members = $bindGroup['members'] ?? [];
|
||||||
if (in_array(needle: $name, haystack: $members)) {
|
if (in_array(needle: $name, haystack: $members)) {
|
||||||
if (!$this->quiet) {
|
if (!$this->quiet) {
|
||||||
echo "\t✅ $name" . Colors::DEFAULT . ' is in group ' . Colors::YELLOW . 'bind' . PHP_EOL;
|
echo "\t✅ $name" . COLOR_DEFAULT . ' is in group ' . COLOR_YELLOW . 'bind' . PHP_EOL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$setupIsValid = false;
|
$setupIsValid = false;
|
||||||
if (!$this->quiet) {
|
if (!$this->quiet) {
|
||||||
echo Colors::RED . "\t❌$name needs to be in group " . Colors::YELLOW . 'bind' . Colors::DEFAULT . '!' . PHP_EOL;
|
echo COLOR_RED . "\t❌$name needs to be in group " . COLOR_YELLOW . 'bind' . COLOR_DEFAULT . '!' . PHP_EOL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!$this->quiet) {
|
if (!$this->quiet) {
|
||||||
echo Colors::DEFAULT . 'Checking ' . Colors::YELLOW . $this->localZoneFile . PHP_EOL;
|
echo COLOR_DEFAULT . 'Checking ' . COLOR_YELLOW . $this->localZoneFile . PHP_EOL;
|
||||||
}
|
}
|
||||||
$localZoneFilePermissions = @fileperms(filename: $this->localZoneFile);
|
$localZoneFilePermissions = @fileperms(filename: $this->localZoneFile);
|
||||||
if ($localZoneFilePermissions & 0x0010) {
|
if ($localZoneFilePermissions & 0x0010) {
|
||||||
if (!$this->quiet) {
|
if (!$this->quiet) {
|
||||||
echo Colors::DEFAULT . "\t✅ Group has write access." . PHP_EOL;
|
echo COLOR_DEFAULT . "\t✅ Group has write access." . PHP_EOL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$setupIsValid = false;
|
$setupIsValid = false;
|
||||||
if (!$this->quiet) {
|
if (!$this->quiet) {
|
||||||
echo Colors::RED . "\t❌Group needs write permission!" . Colors::DEFAULT . PHP_EOL;
|
echo COLOR_RED . "\t❌Group needs write permission!" . COLOR_DEFAULT . PHP_EOL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!$this->quiet) {
|
if (!$this->quiet) {
|
||||||
echo 'Checking ' . Colors::YELLOW . $this->namedConfLocalFile . PHP_EOL;
|
echo 'Checking ' . COLOR_YELLOW . $this->namedConfLocalFile . PHP_EOL;
|
||||||
}
|
}
|
||||||
if (file_exists(filename: $this->namedConfLocalFile) && $namedConfLocal = file_get_contents(filename: $this->namedConfLocalFile)) {
|
if (file_exists(filename: $this->namedConfLocalFile) && $namedConfLocal = file_get_contents(filename: $this->namedConfLocalFile)) {
|
||||||
if (!str_contains(haystack: $namedConfLocal, needle: $this->localZoneFile)) {
|
if (!str_contains(haystack: $namedConfLocal, needle: $this->localZoneFile)) {
|
||||||
$setupIsValid = false;
|
$setupIsValid = false;
|
||||||
if (!$this->quiet) {
|
if (!$this->quiet) {
|
||||||
echo "\t❌ $this->localZoneFile" . Colors::RED . ' needs to be included in ' . Colors::YELLOW . $this->namedConfLocalFile . PHP_EOL;
|
echo "\t❌ $this->localZoneFile" . COLOR_RED . ' needs to be included in ' . COLOR_YELLOW . $this->namedConfLocalFile . PHP_EOL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!$this->quiet) {
|
if (!$this->quiet) {
|
||||||
echo "\t✅ $this->localZoneFile" . Colors::DEFAULT . ' is included in ' . Colors::YELLOW . $this->namedConfLocalFile . PHP_EOL;
|
echo "\t✅ $this->localZoneFile" . COLOR_DEFAULT . ' is included in ' . COLOR_YELLOW . $this->namedConfLocalFile . PHP_EOL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -248,7 +246,7 @@ class DomainController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!$this->quiet) {
|
if (!$this->quiet) {
|
||||||
echo Colors::DEFAULT . 'Checking directory: ' . Colors::YELLOW . $this->localZonesDir . PHP_EOL;
|
echo COLOR_DEFAULT . 'Checking directory: ' . COLOR_YELLOW . $this->localZonesDir . PHP_EOL;
|
||||||
}
|
}
|
||||||
$localZoneDirPermissions = @fileperms(filename: $this->localZonesDir);
|
$localZoneDirPermissions = @fileperms(filename: $this->localZonesDir);
|
||||||
if ($localZoneDirPermissions & 0x0010) {
|
if ($localZoneDirPermissions & 0x0010) {
|
||||||
|
@ -258,7 +256,7 @@ class DomainController
|
||||||
} else {
|
} else {
|
||||||
$setupIsValid = false;
|
$setupIsValid = false;
|
||||||
if (!$this->quiet) {
|
if (!$this->quiet) {
|
||||||
echo Colors::RED . "\t❌Group needs write permission!" . PHP_EOL;
|
echo COLOR_RED . "\t❌Group needs write permission!" . PHP_EOL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $setupIsValid;
|
return $setupIsValid;
|
||||||
|
@ -272,7 +270,7 @@ class DomainController
|
||||||
{
|
{
|
||||||
if (!file_exists(filename: $this->localZoneFile)) {
|
if (!file_exists(filename: $this->localZoneFile)) {
|
||||||
if (!$this->quiet) {
|
if (!$this->quiet) {
|
||||||
echo Colors::DEFAULT . 'Local Zone file ' . Colors::YELLOW . $this->localZoneFile . Colors::DEFAULT . ' does not exist.' . PHP_EOL;
|
echo COLOR_DEFAULT . 'Local Zone file ' . COLOR_YELLOW . $this->localZoneFile . COLOR_DEFAULT . ' does not exist.' . PHP_EOL;
|
||||||
}
|
}
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -283,33 +281,33 @@ class DomainController
|
||||||
foreach ($domains as $domain) {
|
foreach ($domains as $domain) {
|
||||||
$idString = '(' . $domain->getId() . ') ';
|
$idString = '(' . $domain->getId() . ') ';
|
||||||
if (!$this->quiet) {
|
if (!$this->quiet) {
|
||||||
echo Colors::YELLOW .
|
echo COLOR_YELLOW .
|
||||||
str_pad(string: $domain->getName(), length: $maxNameLength + 1)
|
str_pad(string: $domain->getName(), length: $maxNameLength + 1)
|
||||||
. Colors::DEFAULT
|
. COLOR_DEFAULT
|
||||||
. str_pad(string: $idString, length: 7, pad_type: STR_PAD_LEFT);
|
. str_pad(string: $idString, length: 7, pad_type: STR_PAD_LEFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
$hasError = false;
|
$hasError = false;
|
||||||
if ($this->isMasterZone(domain: $domain)) {
|
if ($this->isMasterZone(domain: $domain)) {
|
||||||
if (!$this->quiet) {
|
if (!$this->quiet) {
|
||||||
echo Colors::GREEN . 'Master Zone';
|
echo COLOR_GREEN . 'Master Zone';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!str_contains(haystack: $localZones, needle: $domain->getName())) {
|
if (!str_contains(haystack: $localZones, needle: $domain->getName())) {
|
||||||
if (!$this->quiet) {
|
if (!$this->quiet) {
|
||||||
echo Colors::RED . 'is missing in ' . Colors::YELLOW . $this->localZoneFile . Colors::DEFAULT;
|
echo COLOR_RED . 'is missing in ' . COLOR_YELLOW . $this->localZoneFile . COLOR_DEFAULT;
|
||||||
}
|
}
|
||||||
$hasError = true;
|
$hasError = true;
|
||||||
} else {
|
} else {
|
||||||
if (!$this->quiet) {
|
if (!$this->quiet) {
|
||||||
echo Colors::GREEN . 'OK';
|
echo COLOR_GREEN . 'OK';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$zoneFile = $this->localZonesDir . $domain->getName();
|
$zoneFile = $this->localZonesDir . $domain->getName();
|
||||||
|
|
||||||
if (!file_exists(filename: $zoneFile)) {
|
if (!file_exists(filename: $zoneFile)) {
|
||||||
echo ' Missing zone file for ' . Colors::YELLOW . $zoneFile . Colors::DEFAULT;
|
echo ' Missing zone file for ' . COLOR_YELLOW . $zoneFile . COLOR_DEFAULT;
|
||||||
$hasError = true;
|
$hasError = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,7 +316,7 @@ class DomainController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!$this->quiet) {
|
if (!$this->quiet) {
|
||||||
echo Colors::DEFAULT . PHP_EOL;
|
echo COLOR_DEFAULT . PHP_EOL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,7 +366,7 @@ class DomainController
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if (!$this->quiet) {
|
if (!$this->quiet) {
|
||||||
echo Colors::RED . ' Error: ' . Colors::DEFAULT . 'unable to create ' . Colors::YELLOW . $this->localZonesDir . $domainName . Colors::DEFAULT . PHP_EOL;
|
echo COLOR_RED . ' Error: ' . COLOR_DEFAULT . 'unable to create ' . COLOR_YELLOW . $this->localZonesDir . $domainName . COLOR_DEFAULT . PHP_EOL;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ class EncryptionController
|
||||||
|
|
||||||
$plain = sodium_crypto_secretbox_open(ciphertext: $ciphertext, nonce: $nonce, key: $binKey);
|
$plain = sodium_crypto_secretbox_open(ciphertext: $ciphertext, nonce: $nonce, key: $binKey);
|
||||||
if ($plain === false) {
|
if ($plain === false) {
|
||||||
throw new Exception(message: ' Incorrect key.' . PHP_EOL);
|
throw new Exception(message: ' Incorrect key.');
|
||||||
}
|
}
|
||||||
sodium_memzero(string: $ciphertext);
|
sodium_memzero(string: $ciphertext);
|
||||||
sodium_memzero(string: $key);
|
sodium_memzero(string: $key);
|
||||||
|
|
|
@ -10,40 +10,39 @@ use App\Repository\ApikeyRepository;
|
||||||
use App\Repository\DomainRepository;
|
use App\Repository\DomainRepository;
|
||||||
use App\Repository\DynDNSRepository;
|
use App\Repository\DynDNSRepository;
|
||||||
use App\Repository\PanelRepository;
|
use App\Repository\PanelRepository;
|
||||||
use App\Service\ApiClient;
|
|
||||||
use Monolog\Logger;
|
use Monolog\Logger;
|
||||||
use OpenApi\Attributes as OA;
|
use OpenApi\Attributes as OAT;
|
||||||
use OpenApi\Attributes\OpenApi;
|
|
||||||
use OpenApi\Generator;
|
|
||||||
use UnhandledMatchError;
|
use UnhandledMatchError;
|
||||||
use function Symfony\Component\String\s;
|
|
||||||
|
|
||||||
// TODO attributes for swaggerUI
|
// TODO attributes for swaggerUI
|
||||||
|
|
||||||
#[OA\Info(version: VERSION, title: 'bindAPI')]
|
/**
|
||||||
#[OA\Server(
|
*
|
||||||
|
*/
|
||||||
|
#[OAT\Info(version: '0.0.1', title: 'bindAPI')]
|
||||||
|
#[OAT\Server(
|
||||||
url: "{schema}://{hostname}/api",
|
url: "{schema}://{hostname}/api",
|
||||||
description: "The bindAPI URL.",
|
description: "The bindAPI URL.",
|
||||||
variables: [
|
variables: [
|
||||||
new OA\ServerVariable(
|
new OAT\ServerVariable(
|
||||||
serverVariable: 'schema',
|
serverVariable: "schema",
|
||||||
default: 'https',
|
default: "https",
|
||||||
enum: ['http', 'https']
|
enum: ["https", "http"]
|
||||||
),
|
),
|
||||||
new OA\ServerVariable(
|
new OAT\ServerVariable(
|
||||||
serverVariable: 'hostname',
|
serverVariable: "hostname",
|
||||||
default: DEFAULT_NS,
|
default: "ns2.24unix.net",
|
||||||
enum: NAMESERVERS
|
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
)]
|
)]
|
||||||
#[OA\Tag(
|
#[OAT\Tag(
|
||||||
name: "Server"
|
name: "Server"
|
||||||
)]
|
)]
|
||||||
#[OA\SecurityScheme(
|
#[OAT\SecurityScheme(
|
||||||
securityScheme: "Authorization",
|
securityScheme: "Authorization",
|
||||||
type: "apiKey",
|
type: "apiKey",
|
||||||
description: "Api Authentication",
|
description: "description",
|
||||||
name: "X-API-Key",
|
name: "X-API-Key",
|
||||||
in: "header"
|
in: "header"
|
||||||
)]
|
)]
|
||||||
|
@ -57,96 +56,60 @@ class RequestController
|
||||||
private array $uri;
|
private array $uri;
|
||||||
|
|
||||||
|
|
||||||
// server tag
|
/**
|
||||||
private string $baseDir;
|
* @param ApiController $apiController
|
||||||
|
* @param ApikeyRepository $apikeyRepository
|
||||||
#[OA\Get(
|
* @param DomainController $domainController
|
||||||
path: '/ping',
|
* @param DomainRepository $domainRepository
|
||||||
operationId: 'ping',
|
* @param DynDNSRepository $dynDNSRepository
|
||||||
description: 'Checks for connectivity and valid APIkey',
|
* @param PanelRepository $panelRepository
|
||||||
security: [
|
* @param ConfigController $configController
|
||||||
['Authorization' => []]
|
* @param EncryptionController $encryptionController
|
||||||
],
|
* @param Logger $logger
|
||||||
tags: ['Server'],
|
*/
|
||||||
responses: [
|
public function __construct(
|
||||||
new OA\Response(
|
private readonly ApiController $apiController,
|
||||||
response: 200,
|
private readonly ApikeyRepository $apikeyRepository,
|
||||||
description: 'OK'
|
private readonly DomainController $domainController,
|
||||||
),
|
private readonly DomainRepository $domainRepository,
|
||||||
new OA\Response(
|
private readonly DynDNSRepository $dynDNSRepository,
|
||||||
response: 401,
|
private readonly PanelRepository $panelRepository,
|
||||||
description: 'API key is missing or invalid.'
|
private readonly ConfigController $configController,
|
||||||
)
|
private readonly EncryptionController $encryptionController,
|
||||||
]
|
private readonly Logger $logger)
|
||||||
)]
|
|
||||||
private function handlePing(): void
|
|
||||||
{
|
{
|
||||||
if ($this->validateApiKey()) {
|
$this->status = '';
|
||||||
$this->status = '200 OK';
|
$this->response = '';
|
||||||
$this->response = 'pong';
|
$this->message = '';
|
||||||
} else {
|
$this->result = [];
|
||||||
$this->status = '401 Unauthorized';
|
|
||||||
$this->message = 'API key is missing or invalid';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[OA\Get(
|
/**
|
||||||
path: '/version',
|
* @return void
|
||||||
operationId: 'version',
|
*/
|
||||||
description: 'Check the API version of the nameserver.',
|
#[OAT\Get(
|
||||||
security: [
|
|
||||||
['Authorization' => []]
|
|
||||||
],
|
|
||||||
tags: ['Server'],
|
|
||||||
responses: [
|
|
||||||
new OA\Response(
|
|
||||||
response: 200,
|
|
||||||
description: 'x.y.z, aka major, minor, patch'
|
|
||||||
),
|
|
||||||
new OA\Response(
|
|
||||||
response: 401,
|
|
||||||
description: 'API key is missing or invalid.'
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)]
|
|
||||||
private function getVersion(): void
|
|
||||||
{
|
|
||||||
if ($this->validateApiKey()) {
|
|
||||||
$this->status = '200 OK';
|
|
||||||
|
|
||||||
$composerJson = json_decode(json: file_get_contents(filename: $this->baseDir . 'composer.json'));
|
|
||||||
$version = $composerJson->version;
|
|
||||||
$buildNumber = $composerJson->build_number;
|
|
||||||
|
|
||||||
$this->result = [
|
|
||||||
'version' => $version,
|
|
||||||
'buildnumber' => $buildNumber,
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
$this->status = '401 Unauthorized';
|
|
||||||
$this->message = 'API key is missing or invalid';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[OA\Get(
|
|
||||||
path: '/domains',
|
path: '/domains',
|
||||||
operationId: 'getAllDomains',
|
operationId: 'getAllDomains',
|
||||||
description: 'Returns a list of all domains on this server.',
|
description: 'Returns a list of all domains on this server.',
|
||||||
summary: 'List all domains.',
|
summary: 'Listing all domains.',
|
||||||
security: [
|
// security: [
|
||||||
['Authorization' => []]
|
// 'Authorization' => [
|
||||||
],
|
//
|
||||||
|
// "read:api"
|
||||||
|
// ]
|
||||||
|
// ],
|
||||||
|
servers: [],
|
||||||
tags: ['Domains'],
|
tags: ['Domains'],
|
||||||
responses: [
|
responses: [
|
||||||
new OA\Response(
|
new OAT\Response(
|
||||||
response: 200,
|
response: 200,
|
||||||
description: 'OK'
|
description: 'OK'
|
||||||
),
|
),
|
||||||
new OA\Response(
|
new OAT\Response(
|
||||||
response: 401,
|
response: 401,
|
||||||
description: 'API key is missing or invalid.'
|
description: 'API key is missing or invalid.'
|
||||||
),
|
),
|
||||||
new OA\Response(
|
new OAT\Response(
|
||||||
response: 404,
|
response: 404,
|
||||||
description: 'Domain not found.'
|
description: 'Domain not found.'
|
||||||
)]
|
)]
|
||||||
|
@ -168,6 +131,16 @@ class RequestController
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
|
private function handlePing(): void
|
||||||
|
{
|
||||||
|
if ($this->checkPassword()) {
|
||||||
|
$this->status = '200 OK';
|
||||||
|
$this->response = 'pong';
|
||||||
|
} else {
|
||||||
|
$this->status = '401 Unauthorized';
|
||||||
|
$this->message = 'API key is missing or invalid';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -175,7 +148,7 @@ class RequestController
|
||||||
*/
|
*/
|
||||||
private function handleDomains(): void
|
private function handleDomains(): void
|
||||||
{
|
{
|
||||||
if ($this->validateApiKey()) {
|
if ($this->checkPassword()) {
|
||||||
try {
|
try {
|
||||||
match ($this->requestMethod) {
|
match ($this->requestMethod) {
|
||||||
'GET' => $this->handleDomainsGetRequest(),
|
'GET' => $this->handleDomainsGetRequest(),
|
||||||
|
@ -191,8 +164,131 @@ class RequestController
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Tag(name = "Server")
|
||||||
|
* @OA\Get(
|
||||||
|
* path = "/ping",
|
||||||
|
* summary = "Returning pong.",
|
||||||
|
* description = "Can be used to check API or server availability.",
|
||||||
|
* tags={"Server"},
|
||||||
|
* @OA\Response(response = "200", description = "OK"),
|
||||||
|
* @OA\Response(response = "401", description = "API key is missing or invalid."),
|
||||||
|
* security={
|
||||||
|
* {"Authorization":{"read"}}
|
||||||
|
* }
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
* @OA\Tag(name = "Domains")
|
||||||
|
* @OA\Put(
|
||||||
|
* path="/domains/{name}",
|
||||||
|
* summary="Updates a domain.",
|
||||||
|
* description="Updates a domain. Only supplied fields will be updated, existing won't be affected.",
|
||||||
|
* tags={"Domains"},
|
||||||
|
* @OA\Response(response="200", description="OK"),
|
||||||
|
* @OA\Response(response = "401", description = "API key is missing or invalid."),
|
||||||
|
* @OA\Response(response="404", description="Domain not found."),
|
||||||
|
* security={
|
||||||
|
* {"Authorization":{"read":"write"}}
|
||||||
|
* }
|
||||||
|
* )
|
||||||
|
* @OA\Delete (
|
||||||
|
* path="/domains/{name}",
|
||||||
|
* summary="Deletes a domain.",
|
||||||
|
* description="Deletes a domain.",
|
||||||
|
* tags={"Domains"},
|
||||||
|
* @OA\Response(response="200", description="OK"),
|
||||||
|
* @OA\Response(response = "401", description = "API key is missing or invalid."),
|
||||||
|
* @OA\Response(response="404", description="Domain not found."),
|
||||||
|
* security={
|
||||||
|
* {"Authorization":{"read":"write"}}
|
||||||
|
* }
|
||||||
|
* )
|
||||||
|
* @param string $requestMethod
|
||||||
|
* @param array $uri
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
private function validateApiKey(): bool
|
#[
|
||||||
|
OAT\Get(
|
||||||
|
path: '/domains/{name}',
|
||||||
|
operationId: 'getSingleDomain',
|
||||||
|
description: 'Returns information of a single domain specified by its domain name.',
|
||||||
|
summary: 'Returns a single domain.',
|
||||||
|
security: [
|
||||||
|
],
|
||||||
|
tags: ['Domains'],
|
||||||
|
parameters: [
|
||||||
|
new OAT\Parameter(name: 'name', in: 'path', required: true, schema: new OAT\Schema(type: 'string')),
|
||||||
|
],
|
||||||
|
responses: [
|
||||||
|
new OAT\Response(
|
||||||
|
response: 200,
|
||||||
|
description: 'OK'
|
||||||
|
),
|
||||||
|
new OAT\Response(
|
||||||
|
response: 401,
|
||||||
|
description: 'API key is missing or invalid.'
|
||||||
|
),
|
||||||
|
new OAT\Response(
|
||||||
|
response: 404,
|
||||||
|
description: 'Domain not found.'
|
||||||
|
)]
|
||||||
|
|
||||||
|
)]
|
||||||
|
public function handleRequest(string $requestMethod, array $uri): void
|
||||||
|
{
|
||||||
|
$this->logger->debug(message: "Request: $requestMethod $uri[1]");
|
||||||
|
|
||||||
|
$this->requestMethod = strtoupper(string: $requestMethod);
|
||||||
|
$this->uri = $uri;
|
||||||
|
|
||||||
|
$command = $this->uri[2];
|
||||||
|
|
||||||
|
if (empty($command) || !(($command == 'domains') || ($command == 'ping') || ($command == 'apidoc') || ($command == 'dyndns'))) {
|
||||||
|
$this->status = "404 Not Found";
|
||||||
|
$this->message = "Endpoint not found.";
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
match ($command) {
|
||||||
|
'dyndns' => $this->handleDynDNS(),
|
||||||
|
'ping' => $this->handlePing(),
|
||||||
|
'domains' => $this->handleDomains(),
|
||||||
|
};
|
||||||
|
} catch (UnhandledMatchError) {
|
||||||
|
$this->status = '400 Bad Request';
|
||||||
|
$this->message = 'Unknown path: ' . $command;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($this->status)) {
|
||||||
|
header(header: $_SERVER['SERVER_PROTOCOL'] . ' ' . $this->status);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($this->response)) {
|
||||||
|
echo json_encode(value: [
|
||||||
|
'response' => $this->response
|
||||||
|
]);
|
||||||
|
} elseif (!empty($this->result)) {
|
||||||
|
echo json_encode(value: [
|
||||||
|
'result' => $this->result
|
||||||
|
]);
|
||||||
|
} elseif (!empty($this->message)) {
|
||||||
|
echo json_encode(value: [
|
||||||
|
'message' => $this->message
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
echo json_encode(value: [
|
||||||
|
'message' => $this->message ?? 'Error: No message.'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function checkPassword(): bool
|
||||||
{
|
{
|
||||||
$headers = array_change_key_case(array: getallheaders(), case: CASE_UPPER);
|
$headers = array_change_key_case(array: getallheaders(), case: CASE_UPPER);
|
||||||
$apiKey = $headers['X-API-KEY'] ?? '';
|
$apiKey = $headers['X-API-KEY'] ?? '';
|
||||||
|
@ -222,33 +318,10 @@ class RequestController
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[OA\Get(
|
|
||||||
path: '/domains/{name}',
|
|
||||||
operationId: 'getSingleDomain',
|
|
||||||
description: 'Returns information of a single domain specified by its domain name.',
|
|
||||||
summary: 'Returns a single domain.',
|
|
||||||
security: [
|
|
||||||
['Authorization' => []]
|
|
||||||
],
|
|
||||||
tags: ['Domains'],
|
|
||||||
parameters: [
|
|
||||||
new OA\Parameter(name: 'name', in: 'path', required: true, schema: new OA\Schema(type: 'string')),
|
|
||||||
],
|
|
||||||
responses: [
|
|
||||||
new OA\Response(
|
|
||||||
response: 200,
|
|
||||||
description: 'OK'
|
|
||||||
),
|
|
||||||
new OA\Response(
|
|
||||||
response: 401,
|
|
||||||
description: 'API key is missing or invalid.'
|
|
||||||
),
|
|
||||||
new OA\Response(
|
|
||||||
response: 404,
|
|
||||||
description: 'Domain not found.'
|
|
||||||
)]
|
|
||||||
|
|
||||||
)]
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
private function handleDomainsGetRequest(): void
|
private function handleDomainsGetRequest(): void
|
||||||
{
|
{
|
||||||
$name = $this->uri[3] ?? '';
|
$name = $this->uri[3] ?? '';
|
||||||
|
@ -360,6 +433,9 @@ class RequestController
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
private function handleDomainsDeleteRequest(): void
|
private function handleDomainsDeleteRequest(): void
|
||||||
{
|
{
|
||||||
$deleteData = fopen(filename: 'php://input', mode: 'r');
|
$deleteData = fopen(filename: 'php://input', mode: 'r');
|
||||||
|
@ -394,7 +470,7 @@ class RequestController
|
||||||
{
|
{
|
||||||
$this->logger->debug(message: 'handleDynDNS()');
|
$this->logger->debug(message: 'handleDynDNS()');
|
||||||
|
|
||||||
if ($this->validateApiKey()) {
|
if ($this->checkPassword()) {
|
||||||
$host = $this->uri[3] ?? '';
|
$host = $this->uri[3] ?? '';
|
||||||
|
|
||||||
if (empty($host)) {
|
if (empty($host)) {
|
||||||
|
@ -461,7 +537,7 @@ class RequestController
|
||||||
$panel = $this->panelRepository->findByName(name: $domain->getPanel());
|
$panel = $this->panelRepository->findByName(name: $domain->getPanel());
|
||||||
|
|
||||||
if (!empty($panel->getAaaa())) {
|
if (!empty($panel->getAaaa())) {
|
||||||
$domainData = $this->apiClient->sendCommand(
|
$domainData = $this->apiController->sendCommand(
|
||||||
requestType: 'GET',
|
requestType: 'GET',
|
||||||
serverName: $panel->getName(),
|
serverName: $panel->getName(),
|
||||||
versionIP: 6,
|
versionIP: 6,
|
||||||
|
@ -469,7 +545,7 @@ class RequestController
|
||||||
command: 'domains/name/' . $domainName,
|
command: 'domains/name/' . $domainName,
|
||||||
serverType: 'panel');
|
serverType: 'panel');
|
||||||
} else {
|
} else {
|
||||||
$domainData = $this->apiClient->sendCommand(
|
$domainData = $this->apiController->sendCommand(
|
||||||
requestType: 'GET',
|
requestType: 'GET',
|
||||||
serverName: $panel->getName(),
|
serverName: $panel->getName(),
|
||||||
versionIP: 4,
|
versionIP: 4,
|
||||||
|
@ -482,7 +558,7 @@ class RequestController
|
||||||
$domainID = $domainDecodedData->id;
|
$domainID = $domainDecodedData->id;
|
||||||
|
|
||||||
if (!empty($panel->getAaaa())) {
|
if (!empty($panel->getAaaa())) {
|
||||||
$dnsData = $this->apiClient->sendCommand(
|
$dnsData = $this->apiController->sendCommand(
|
||||||
requestType: 'GET',
|
requestType: 'GET',
|
||||||
serverName: $panel->getName(),
|
serverName: $panel->getName(),
|
||||||
versionIP: 6,
|
versionIP: 6,
|
||||||
|
@ -490,7 +566,7 @@ class RequestController
|
||||||
command: 'dns/' . $domainID,
|
command: 'dns/' . $domainID,
|
||||||
serverType: 'panel');
|
serverType: 'panel');
|
||||||
} else {
|
} else {
|
||||||
$dnsData = $this->apiClient->sendCommand(
|
$dnsData = $this->apiController->sendCommand(
|
||||||
requestType: 'GET',
|
requestType: 'GET',
|
||||||
serverName: $panel->getName(),
|
serverName: $panel->getName(),
|
||||||
versionIP: 4,
|
versionIP: 4,
|
||||||
|
@ -531,7 +607,7 @@ class RequestController
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (!empty($panel->getAaaa())) {
|
if (!empty($panel->getAaaa())) {
|
||||||
$result = $this->apiClient->sendCommand(
|
$result = $this->apiController->sendCommand(
|
||||||
requestType: 'PUT',
|
requestType: 'PUT',
|
||||||
serverName: $panel->getName(),
|
serverName: $panel->getName(),
|
||||||
versionIP: 6,
|
versionIP: 6,
|
||||||
|
@ -541,7 +617,7 @@ class RequestController
|
||||||
body: json_decode(json: $newDnsData, associative: true)
|
body: json_decode(json: $newDnsData, associative: true)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
$result = $this->apiClient->sendCommand(
|
$result = $this->apiController->sendCommand(
|
||||||
requestType: 'PUT',
|
requestType: 'PUT',
|
||||||
serverName: $panel->getName(),
|
serverName: $panel->getName(),
|
||||||
versionIP: 4,
|
versionIP: 4,
|
||||||
|
@ -569,6 +645,11 @@ class RequestController
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param String $host
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
private function getDomain(string $host): string
|
private function getDomain(string $host): string
|
||||||
{
|
{
|
||||||
$host = strtolower(string: trim(string: $host));
|
$host = strtolower(string: trim(string: $host));
|
||||||
|
@ -583,89 +664,5 @@ class RequestController
|
||||||
return $host;
|
return $host;
|
||||||
}
|
}
|
||||||
|
|
||||||
// private function apiDoc(): void
|
|
||||||
// {
|
|
||||||
// $srcDir = dirname(path: __DIR__);
|
|
||||||
// $requestControllerPath = $srcDir . '/Controller/RequestController.php';
|
|
||||||
//
|
|
||||||
// $openApi = Generator::scan(sources: [$requestControllerPath]);
|
|
||||||
// header(header: 'Content-Type: application/json');
|
|
||||||
//
|
|
||||||
// echo $openApi->toJson();
|
|
||||||
// exit(0);
|
|
||||||
// }
|
|
||||||
|
|
||||||
public function __construct(
|
|
||||||
private readonly ApiClient $apiClient,
|
|
||||||
private readonly ApikeyRepository $apikeyRepository,
|
|
||||||
private readonly DomainController $domainController,
|
|
||||||
private readonly DomainRepository $domainRepository,
|
|
||||||
private readonly DynDNSRepository $dynDNSRepository,
|
|
||||||
private readonly PanelRepository $panelRepository,
|
|
||||||
private readonly ConfigController $configController,
|
|
||||||
private readonly EncryptionController $encryptionController,
|
|
||||||
private readonly Logger $logger)
|
|
||||||
{
|
|
||||||
$this->baseDir = dirname(path: __DIR__, levels: 2) . '/';
|
|
||||||
|
|
||||||
$this->status = '';
|
|
||||||
$this->response = '';
|
|
||||||
$this->message = '';
|
|
||||||
$this->result = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handleRequest(string $requestMethod, array $uri): void
|
|
||||||
{
|
|
||||||
$this->logger->debug(message: "Request: $requestMethod $uri[1]");
|
|
||||||
|
|
||||||
$this->requestMethod = strtoupper(string: $requestMethod);
|
|
||||||
$this->uri = $uri;
|
|
||||||
|
|
||||||
$command = $this->uri[2];
|
|
||||||
|
|
||||||
// use my router class from address book?
|
|
||||||
$routes = ['ping', 'version', 'domains', 'apidoc', 'dyndns'];
|
|
||||||
|
|
||||||
if (empty($command) || !(in_array(needle: $command, haystack: $routes))) {
|
|
||||||
$this->status = "404 Not Found";
|
|
||||||
$this->message = "Endpoint not found.";
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
match ($command) {
|
|
||||||
// server
|
|
||||||
'ping' => $this->handlePing(),
|
|
||||||
'version' => $this->getVersion(),
|
|
||||||
// domains
|
|
||||||
'domains' => $this->handleDomains(),
|
|
||||||
'dyndns' => $this->handleDynDNS(),
|
|
||||||
// 'apidoc' => $this->apiDoc(),
|
|
||||||
};
|
|
||||||
} catch (UnhandledMatchError) {
|
|
||||||
$this->status = '400 Bad Request';
|
|
||||||
$this->message = 'Unknown path: ' . $command;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// process api requests
|
|
||||||
if (!empty($this->status)) {
|
|
||||||
header(header: $_SERVER['SERVER_PROTOCOL'] . ' ' . $this->status);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($this->response)) {
|
|
||||||
echo json_encode(value: [
|
|
||||||
'response' => $this->response
|
|
||||||
]);
|
|
||||||
} elseif (!empty($this->result)) {
|
|
||||||
echo json_encode(value: $this->result);
|
|
||||||
} elseif (!empty($this->message)) {
|
|
||||||
echo json_encode(value: [
|
|
||||||
'message' => $this->message
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
echo json_encode(value: [
|
|
||||||
'message' => $this->message ?? 'Error: No message.'
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,19 +15,6 @@ class Security
|
||||||
private bool $hstsInclude;
|
private bool $hstsInclude;
|
||||||
private bool $hstsPreload;
|
private bool $hstsPreload;
|
||||||
|
|
||||||
private bool $isPreferHttps;
|
|
||||||
|
|
||||||
public function isPreferHttps(): bool
|
|
||||||
{
|
|
||||||
return $this->isPreferHttps;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setIsPreferHttps(bool $isPreferHttps): void
|
|
||||||
{
|
|
||||||
$this->isPreferHttps = $isPreferHttps;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -12,6 +12,7 @@ use SodiumException;
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#[OAT\Schema(schema: 'nameserver')]
|
#[OAT\Schema(schema: 'nameserver')]
|
||||||
|
|
||||||
class Nameserver
|
class Nameserver
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -30,10 +31,8 @@ class Nameserver
|
||||||
private string $aaaa = '',
|
private string $aaaa = '',
|
||||||
private readonly string $passphrase = '',
|
private readonly string $passphrase = '',
|
||||||
private string $apikey = '',
|
private string $apikey = '',
|
||||||
private string $apikeyPrefix = '',
|
private string $apikeyPrefix = '')
|
||||||
private string $self = 'no'
|
{
|
||||||
)
|
|
||||||
{
|
|
||||||
if ($this->passphrase) {
|
if ($this->passphrase) {
|
||||||
$configController = new ConfigController(quiet: false);
|
$configController = new ConfigController(quiet: false);
|
||||||
$encryptionController = new EncryptionController();
|
$encryptionController = new EncryptionController();
|
||||||
|
@ -51,16 +50,6 @@ class Nameserver
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSelf(): string
|
|
||||||
{
|
|
||||||
return $this->self;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setSelf(string $self): void
|
|
||||||
{
|
|
||||||
$this->self = $self;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
|
@ -78,90 +67,90 @@ class Nameserver
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
#[OAT\Property(type: 'string')]
|
#[OAT\Property(type: 'string')]
|
||||||
public function getA(): string
|
public function getA(): string
|
||||||
{
|
{
|
||||||
return $this->a;
|
return $this->a;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $a
|
* @param string $a
|
||||||
*/
|
*/
|
||||||
public function setA(string $a): void
|
public function setA(string $a): void
|
||||||
{
|
{
|
||||||
$this->a = $a;
|
$this->a = $a;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
#[OAT\Property(type: 'string')]
|
#[OAT\Property(type: 'string')]
|
||||||
public function getAaaa(): string
|
public function getAaaa(): string
|
||||||
{
|
{
|
||||||
return $this->aaaa;
|
return $this->aaaa;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $aaaa
|
* @param string $aaaa
|
||||||
*/
|
*/
|
||||||
public function setAaaa(string $aaaa): void
|
public function setAaaa(string $aaaa): void
|
||||||
{
|
{
|
||||||
$this->aaaa = $aaaa;
|
$this->aaaa = $aaaa;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
#[OAT\Property(type: 'string')]
|
#[OAT\Property(type: 'string')]
|
||||||
public function getApikey(): string
|
public function getApikey(): string
|
||||||
{
|
{
|
||||||
return $this->apikey;
|
return $this->apikey;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $apikey
|
* @param string $apikey
|
||||||
*/
|
*/
|
||||||
public function setApikey(string $apikey): void
|
public function setApikey(string $apikey): void
|
||||||
{
|
{
|
||||||
$this->apikey = $apikey;
|
$this->apikey = $apikey;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
#[OAT\Property(type: 'int')]
|
#[OAT\Property(type: 'int')]
|
||||||
public function getId(): int
|
public function getId(): int
|
||||||
{
|
{
|
||||||
return $this->id;
|
return $this->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $id
|
* @param int $id
|
||||||
*/
|
*/
|
||||||
public function setId(int $id): void
|
public function setId(int $id): void
|
||||||
{
|
{
|
||||||
$this->id = $id;
|
$this->id = $id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
#[OAT\Property(type: 'string')]
|
#[OAT\Property(type: 'string')]
|
||||||
public function getName(): string
|
public function getName(): string
|
||||||
{
|
{
|
||||||
return $this->name;
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $name
|
* @param string $name
|
||||||
*/
|
*/
|
||||||
public function setName(string $name): void
|
public function setName(string $name): void
|
||||||
{
|
{
|
||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
|
|
|
@ -5,7 +5,6 @@ namespace App\Provider;
|
||||||
//error_reporting(error_level: E_ALL);
|
//error_reporting(error_level: E_ALL);
|
||||||
|
|
||||||
|
|
||||||
use App\Utilities\Colors;
|
|
||||||
use PDO;
|
use PDO;
|
||||||
use PDOException;
|
use PDOException;
|
||||||
use PHPUnit\Exception;
|
use PHPUnit\Exception;
|
||||||
|
@ -18,39 +17,21 @@ class DatabaseConnection
|
||||||
{
|
{
|
||||||
private PDO $dbConnection;
|
private PDO $dbConnection;
|
||||||
|
|
||||||
const TABLE_PREFIX = '';
|
const TABLE_PREFIX = '';
|
||||||
const TABLE_DOMAINS = self::TABLE_PREFIX . "domains";
|
const TABLE_DOMAINS = self::TABLE_PREFIX . "domains";
|
||||||
const TABLE_NAMESERVERS = self::TABLE_PREFIX . "nameservers";
|
const TABLE_NAMESERVERS = self::TABLE_PREFIX . "nameservers";
|
||||||
const TABLE_PANELS = self::TABLE_PREFIX . "panels";
|
const TABLE_PANELS = self::TABLE_PREFIX . "panels";
|
||||||
const TABLE_APIKEYS = self::TABLE_PREFIX . "apikeys";
|
const TABLE_APIKEYS = self::TABLE_PREFIX . "apikeys";
|
||||||
const TABLE_DYNDNS = self::TABLE_PREFIX . "dyndns";
|
const TABLE_DYNDNS = self::TABLE_PREFIX . "dyndns";
|
||||||
const TABLE_SETTINGS = self::TABLE_PREFIX . 'config';
|
const TABLE_SETTINGS = self::TABLE_PREFIX . 'config';
|
||||||
|
|
||||||
public function __construct(private readonly ConfigController $configController)
|
public function __construct(private readonly ConfigController $configController)
|
||||||
{
|
{
|
||||||
$errors = [];
|
$dbHost = $this->configController->getConfig(configKey: 'dbHost');
|
||||||
if (!$dbHost = $this->configController->getConfig(configKey: 'dbHost')) {
|
$dbPort = $this->configController->getConfig(configKey: 'dbPort');
|
||||||
$errors[] = Colors::RED . 'Error: ' . Colors::DEFAULT . 'Missing config: dbHost' . PHP_EOL;
|
$dbDatabase = $this->configController->getConfig(configKey: 'dbDatabase');
|
||||||
}
|
$dbUser = $this->configController->getConfig(configKey: 'dbUser');
|
||||||
if (!$dbPort = $this->configController->getConfig(configKey: 'dbPort')) {
|
$dbPassword = $this->configController->getConfig(configKey: 'dbPassword');
|
||||||
$errors[] = Colors::RED . 'Error: ' . Colors::DEFAULT . 'Missing config: dbPort}' . PHP_EOL;
|
|
||||||
}
|
|
||||||
if (!$dbDatabase = $this->configController->getConfig(configKey: 'dbDatabase')) {
|
|
||||||
$errors[] = Colors::RED . 'Error: ' . Colors::DEFAULT . 'Missing config: dbDatabase' . PHP_EOL;
|
|
||||||
}
|
|
||||||
if (!$dbUser = $this->configController->getConfig(configKey: 'dbUser')) {
|
|
||||||
$errors[] = Colors::RED . 'Error: ' . Colors::DEFAULT . 'Missing config: dbUser' . PHP_EOL;
|
|
||||||
}
|
|
||||||
if (!$dbPassword = $this->configController->getConfig(configKey: 'dbPassword')) {
|
|
||||||
$errors[] = Colors::RED . 'Error: ' . Colors::DEFAULT . 'Missing config: dbPassword' . PHP_EOL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($errors) {
|
|
||||||
foreach ($errors as $error) {
|
|
||||||
echo $error;
|
|
||||||
}
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->dbConnection = new PDO(
|
$this->dbConnection = new PDO(
|
||||||
|
@ -73,8 +54,8 @@ class DatabaseConnection
|
||||||
$result = $statement->fetch();
|
$result = $statement->fetch();
|
||||||
if (empty($result)) {
|
if (empty($result)) {
|
||||||
// ALTER TABLE `domains` ADD `panel_id` INT NULL AFTER `id`;
|
// ALTER TABLE `domains` ADD `panel_id` INT NULL AFTER `id`;
|
||||||
echo Colors::RED . 'Error: ' . Colors::DEFAULT . 'Cannot find tables.' . PHP_EOL;
|
echo COLOR_RED . 'Error: ' . COLOR_DEFAULT . 'Cannot find tables.' . PHP_EOL;
|
||||||
echo 'Run the migration: ' . Colors::YELLOW . './bin/console migrations:migrate' . Colors::DEFAULT . PHP_EOL;
|
echo 'Run the migration: ' . COLOR_YELLOW . './bin/console migrations:migrate' . COLOR_DEFAULT . PHP_EOL;
|
||||||
}
|
}
|
||||||
} catch (PDOException $exception) {
|
} catch (PDOException $exception) {
|
||||||
echo $exception->getMessage() . PHP_EOL;
|
echo $exception->getMessage() . PHP_EOL;
|
||||||
|
@ -90,10 +71,9 @@ class DatabaseConnection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function generatePassword(int $length = 8): string
|
function generatePassword(int $length = 8): string
|
||||||
{
|
{
|
||||||
$chars = '23456789bcdfhkmnprstvzBCDFHJKLMNPRSTVZ';
|
$chars = '23456789bcdfhkmnprstvzBCDFHJKLMNPRSTVZ';
|
||||||
$shuffled = str_shuffle(string: $chars);
|
$shuffled = str_shuffle(string: $chars);
|
||||||
return mb_substr(string: $shuffled, start: 0, length: $length);
|
return mb_substr(string: $shuffled, start: 0, length: $length);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ class NameserverRepository
|
||||||
{
|
{
|
||||||
$nameservers = [];
|
$nameservers = [];
|
||||||
$sql = "
|
$sql = "
|
||||||
SELECT id, name, a, aaaa, apikey, apikey_prefix, self
|
SELECT id, name, a, aaaa, apikey, apikey_prefix
|
||||||
FROM " . DatabaseConnection::TABLE_NAMESERVERS . "
|
FROM " . DatabaseConnection::TABLE_NAMESERVERS . "
|
||||||
ORDER BY name";
|
ORDER BY name";
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ class NameserverRepository
|
||||||
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
|
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
|
||||||
$statement->execute();
|
$statement->execute();
|
||||||
while ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
|
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']);
|
$nameserver = new Nameserver(name: $result['name'], id: $result['id'], a: $result['a'], aaaa: $result['aaaa'], apikey: $result['apikey'], apikeyPrefix: $result['apikey_prefix']);
|
||||||
$nameservers[] = $nameserver;
|
$nameservers[] = $nameserver;
|
||||||
}
|
}
|
||||||
return $nameservers;
|
return $nameservers;
|
||||||
|
@ -50,7 +50,7 @@ class NameserverRepository
|
||||||
public function findFirst(): ?Nameserver
|
public function findFirst(): ?Nameserver
|
||||||
{
|
{
|
||||||
$sql = "
|
$sql = "
|
||||||
SELECT id, name, a, aaaa, apikey, apikey_prefix, self
|
SELECT id, name, a, aaaa, apikey, apikey_prefix
|
||||||
FROM " . DatabaseConnection::TABLE_NAMESERVERS . "
|
FROM " . DatabaseConnection::TABLE_NAMESERVERS . "
|
||||||
ORDER BY name";
|
ORDER BY name";
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ class NameserverRepository
|
||||||
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
|
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
|
||||||
$statement->execute();
|
$statement->execute();
|
||||||
$result = $statement->fetch(mode: PDO::FETCH_ASSOC);
|
$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']);
|
return new Nameserver(name: $result['name'], id: $result['id'], a: $result['a'], aaaa: $result['aaaa'], apikey: $result['apikey'], apikeyPrefix: $result['apikey_prefix']);
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
exit($e->getMessage());
|
exit($e->getMessage());
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ class NameserverRepository
|
||||||
public function findByID(int $id): ?Nameserver
|
public function findByID(int $id): ?Nameserver
|
||||||
{
|
{
|
||||||
$sql = "
|
$sql = "
|
||||||
SELECT id, name, a, aaaa, apikey, apikey_prefix, self
|
SELECT id, name, a, aaaa, apikey, apikey_prefix
|
||||||
FROM . " . DatabaseConnection::TABLE_NAMESERVERS . "
|
FROM . " . DatabaseConnection::TABLE_NAMESERVERS . "
|
||||||
WHERE id = :id";
|
WHERE id = :id";
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ class NameserverRepository
|
||||||
$statement->bindParam(param: ':id', var: $id);
|
$statement->bindParam(param: ':id', var: $id);
|
||||||
$statement->execute();
|
$statement->execute();
|
||||||
if ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
|
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']);
|
return new Nameserver(name: $result['name'], a: $result['a'], aaaa: $result['aaaa'], apikey: $result['apikey'], apikeyPrefix: $result['apikey_prefix']);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@ class NameserverRepository
|
||||||
public function findByName(string $name): ?Nameserver
|
public function findByName(string $name): ?Nameserver
|
||||||
{
|
{
|
||||||
$sql = "
|
$sql = "
|
||||||
SELECT id, name, a, aaaa, apikey, apikey_prefix, self
|
SELECT id, name, a, aaaa, apikey, apikey_prefix
|
||||||
FROM " . DatabaseConnection::TABLE_NAMESERVERS . "
|
FROM " . DatabaseConnection::TABLE_NAMESERVERS . "
|
||||||
WHERE name = :name";
|
WHERE name = :name";
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ class NameserverRepository
|
||||||
$statement->bindParam(param: ':name', var: $name);
|
$statement->bindParam(param: ':name', var: $name);
|
||||||
$statement->execute();
|
$statement->execute();
|
||||||
if ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
|
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']);
|
return new Nameserver(name: $result['name'], a: $result['a'], aaaa: $result['aaaa'], apikey: $result['apikey'], apikeyPrefix: $result['apikey_prefix']);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -131,17 +131,11 @@ class NameserverRepository
|
||||||
$aaaa = $nameserver->getAaaa();
|
$aaaa = $nameserver->getAaaa();
|
||||||
$apikey = $nameserver->getApikey();
|
$apikey = $nameserver->getApikey();
|
||||||
$apikeyPrefix = $nameserver->getApikeyPrefix();
|
$apikeyPrefix = $nameserver->getApikeyPrefix();
|
||||||
$self = $nameserver->getSelf();
|
|
||||||
if ($self === '') {
|
|
||||||
$selfValue = 'no';
|
|
||||||
} else {
|
|
||||||
$selfValue = $self;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$sql = "
|
$sql = "
|
||||||
INSERT INTO " . DatabaseConnection::TABLE_NAMESERVERS . " (name, a, aaaa, apikey, apikey_prefix, self)
|
INSERT INTO " . DatabaseConnection::TABLE_NAMESERVERS . " (name, a, aaaa, apikey, apikey_prefix)
|
||||||
VALUES (:name, :a, :aaaa, :apikey, :apikey_prefix, :self)";
|
VALUES (:name, :a, :aaaa, :apikey, :apikey_prefix)";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
|
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
|
||||||
|
@ -150,7 +144,6 @@ class NameserverRepository
|
||||||
$statement->bindParam(param: ':aaaa', var: $aaaa);
|
$statement->bindParam(param: ':aaaa', var: $aaaa);
|
||||||
$statement->bindParam(param: ':apikey', var: $apikey);
|
$statement->bindParam(param: ':apikey', var: $apikey);
|
||||||
$statement->bindParam(param: ':apikey_prefix', var: $apikeyPrefix);
|
$statement->bindParam(param: ':apikey_prefix', var: $apikeyPrefix);
|
||||||
$statement->bindParam(param: ':self', var: $selfValue);
|
|
||||||
$statement->execute();
|
$statement->execute();
|
||||||
|
|
||||||
return intval(value: $this->databaseConnection->getConnection()->lastInsertId());
|
return intval(value: $this->databaseConnection->getConnection()->lastInsertId());
|
||||||
|
@ -173,7 +166,6 @@ class NameserverRepository
|
||||||
$apikey = $nameserver->getApikey();
|
$apikey = $nameserver->getApikey();
|
||||||
$apikeyPrefix = $nameserver->getApikeyPrefix();
|
$apikeyPrefix = $nameserver->getApikeyPrefix();
|
||||||
$passphrase = $nameserver->getPassphrase();
|
$passphrase = $nameserver->getPassphrase();
|
||||||
$self =$nameserver->getSelf();
|
|
||||||
|
|
||||||
$current = $this->findByID(id: $id);
|
$current = $this->findByID(id: $id);
|
||||||
|
|
||||||
|
@ -193,10 +185,6 @@ class NameserverRepository
|
||||||
$apikeyPrefix = $current->getApikeyPrefix();
|
$apikeyPrefix = $current->getApikeyPrefix();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($self)) {
|
|
||||||
$self = $current->getSelf();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$sql = "
|
$sql = "
|
||||||
UPDATE " . DatabaseConnection::TABLE_NAMESERVERS . " SET
|
UPDATE " . DatabaseConnection::TABLE_NAMESERVERS . " SET
|
||||||
|
@ -204,8 +192,7 @@ class NameserverRepository
|
||||||
a = :a,
|
a = :a,
|
||||||
aaaa = :aaaa,
|
aaaa = :aaaa,
|
||||||
apikey = :apikey,
|
apikey = :apikey,
|
||||||
apikey_prefix = :apikey_prefix,
|
apikey_prefix = :apikey_prefix
|
||||||
self = :self
|
|
||||||
WHERE id = :id";
|
WHERE id = :id";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -216,7 +203,6 @@ class NameserverRepository
|
||||||
$statement->bindParam(param: 'aaaa', var: $aaaa);
|
$statement->bindParam(param: 'aaaa', var: $aaaa);
|
||||||
$statement->bindParam(param: 'apikey', var: $apikey);
|
$statement->bindParam(param: 'apikey', var: $apikey);
|
||||||
$statement->bindParam(param: 'apikey_prefix', var: $apikeyPrefix);
|
$statement->bindParam(param: 'apikey_prefix', var: $apikeyPrefix);
|
||||||
$statement->bindParam(param: 'self', var: $self);
|
|
||||||
$statement->execute();
|
$statement->execute();
|
||||||
try {
|
try {
|
||||||
sodium_memzero(string: $apikey);
|
sodium_memzero(string: $apikey);
|
||||||
|
|
|
@ -40,19 +40,13 @@ readonly class SettingsRepository
|
||||||
|
|
||||||
public function set(string $name, string $value): int
|
public function set(string $name, string $value): int
|
||||||
{
|
{
|
||||||
$currentSetting = $this->findByName($name);
|
|
||||||
if ($currentSetting !== false) {
|
$sql = "
|
||||||
$sql = "
|
INSERT INTO " . DatabaseConnection::TABLE_SETTINGS . " (name, value)
|
||||||
UPDATE " . DatabaseConnection::TABLE_SETTINGS . "
|
VALUES (:name, :value)
|
||||||
SET value = :value
|
ON DUPLICATE KEY UPDATE
|
||||||
WHERE name = :name
|
value = :value
|
||||||
";
|
";
|
||||||
} else {
|
|
||||||
$sql = "
|
|
||||||
INSERT INTO " . DatabaseConnection::TABLE_SETTINGS . " (id, name, value)
|
|
||||||
VALUES (UUID(), :name, :value)
|
|
||||||
";
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
|
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
|
||||||
|
|
|
@ -10,7 +10,6 @@ use App\Controller\DomainController;
|
||||||
use App\Controller\RequestController;
|
use App\Controller\RequestController;
|
||||||
use App\Repository\DomainRepository;
|
use App\Repository\DomainRepository;
|
||||||
use App\Repository\DynDNSRepository;
|
use App\Repository\DynDNSRepository;
|
||||||
use App\Service\ApiClient;
|
|
||||||
use DI\Container;
|
use DI\Container;
|
||||||
use DI\ContainerBuilder;
|
use DI\ContainerBuilder;
|
||||||
use DI\DependencyException;
|
use DI\DependencyException;
|
||||||
|
@ -24,71 +23,73 @@ use function DI\autowire;
|
||||||
|
|
||||||
class BindAPI
|
class BindAPI
|
||||||
{
|
{
|
||||||
private Logger $logger;
|
private Logger $logger;
|
||||||
private Container $container;
|
private Container $container;
|
||||||
|
|
||||||
public function __construct(bool $quiet)
|
/**
|
||||||
{
|
* @throws Exception
|
||||||
// init the logger
|
*/
|
||||||
$dateFormat = "Y:m:d H:i:s";
|
public function __construct(bool $quiet)
|
||||||
$output = "%datetime% %channel%.%level_name% %message%\n"; // %context% %extra%
|
{
|
||||||
$formatter = new LineFormatter(format: $output, dateFormat: $dateFormat);
|
// init the logger
|
||||||
|
$dateFormat = "Y:m:d H:i:s";
|
||||||
$debug = (new ConfigController(quiet: $quiet))->getConfig(configKey: 'debug');
|
$output = "%datetime% %channel%.%level_name% %message%\n"; // %context% %extra%
|
||||||
if ($debug) {
|
$formatter = new LineFormatter(format: $output, dateFormat: $dateFormat);
|
||||||
$stream = new StreamHandler(stream: dirname(path: __DIR__, levels: 2) . '/var/log/bindAPI.debug', level: Level::Debug);
|
|
||||||
} else {
|
$debug = (new ConfigController(quiet: $quiet))->getConfig(configKey: 'debug');
|
||||||
$stream = new StreamHandler(stream: dirname(path: __DIR__, levels: 2) . '/var/log/bindAPI.info', level: Level::Info);
|
if ($debug) {
|
||||||
}
|
$stream = new StreamHandler(stream: dirname(path: __DIR__, levels: 2) . '/bindAPI.log', level: Level::Debug);
|
||||||
$stream->setFormatter(formatter: $formatter);
|
} else {
|
||||||
|
$stream = new StreamHandler(stream: dirname(path: __DIR__, levels: 2) . '/bindAPI.log', level: Level::Info);
|
||||||
$this->logger = new Logger(name: 'bindAPI');
|
}
|
||||||
$this->logger->pushHandler(handler: $stream);
|
$stream->setFormatter(formatter: $formatter);
|
||||||
$this->logger->debug(message: 'bindAPI started');
|
|
||||||
|
$this->logger = new Logger(name: 'bindAPI');
|
||||||
|
$this->logger->pushHandler(handler: $stream);
|
||||||
$containerBuilder = new ContainerBuilder();
|
$this->logger->debug(message: 'bindAPI started');
|
||||||
$containerBuilder->addDefinitions([
|
|
||||||
ApiClient::class => autowire(),
|
|
||||||
ConfigController::class => autowire()
|
$containerBuilder = new ContainerBuilder();
|
||||||
|
$containerBuilder->addDefinitions([
|
||||||
|
ConfigController::class => autowire()
|
||||||
->constructorParameter(parameter: 'quiet', value: $quiet),
|
->constructorParameter(parameter: 'quiet', value: $quiet),
|
||||||
CLIController::class => autowire()
|
CLIController::class => autowire()
|
||||||
->constructorParameter(parameter: 'logger', value: $this->logger)
|
->constructorParameter(parameter: 'logger', value: $this->logger)
|
||||||
->constructorParameter(parameter: 'quiet', value: $quiet),
|
->constructorParameter(parameter: 'quiet', value: $quiet),
|
||||||
DomainController::class => autowire()
|
DomainController::class => autowire()
|
||||||
->constructorParameter(parameter: 'logger', value: $this->logger)
|
->constructorParameter(parameter: 'logger', value: $this->logger)
|
||||||
->constructorParameter(parameter: 'quiet', value: $quiet),
|
->constructorParameter(parameter: 'quiet', value: $quiet),
|
||||||
DomainRepository::class => autowire()
|
DomainRepository::class => autowire()
|
||||||
->constructorParameter(parameter: 'logger', value: $this->logger),
|
->constructorParameter(parameter: 'logger', value: $this->logger),
|
||||||
DynDnsRepository::class => autowire()
|
DynDnsRepository::class => autowire()
|
||||||
->constructorParameter(parameter: 'logger', value: $this->logger),
|
->constructorParameter(parameter: 'logger', value: $this->logger),
|
||||||
RequestController::class => autowire()
|
RequestController::class => autowire()
|
||||||
->constructorParameter(parameter: 'logger', value: $this->logger)
|
->constructorParameter(parameter: 'logger', value: $this->logger)
|
||||||
]);
|
]);
|
||||||
$this->container = $containerBuilder->build();
|
$this->container = $containerBuilder->build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws DependencyException
|
* @throws DependencyException
|
||||||
* @throws NotFoundException
|
* @throws NotFoundException
|
||||||
*/
|
*/
|
||||||
public function runCommand(array $arguments): void
|
public function runCommand(array $arguments): void
|
||||||
{
|
{
|
||||||
$this->logger->debug(message: 'runCommand()');
|
$this->logger->debug(message: 'runCommand()');
|
||||||
$cliController = $this->container->get(name: CLIController::class);
|
$cliController = $this->container->get(name: CLIController::class);
|
||||||
$cliController->runCommand(arguments: $arguments);
|
$cliController->runCommand(arguments: $arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws DependencyException
|
* @throws DependencyException
|
||||||
* @throws NotFoundException
|
* @throws NotFoundException
|
||||||
*/
|
*/
|
||||||
public function handleRequest(string $requestMethod, array $uri): void
|
public function handleRequest(string $requestMethod, array $uri): void
|
||||||
{
|
{
|
||||||
$this->logger->debug(message: 'handleRequest()');
|
$this->logger->debug(message: 'handleRequest()');
|
||||||
$requestController = $this->container->get(name: RequestController::class);
|
$requestController = $this->container->get(name: RequestController::class);
|
||||||
$requestController->handleRequest(requestMethod: $requestMethod, uri: $uri);
|
$requestController->handleRequest(requestMethod: $requestMethod, uri: $uri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use App\Service\BindAPI;
|
use App\Service\BindAPI;
|
||||||
use App\Utilities\Colors;
|
|
||||||
|
|
||||||
error_reporting(error_level: E_ALL & ~E_DEPRECATED);
|
error_reporting(error_level: E_ALL & ~E_DEPRECATED);
|
||||||
|
|
||||||
if (!is_file(filename: dirname(path: __DIR__, levels: 2) . '/vendor/autoload.php')) {
|
if (!is_file(filename: dirname(path: __DIR__, levels: 2) . '/vendor/autoload.php')) {
|
||||||
echo 'Required runtime components are missing. Try running "' . Colors::YELLOW . 'composer install' . Colors::DEFAULT . '".' . PHP_EOL;
|
exit('Required runtime components are missing. Try running "composer install".' . PHP_EOL);
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
require dirname(path: __DIR__, levels: 2) . '/vendor/autoload.php';
|
require dirname(path: __DIR__, levels: 2) . '/vendor/autoload.php';
|
||||||
|
@ -40,11 +38,11 @@ if (array_key_exists(key: 'v', array: $options) || array_key_exists(key: 'versio
|
||||||
$authorName = $authors[0]->name;
|
$authorName = $authors[0]->name;
|
||||||
$authorEmail = $authors[0]->email;
|
$authorEmail = $authors[0]->email;
|
||||||
|
|
||||||
echo "Name: $name" . PHP_EOL;
|
echo 'Name: $name' . PHP_EOL;
|
||||||
echo "Description: $description" . PHP_EOL;
|
echo 'Description: $description' . PHP_EOL;
|
||||||
echo "Version: $version" . PHP_EOL;
|
echo 'Version: $version' . PHP_EOL;
|
||||||
echo "Build Number: $buildNumber" . PHP_EOL;
|
echo 'Build Number: $buildNumber' . PHP_EOL;
|
||||||
echo "Author: $authorName ($authorEmail)" . PHP_EOL;
|
echo 'Author: $authorName ($authorEmail)' . PHP_EOL;
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
<?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";
|
|
||||||
}
|
|
Loading…
Reference in New Issue