diff --git a/cp/app/Controllers/RegistrarsController.php b/cp/app/Controllers/RegistrarsController.php index 17aad09..bada3d9 100644 --- a/cp/app/Controllers/RegistrarsController.php +++ b/cp/app/Controllers/RegistrarsController.php @@ -333,9 +333,15 @@ class RegistrarsController extends Controller [ $registrar['id'] ]); // Check if RegistrarOTE is not empty if (is_array($registrarOte) && !empty($registrarOte)) { - // Split the results into two groups - $firstHalf = array_slice($registrarOte, 0, 5); - $secondHalf = array_slice($registrarOte, 5); + // Calculate the total number of elements + $totalElements = count($registrarOte); + + // Calculate the size of the first half. If the total number is odd, add 1 to include the extra item in the first half. + $firstHalfSize = ceil($totalElements / 2); + + // Split the array into two halves + $firstHalf = array_slice($registrarOte, 0, $firstHalfSize); + $secondHalf = array_slice($registrarOte, $firstHalfSize); } else { // If RegistrarOTE is empty, set both halves to empty arrays $firstHalf = []; @@ -387,9 +393,15 @@ class RegistrarsController extends Controller [ $registrar['id'] ]); // Check if RegistrarOTE is not empty if (is_array($registrarOte) && !empty($registrarOte)) { - // Split the results into two groups - $firstHalf = array_slice($registrarOte, 0, 5); - $secondHalf = array_slice($registrarOte, 5); + // Calculate the total number of elements + $totalElements = count($registrarOte); + + // Calculate the size of the first half. If the total number is odd, add 1 to include the extra item in the first half. + $firstHalfSize = ceil($totalElements / 2); + + // Split the array into two halves + $firstHalf = array_slice($registrarOte, 0, $firstHalfSize); + $secondHalf = array_slice($registrarOte, $firstHalfSize); } else { // If RegistrarOTE is empty, set both halves to empty arrays $firstHalf = []; @@ -442,7 +454,7 @@ class RegistrarsController extends Controller $contacts = $db->select("SELECT * FROM registrar_contact WHERE registrar_id = ?", [ $registrar['id'] ]); - $ote = $db->select("SELECT * FROM registrar_ote WHERE registrar_id = ?", + $registrarOte = $db->select("SELECT * FROM registrar_ote WHERE registrar_id = ?", [ $registrar['id'] ]); $user_id = $db->selectValue("SELECT user_id FROM registrar_users WHERE registrar_id = ?", [ $registrar['id'] ]); @@ -450,6 +462,22 @@ class RegistrarsController extends Controller [ $user_id ]); $whitelist = $db->select("SELECT * FROM registrar_whitelist WHERE registrar_id = ?", [ $registrar['id'] ]); + // Check if RegistrarOTE is not empty + if (is_array($registrarOte) && !empty($registrarOte)) { + // Calculate the total number of elements + $totalElements = count($registrarOte); + + // Calculate the size of the first half. If the total number is odd, add 1 to include the extra item in the first half. + $firstHalfSize = ceil($totalElements / 2); + + // Split the array into two halves + $firstHalf = array_slice($registrarOte, 0, $firstHalfSize); + $secondHalf = array_slice($registrarOte, $firstHalfSize); + } else { + // If RegistrarOTE is empty, set both halves to empty arrays + $firstHalf = []; + $secondHalf = []; + } $_SESSION['registrars_to_update'] = [$registrar['clid']]; $_SESSION['registrars_user_email'] = [$user['email']]; @@ -457,7 +485,8 @@ class RegistrarsController extends Controller return view($response,'admin/registrars/updateRegistrar.twig', [ 'registrar' => $registrar, 'contacts' => $contacts, - 'ote' => $ote, + 'firstHalf' => $firstHalf, + 'secondHalf' => $secondHalf, 'user' => $user, 'whitelist' => $whitelist, 'currentUri' => $uri, @@ -970,7 +999,7 @@ class RegistrarsController extends Controller if ($registrar) { $contacts = $db->select("SELECT * FROM registrar_contact WHERE registrar_id = ?", [ $registrar['id'] ]); - $ote = $db->select("SELECT * FROM registrar_ote WHERE registrar_id = ?", + $registrarOte = $db->select("SELECT * FROM registrar_ote WHERE registrar_id = ?", [ $registrar['id'] ]); $user_id = $db->selectValue("SELECT user_id FROM registrar_users WHERE registrar_id = ?", [ $registrar['id'] ]); @@ -978,6 +1007,22 @@ class RegistrarsController extends Controller [ $user_id ]); $whitelist = $db->select("SELECT * FROM registrar_whitelist WHERE registrar_id = ?", [ $registrar['id'] ]); + // Check if RegistrarOTE is not empty + if (is_array($registrarOte) && !empty($registrarOte)) { + // Calculate the total number of elements + $totalElements = count($registrarOte); + + // Calculate the size of the first half. If the total number is odd, add 1 to include the extra item in the first half. + $firstHalfSize = ceil($totalElements / 2); + + // Split the array into two halves + $firstHalf = array_slice($registrarOte, 0, $firstHalfSize); + $secondHalf = array_slice($registrarOte, $firstHalfSize); + } else { + // If RegistrarOTE is empty, set both halves to empty arrays + $firstHalf = []; + $secondHalf = []; + } $_SESSION['registrars_to_update'] = [$registrar['clid']]; $_SESSION['registrars_user_email'] = [$user['email']]; @@ -985,7 +1030,8 @@ class RegistrarsController extends Controller return view($response,'admin/registrars/updateRegistrarUser.twig', [ 'registrar' => $registrar, 'contacts' => $contacts, - 'ote' => $ote, + 'firstHalf' => $firstHalf, + 'secondHalf' => $secondHalf, 'user' => $user, 'whitelist' => $whitelist, 'currentUri' => $uri, @@ -1000,5 +1046,119 @@ class RegistrarsController extends Controller return $response->withHeader('Location', '/registrars')->withStatus(302); } } + + public function oteCheck(Request $request, Response $response) + { + $db = $this->container->get('db'); + // Get the current URI + $uri = $request->getUri()->getPath(); + + if ($_SESSION["auth_roles"] != 0) { + $reg_id = $db->selectValue('SELECT registrar_id FROM registrar_users WHERE user_id = ?', [$_SESSION['auth_user_id']]); + + if (!$reg_id) { + return $response->withHeader('Location', '/dashboard')->withStatus(302); + } + } else { + $queryParams = $request->getQueryParams(); + $reg_id = $queryParams['reg'] ?? '1'; + } + + if (!preg_match('/^\d+$/', $reg_id)) { + $this->container->get('flash')->addMessage('error', 'Invalid registrar'); + return $response->withHeader('Location', '/dashboard')->withStatus(302); + } + + $registrar = $db->selectRow('SELECT id,name FROM registrar WHERE id = ?', + [ $reg_id ]); + + if ($registrar) { + $host = envi('DB_HOST'); + $dsn = "mysql:host=$host;dbname=registryTransaction;charset=utf8mb4"; + + $options = [ + \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, + \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC, + \PDO::ATTR_EMULATE_PREPARES => false, + ]; + + try { + $pdo = new \PDO($dsn, envi('DB_USERNAME'), envi('DB_PASSWORD'), $options); + $commands = $db->select('SELECT command FROM registrar_ote WHERE registrar_id = ? ORDER by command', + [ $registrar['id'] ]); + $commands = array_map(function($item) { + return $item['command']; + }, $commands); + + // Function to execute query and fetch first result + function fetchFirstMatchingResult($pdo, $sql, $params) { + $stmt = $pdo->prepare($sql); + $stmt->execute($params); + return $stmt->fetch(\PDO::FETCH_ASSOC); // Fetch the first row + } + + foreach ($commands as $command) { + if (strpos($command, ':') !== false) { + // Command contains ':', split and prepare query for obj_type and cmd + list($obj_type, $cmd) = explode(':', $command, 2); + $sql = "SELECT * FROM transaction_identifier WHERE registrar_id = ? AND obj_type = ? AND cmd = ? LIMIT 1"; + $params = [$reg_id, $obj_type, $cmd]; + } else { + // Command is a single word + $sql = "SELECT * FROM transaction_identifier WHERE registrar_id = ? AND cmd = ? LIMIT 1"; + $params = [$reg_id, $command]; + } + + $result = fetchFirstMatchingResult($pdo, $sql, $params); + + if ($result) { + $cmd = ''; + if (isset($result['cmd']) && ($result['cmd'] == 'login' || $result['cmd'] == 'logout')) { + $cmd = $result['cmd']; + } elseif (isset($result['obj_type']) && isset($result['cmd'])) { + $cmd = $result['obj_type'] . ':' . $result['cmd']; + } + if (isset($result['code']) && strpos(strval($result['code']), '1') === 0) { + $db->update( + 'registrar_ote', + [ + 'result' => 0 + ], + [ + 'registrar_id' => $reg_id, + 'command' => $cmd, + ] + ); + } else { + $db->update( + 'registrar_ote', + [ + 'result' => 1 + ], + [ + 'registrar_id' => $reg_id, + 'command' => $cmd, + ] + ); + } + } + } + } catch (\PDOException $e) { + $this->container->get('flash')->addMessage('error', 'Database failure: ' . $e->getMessage()); + return $response->withHeader('Location', '/registrar/view/'.$registrar['name'])->withStatus(302); + } catch (Exception $e) { + $this->container->get('flash')->addMessage('error', 'Database failure: ' . $e->getMessage()); + return $response->withHeader('Location', '/registrar/view/'.$registrar['name'])->withStatus(302); + } catch (Throwable $e) { + $this->container->get('flash')->addMessage('error', 'Database failure: ' . $e->getMessage()); + return $response->withHeader('Location', '/registrar/view/'.$registrar['name'])->withStatus(302); + } + + $this->container->get('flash')->addMessage('success', 'Registrar test results updated successfully'); + return $response->withHeader('Location', '/registrar/view/'.$registrar['name'])->withStatus(302); + } else { + return $response->withHeader('Location', '/dashboard')->withStatus(302); + } + } } \ No newline at end of file diff --git a/cp/resources/views/admin/registrars/updateRegistrar.twig b/cp/resources/views/admin/registrars/updateRegistrar.twig index 85fb3b2..ae8eca8 100644 --- a/cp/resources/views/admin/registrars/updateRegistrar.twig +++ b/cp/resources/views/admin/registrars/updateRegistrar.twig @@ -420,60 +420,43 @@
{{ __('Operational Test and Evaluation (OTE)') }}
-

- {{ __('Operational Test and Evaluation (OTE) assesses the functionality of EPP commands in a simulated environment, ensuring effective communication between the registrar\'s system and the registry. Below are key EPP commands and their test statuses:') }} -

+
+
+

+ {{ __('Successfully passing the Operational Test and Evaluation (OTE) is a mandatory requirement for registrars. The OTE process evaluates the interaction and compliance of the registrar\'s system with registry operations through a series of EPP command tests in a controlled environment. Below you can find the results of these essential EPP command tests for your account:') }} +

+
+
+ + + +
+
-
-
    -
  • - contact:create - {{ __('Pending') }} -
  • -
  • - domain:check - {{ __('Pending') }} -
  • -
  • - domain:info - {{ __('Pending') }} -
  • -
  • - domain:renew - {{ __('Pending') }} -
  • -
  • - domain:transfer - {{ __('Pending') }} -
  • -
+
    + {% for item in firstHalf %} +
  • + {{ item.command }} + + {% if item.result == 0 %}{{ __('Completed') }}{% elseif item.result == 9 %}{{ __('Pending') }}{% elseif item.result == 1 %}{{ __('Failed') }}{% endif %} + +
  • + {% endfor %} +
-
-
    -
  • - host:create - {{ __('Pending') }} -
  • -
  • - host:info - {{ __('Pending') }} -
  • -
  • - contact:update - {{ __('Pending') }} -
  • -
  • - domain:delete - {{ __('Pending') }} -
  • -
  • - poll:request - {{ __('Pending') }} -
  • -
+
    + {% for item in secondHalf %} +
  • + {{ item.command }} + + {% if item.result == 0 %}{{ __('Completed') }}{% elseif item.result == 9 %}{{ __('Pending') }}{% elseif item.result == 1 %}{{ __('Failed') }}{% endif %} + +
  • + {% endfor %} +
diff --git a/cp/resources/views/admin/registrars/updateRegistrarUser.twig b/cp/resources/views/admin/registrars/updateRegistrarUser.twig index a31d913..4703500 100644 --- a/cp/resources/views/admin/registrars/updateRegistrarUser.twig +++ b/cp/resources/views/admin/registrars/updateRegistrarUser.twig @@ -420,60 +420,43 @@
{{ __('Operational Test and Evaluation (OTE)') }}
-

- {{ __('Operational Test and Evaluation (OTE) assesses the functionality of EPP commands in a simulated environment, ensuring effective communication between the registrar\'s system and the registry. Below are key EPP commands and their test statuses:') }} -

+
+
+

+ {{ __('Successfully passing the Operational Test and Evaluation (OTE) is a mandatory requirement for registrars. The OTE process evaluates the interaction and compliance of the registrar\'s system with registry operations through a series of EPP command tests in a controlled environment. Below you can find the results of these essential EPP command tests for your account:') }} +

+
+
+ + + +
+
-
-
    -
  • - contact:create - {{ __('Pending') }} -
  • -
  • - domain:check - {{ __('Pending') }} -
  • -
  • - domain:info - {{ __('Pending') }} -
  • -
  • - domain:renew - {{ __('Pending') }} -
  • -
  • - domain:transfer - {{ __('Pending') }} -
  • -
+
    + {% for item in firstHalf %} +
  • + {{ item.command }} + + {% if item.result == 0 %}{{ __('Completed') }}{% elseif item.result == 9 %}{{ __('Pending') }}{% elseif item.result == 1 %}{{ __('Failed') }}{% endif %} + +
  • + {% endfor %} +
-
-
    -
  • - host:create - {{ __('Pending') }} -
  • -
  • - host:info - {{ __('Pending') }} -
  • -
  • - contact:update - {{ __('Pending') }} -
  • -
  • - domain:delete - {{ __('Pending') }} -
  • -
  • - poll:request - {{ __('Pending') }} -
  • -
+
    + {% for item in secondHalf %} +
  • + {{ item.command }} + + {% if item.result == 0 %}{{ __('Completed') }}{% elseif item.result == 9 %}{{ __('Pending') }}{% elseif item.result == 1 %}{{ __('Failed') }}{% endif %} + +
  • + {% endfor %} +
diff --git a/cp/resources/views/admin/registrars/viewRegistrar.twig b/cp/resources/views/admin/registrars/viewRegistrar.twig index 5c13dec..1e1605b 100644 --- a/cp/resources/views/admin/registrars/viewRegistrar.twig +++ b/cp/resources/views/admin/registrars/viewRegistrar.twig @@ -24,6 +24,7 @@
+ {% include 'partials/flash.twig' %}

{{ __('Registrar') }} {{ registrar.name }} {{ registrar.prefix }} {{ registrar.iana_id|default('N/A') }}

@@ -140,9 +141,18 @@
{{ __('Operational Test and Evaluation (OTE)') }}
-

- {{ __('Successfully passing the Operational Test and Evaluation (OTE) is a mandatory requirement for registrars. The OTE process evaluates the interaction and compliance of the registrar\'s system with registry operations through a series of EPP command tests in a controlled environment. Below you can find the results of these essential EPP command tests for your account:') }} -

+
+
+

+ {{ __('Successfully passing the Operational Test and Evaluation (OTE) is a mandatory requirement for registrars. The OTE process evaluates the interaction and compliance of the registrar\'s system with registry operations through a series of EPP command tests in a controlled environment. Below you can find the results of these essential EPP command tests for your account:') }} +

+
+
+ + + +
+
    diff --git a/cp/routes/web.php b/cp/routes/web.php index 124ddd8..147249a 100644 --- a/cp/routes/web.php +++ b/cp/routes/web.php @@ -93,6 +93,7 @@ $app->group('', function ($route) { $route->post('/registrar/update', RegistrarsController::class . ':updateRegistrarProcess')->setName('updateRegistrarProcess'); $route->get('/registrar', RegistrarsController::class .':registrar')->setName('registrar'); $route->map(['GET', 'POST'], '/registrar/edit', RegistrarsController::class .':editRegistrar')->setName('editRegistrar'); + $route->get('/registrar/check', RegistrarsController::class . ':oteCheck')->setName('oteCheck'); $route->get('/users', UsersController::class .':listUsers')->setName('listUsers'); diff --git a/database/registry.mariadb.sql b/database/registry.mariadb.sql index e9eebd1..909f1a8 100644 --- a/database/registry.mariadb.sql +++ b/database/registry.mariadb.sql @@ -853,6 +853,32 @@ INSERT INTO `registry`.`registrar_contact` (`id`, `registrar_id`, `type`, `title (5, 2, 'billing', NULL, 'Test', NULL, 'Name', '', '', NULL, NULL, 'Lviv', '', '', 'ua', '', NULL, 'test@namingo.org'), (6, 2, 'abuse', NULL, 'Test', NULL, 'Name', '', '', NULL, NULL, 'Lviv', '', '', 'ua', '', NULL, 'test@namingo.org'); +INSERT INTO `registry`.`registrar_ote` (`registrar_id`, `command`, `result`) VALUES +(1, 'contact:create', 9), +(1, 'domain:check', 9), +(1, 'domain:info', 9), +(1, 'domain:renew', 9), +(1, 'domain:transfer', 9), +(1, 'login', 9), +(1, 'host:create', 9), +(1, 'host:info', 9), +(1, 'contact:update', 9), +(1, 'domain:delete', 9), +(1, 'poll:request', 9), +(1, 'logout', 9), +(2, 'contact:create', 9), +(2, 'domain:check', 9), +(2, 'domain:info', 9), +(2, 'domain:renew', 9), +(2, 'domain:transfer', 9), +(2, 'login', 9), +(2, 'host:create', 9), +(2, 'host:info', 9), +(2, 'contact:update', 9), +(2, 'domain:delete', 9), +(2, 'poll:request', 9), +(2, 'logout', 9); + INSERT INTO `registry`.`users` (`email`, `password`, `username`, `status`, `verified`, `resettable`, `roles_mask`, `registered`, `last_login`, `force_logout`, `tfa_secret`, `tfa_enabled`, `auth_method`, `backup_codes`) VALUES ('info@leonet.com', '$argon2id$v=19$m=2048,t=4,p=4$STNMRDZRblBBVmRMeFhpdg$DpPnVyIHXJag11Pdi4J7xFAdtnmWfiNCgAjkIOpVtYk', 'leonet', 0, 1, 1, 4, 1, NULL, 0, NULL, 0, 'password', NULL), ('info@nordregistrar.com', '$argon2id$v=19$m=2048,t=4,p=4$STNMRDZRblBBVmRMeFhpdg$DpPnVyIHXJag11Pdi4J7xFAdtnmWfiNCgAjkIOpVtYk', 'nordregistrar', 0, 1, 1, 4, 1, NULL, 0, NULL, 0, 'password', NULL); diff --git a/database/registry.postgres.sql b/database/registry.postgres.sql index 99e377f..848b1de 100644 --- a/database/registry.postgres.sql +++ b/database/registry.postgres.sql @@ -780,6 +780,32 @@ INSERT INTO registrar_contact (id, registrar_id, type, title, first_name, middle ('6', '2', 'abuse', NULL, 'Test', NULL, 'Name', '', '', NULL, NULL, 'Lviv', '', '', 'ua', '', NULL, 'test@namingo.org'); SELECT setval('registrar_contact_id_seq', COALESCE((SELECT MAX(id) FROM registrar_contact), 0) + 1); +INSERT INTO registrar_ote (registrar_id, command, result) VALUES +('1', 'contact:create', '9'), +('1', 'domain:check', '9'), +('1', 'domain:info', '9'), +('1', 'domain:renew', '9'), +('1', 'domain:transfer', '9'), +('1', 'login', '9'), +('1', 'host:create', '9'), +('1', 'host:info', '9'), +('1', 'contact:update', '9'), +('1', 'domain:delete', '9'), +('1', 'poll:request', '9'), +('1', 'logout', '9'), +('2', 'contact:create', '9'), +('2', 'domain:check', '9'), +('2', 'domain:info', '9'), +('2', 'domain:renew', '9'), +('2', 'domain:transfer', '9'), +('2', 'login', '9'), +('2', 'host:create', '9'), +('2', 'host:info', '9'), +('2', 'contact:update', '9'), +('2', 'domain:delete', '9'), +('2', 'poll:request', '9'), +('2', 'logout', '9'); + INSERT INTO users (email, password, username, status, verified, resettable, roles_mask, registered, last_login, force_logout, tfa_secret, tfa_enabled, auth_method, backup_codes) VALUES ('info@leonet.com', '$argon2id$v=19$m=2048,t=4,p=4$STNMRDZRblBBVmRMeFhpdg$DpPnVyIHXJag11Pdi4J7xFAdtnmWfiNCgAjkIOpVtYk', 'leonet', 0, 1, 1, 4, 1, NULL, 0, NULL, false, 'password', NULL), ('info@nordregistrar.com', '$argon2id$v=19$m=2048,t=4,p=4$STNMRDZRblBBVmRMeFhpdg$DpPnVyIHXJag11Pdi4J7xFAdtnmWfiNCgAjkIOpVtYk', 'nordregistrar', 0, 1, 1, 4, 1, NULL, 0, NULL, false, 'password', NULL);