withHeader('Location', '/dashboard')->withStatus(302); } if ($request->getMethod() === 'POST') { // Retrieve POST data $data = $request->getParsedBody(); $db = $this->container->get('db'); $iso3166 = new ISO3166(); $countries = $iso3166->all(); $ipAddressValidator = v::when( v::arrayType()->notEmpty(), // Condition: If it's a non-empty array v::arrayType()->each(v::ip()), // Then: Each element must be a valid IP address v::equals('') // Else: Allow it to be an empty string ); $data['owner']['cc'] = strtoupper($data['owner']['cc']); $data['billing']['cc'] = strtoupper($data['billing']['cc']); $data['abuse']['cc'] = strtoupper($data['abuse']['cc']); $phoneValidator = v::regex('/^\+\d{1,3}\.\d{2,12}$/'); // Define validation for nested fields $contactValidator = [ v::key('first_name', v::stringType()->notEmpty()->length(1, 255), true), v::key('last_name', v::stringType()->notEmpty()->length(1, 255), true), v::key('org', v::optional(v::stringType()->length(1, 255)), false), v::key('street1', v::optional(v::stringType()), false), v::key('city', v::stringType()->notEmpty(), true), v::key('sp', v::optional(v::stringType()), false), v::key('pc', v::optional(v::stringType()), false), v::key('cc', v::countryCode(), true), v::key('voice', v::optional($phoneValidator), false), v::key('fax', v::optional(v::phone()), false), v::key('email', v::email(), true) ]; $validators = [ 'name' => v::stringType()->notEmpty()->length(1, 255), 'ianaId' => v::optional(v::positive()->length(1, 5)), 'email' => v::email(), 'owner' => v::optional(v::keySet(...$contactValidator)), 'billing' => v::optional(v::keySet(...$contactValidator)), 'abuse' => v::optional(v::keySet(...$contactValidator)), 'whoisServer' => v::domain(), 'rdapServer' => v::domain(), 'url' => v::url(), 'abuseEmail' => v::email(), 'abusePhone' => v::optional($phoneValidator), 'accountBalance' => v::numericVal(), 'creditLimit' => v::numericVal(), 'creditThreshold' => v::numericVal(), 'thresholdType' => v::in(['fixed', 'percent']), 'ipAddress' => v::optional($ipAddressValidator), 'user_name' => v::stringType()->notEmpty()->length(1, 255), 'user_email' => v::email(), 'eppPassword' => v::stringType()->notEmpty(), 'panelPassword' => v::stringType()->notEmpty(), ]; $errors = []; foreach ($validators as $field => $validator) { try { $validator->assert(isset($data[$field]) ? $data[$field] : []); } catch (\Respect\Validation\Exceptions\NestedValidationException $e) { $errors[$field] = $e->getMessages(); } } if (!empty($errors)) { // Handle errors $errorText = ''; foreach ($errors as $field => $messages) { $errorText .= ucfirst($field) . ' errors: ' . implode(', ', $messages) . '; '; } // Trim the final semicolon and space $errorText = rtrim($errorText, '; '); return view($response, 'admin/registrars/create.twig', [ 'countries' => $countries, 'error' => $errorText, ]); } $db->beginTransaction(); try { $currentDateTime = new \DateTime(); $crdate = $currentDateTime->format('Y-m-d H:i:s.v'); $characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; $randomPrefix = ''; for ($i = 0; $i < 2; $i++) { $randomPrefix .= $characters[rand(0, strlen($characters) - 1)]; } $currency = $_SESSION['_currency'] ?? 'USD'; $eppPassword = password_hash($data['eppPassword'], PASSWORD_ARGON2ID, ['memory_cost' => 1024 * 128, 'time_cost' => 6, 'threads' => 4]); if (empty($data['ianaId']) || !is_numeric($data['ianaId'])) { $data['ianaId'] = null; } $db->insert( 'registrar', [ 'name' => $data['name'], 'iana_id' => $data['ianaId'], 'clid' => $data['user_name'], 'pw' => $eppPassword, 'prefix' => $randomPrefix, 'email' => $data['email'], 'url' => $data['url'], 'whois_server' => $data['whoisServer'], 'rdap_server' => $data['rdapServer'], 'abuse_email' => $data['abuseEmail'], 'abuse_phone' => $data['abusePhone'], 'accountBalance' => $data['accountBalance'], 'creditLimit' => $data['creditLimit'], 'creditThreshold' => $data['creditThreshold'], 'thresholdType' => $data['thresholdType'], 'currency' => $currency, 'crdate' => $crdate, 'lastupdate' => $crdate ] ); $registrar_id = $db->getLastInsertId(); $db->exec( 'UPDATE registrar SET prefix = ? WHERE id = ?', [ 'R'.$registrar_id, $registrar_id ] ); $db->insert( 'registrar_contact', [ 'registrar_id' => $registrar_id, 'type' => 'owner', 'first_name' => $data['owner']['first_name'], 'last_name' => $data['owner']['last_name'], 'org' => $data['owner']['org'], 'street1' => $data['owner']['street1'], 'city' => $data['owner']['city'], 'sp' => $data['owner']['sp'], 'pc' => $data['owner']['pc'], 'cc' => strtolower($data['owner']['cc']), 'voice' => $data['owner']['voice'], 'email' => $data['owner']['email'] ] ); $db->insert( 'registrar_contact', [ 'registrar_id' => $registrar_id, 'type' => 'billing', 'first_name' => $data['billing']['first_name'], 'last_name' => $data['billing']['last_name'], 'org' => $data['billing']['org'], 'street1' => $data['billing']['street1'], 'city' => $data['billing']['city'], 'sp' => $data['billing']['sp'], 'pc' => $data['billing']['pc'], 'cc' => strtolower($data['billing']['cc']), 'voice' => $data['billing']['voice'], 'email' => $data['billing']['email'] ] ); $db->insert( 'registrar_contact', [ 'registrar_id' => $registrar_id, 'type' => 'abuse', 'first_name' => $data['abuse']['first_name'], 'last_name' => $data['abuse']['last_name'], 'org' => $data['abuse']['org'], 'street1' => $data['abuse']['street1'], 'city' => $data['abuse']['city'], 'sp' => $data['abuse']['sp'], 'pc' => $data['abuse']['pc'], 'cc' => strtolower($data['abuse']['cc']), 'voice' => $data['abuse']['voice'], 'email' => $data['abuse']['email'] ] ); if (!empty($data['ipAddress'])) { foreach ($data['ipAddress'] as $ip) { $db->insert( 'registrar_whitelist', [ 'registrar_id' => $registrar_id, 'addr' => $ip ] ); } } $panelPassword = password_hash($data['panelPassword'], PASSWORD_ARGON2ID, ['memory_cost' => 1024 * 128, 'time_cost' => 6, 'threads' => 4]); $db->insert( 'users', [ 'email' => $data['user_email'], 'password' => $panelPassword, 'username' => $data['user_name'], 'verified' => 1, 'roles_mask' => 4, 'registered' => \time() ] ); $user_id = $db->getLastInsertId(); $db->insert( 'registrar_users', [ 'registrar_id' => $registrar_id, 'user_id' => $user_id ] ); $eppCommands = [ 'contact:create', 'domain:check', 'domain:info', 'domain:renew', 'domain:transfer', 'host:create', 'host:info', 'contact:update', 'domain:delete', 'poll:request' ]; foreach ($eppCommands as $command) { $db->insert( 'registrar_ote', [ 'registrar_id' => $registrar_id, 'command' => $command, 'result' => '9', ] ); } $db->commit(); } catch (Exception $e) { $db->rollBack(); return view($response, 'admin/registrars/create.twig', [ 'error' => $e->getMessage(), 'countries' => $countries, ]); } return view($response,'admin/registrars/create.twig', [ 'registrar' => $data['name'], 'countries' => $countries, ]); } $iso3166 = new ISO3166(); $countries = $iso3166->all(); // Default view for GET requests or if POST data is not set return view($response,'admin/registrars/create.twig', [ 'countries' => $countries, ]); } public function viewRegistrar(Request $request, Response $response, $args) { $db = $this->container->get('db'); // Get the current URI $uri = $request->getUri()->getPath(); if ($args) { $args = trim(preg_replace('/\s+/', ' ', $args)); if (!preg_match('/^[a-zA-Z0-9\s]+$/', $args)) { $this->container->get('flash')->addMessage('error', 'Invalid registrar'); return $response->withHeader('Location', '/registrars')->withStatus(302); } $registrar = $db->selectRow('SELECT * FROM registrar WHERE name = ?', [ $args ]); if ($registrar) { // Check if the user is not an admin (assuming role 0 is admin) if ($_SESSION["auth_roles"] != 0) { $userRegistrars = $db->select('SELECT registrar_id FROM registrar_users WHERE user_id = ?', [$_SESSION['auth_user_id']]); // Assuming $userRegistrars returns an array of arrays, each containing 'registrar_id' $userRegistrarIds = array_column($userRegistrars, 'registrar_id'); // Check if the registrar's ID is in the user's list of registrar IDs if (!in_array($registrars['id'], $userRegistrarIds)) { // Redirect to the registrars view if the user is not authorized for this contact return $response->withHeader('Location', '/registrars')->withStatus(302); } } $registrarContact = $db->selectRow('SELECT * FROM registrar_contact WHERE registrar_id = ?', [ $registrar['id'] ]); $registrarOte = $db->select('SELECT * FROM registrar_ote WHERE registrar_id = ? ORDER by command', [ $registrar['id'] ]); $registrarUsers = $db->selectRow('SELECT user_id FROM registrar_users WHERE registrar_id = ?', [ $registrar['id'] ]); $userEmail = $db->selectRow('SELECT email FROM users WHERE id = ?', [ $registrarUsers['user_id'] ]); $registrarWhitelist = $db->select('SELECT addr FROM registrar_whitelist WHERE registrar_id = ?', [ $registrar['id'] ]); // Check if RegistrarOTE is not empty if (!empty($registrarOte)) { // Split the results into two groups $firstHalf = array_slice($registrarOte, 0, 5); $secondHalf = array_slice($registrarOte, 5); } else { // If RegistrarOTE is empty, set both halves to empty arrays $firstHalf = []; $secondHalf = []; } return view($response,'admin/registrars/viewRegistrar.twig', [ 'registrar' => $registrar, 'registrarContact' => $registrarContact, 'firstHalf' => $firstHalf, 'secondHalf' => $secondHalf, 'userEmail' => $userEmail, 'registrarWhitelist' => $registrarWhitelist, 'currentUri' => $uri ]); } else { // Contact does not exist, redirect to the registrars view return $response->withHeader('Location', '/registrars')->withStatus(302); } } else { // Redirect to the registrars view return $response->withHeader('Location', '/registrars')->withStatus(302); } } public function updateRegistrar(Request $request, Response $response, $args) { $db = $this->container->get('db'); $iso3166 = new ISO3166(); $countries = $iso3166->all(); // Get the current URI $uri = $request->getUri()->getPath(); if ($args) { $args = trim($args); if (!preg_match('/^[a-z0-9]+$/', $args)) { $this->container->get('flash')->addMessage('error', 'Invalid registrar'); return $response->withHeader('Location', '/registrars')->withStatus(302); } $registrar = $db->selectRow('SELECT * FROM registrar WHERE clid = ?', [ $args ]); if ($registrar) { // Check if the user is not an admin (assuming role 0 is admin) if ($_SESSION["auth_roles"] != 0) { return $response->withHeader('Location', '/dashboard')->withStatus(302); } $contacts = $db->select("SELECT * FROM registrar_contact WHERE registrar_id = ?", [ $registrar['id'] ]); $ote = $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'] ]); $user = $db->selectRow("SELECT email FROM users WHERE id = ?", [ $user_id ]); $whitelist = $db->select("SELECT * FROM registrar_whitelist WHERE registrar_id = ?", [ $registrar['id'] ]); return view($response,'admin/registrars/updateRegistrar.twig', [ 'registrar' => $registrar, 'contacts' => $contacts, 'ote' => $ote, 'user' => $user, 'whitelist' => $whitelist, 'currentUri' => $uri, 'countries' => $countries ]); } else { // Registrar does not exist, redirect to the registrars view return $response->withHeader('Location', '/registrars')->withStatus(302); } } else { // Redirect to the registrars view return $response->withHeader('Location', '/registrars')->withStatus(302); } } public function updateRegistrarProcess(Request $request, Response $response) { if ($_SESSION["auth_roles"] != 0) { return $response->withHeader('Location', '/dashboard')->withStatus(302); } if ($request->getMethod() === 'POST') { // Retrieve POST data $data = $request->getParsedBody(); $db = $this->container->get('db'); $registrar = $data['reg_clid'] ?? null; $data['ipAddress'] = array_filter($data['ipAddress']); $iso3166 = new ISO3166(); $countries = $iso3166->all(); $ipAddressValidator = v::when( v::arrayType()->notEmpty(), // Condition: If it's a non-empty array v::arrayType()->each(v::ip()), // Then: Each element must be a valid IP address v::equals('') // Else: Allow it to be an empty string ); $data['owner']['cc'] = strtoupper($data['owner']['cc']); $data['billing']['cc'] = strtoupper($data['billing']['cc']); $data['abuse']['cc'] = strtoupper($data['abuse']['cc']); $phoneValidator = v::regex('/^\+\d{1,3}\.\d{2,12}$/'); // Define validation for nested fields $contactValidator = [ v::key('first_name', v::stringType()->notEmpty()->length(1, 255), true), v::key('last_name', v::stringType()->notEmpty()->length(1, 255), true), v::key('org', v::optional(v::stringType()->length(1, 255)), false), v::key('street1', v::optional(v::stringType()), false), v::key('city', v::stringType()->notEmpty(), true), v::key('sp', v::optional(v::stringType()), false), v::key('pc', v::optional(v::stringType()), false), v::key('cc', v::countryCode(), true), v::key('voice', v::optional($phoneValidator), false), v::key('fax', v::optional(v::phone()), false), v::key('email', v::email(), true) ]; $validators = [ 'name' => v::stringType()->notEmpty()->length(1, 255), 'ianaId' => v::optional(v::positive()->length(1, 5)), 'email' => v::email(), 'owner' => v::optional(v::keySet(...$contactValidator)), 'billing' => v::optional(v::keySet(...$contactValidator)), 'abuse' => v::optional(v::keySet(...$contactValidator)), 'whoisServer' => v::domain(), 'rdapServer' => v::domain(), 'url' => v::url(), 'abuseEmail' => v::email(), 'abusePhone' => v::optional($phoneValidator), 'creditLimit' => v::numericVal(), 'creditThreshold' => v::numericVal(), 'ipAddress' => v::optional($ipAddressValidator) ]; $errors = []; foreach ($validators as $field => $validator) { try { $validator->assert(isset($data[$field]) ? $data[$field] : []); } catch (\Respect\Validation\Exceptions\NestedValidationException $e) { $errors[$field] = $e->getMessages(); } } if (!empty($errors)) { // Handle errors $errorText = ''; foreach ($errors as $field => $messages) { $errorText .= ucfirst($field) . ' errors: ' . implode(', ', $messages) . '; '; } // Trim the final semicolon and space $errorText = rtrim($errorText, '; '); $this->container->get('flash')->addMessage('error', $errorText); return $response->withHeader('Location', '/registrars')->withStatus(302); } $db->beginTransaction(); try { $currentDateTime = new \DateTime(); $update = $currentDateTime->format('Y-m-d H:i:s.v'); $characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; $randomPrefix = ''; for ($i = 0; $i < 2; $i++) { $randomPrefix .= $characters[rand(0, strlen($characters) - 1)]; } $currency = $_SESSION['_currency'] ?? 'USD'; if (empty($data['ianaId']) || !is_numeric($data['ianaId'])) { $data['ianaId'] = null; } $updateData = [ 'name' => $data['name'], 'iana_id' => $data['ianaId'], 'email' => $data['email'], 'url' => $data['url'], 'whois_server' => $data['whoisServer'], 'rdap_server' => $data['rdapServer'], 'abuse_email' => $data['abuseEmail'], 'abuse_phone' => $data['abusePhone'], 'creditLimit' => $data['creditLimit'], 'creditThreshold' => $data['creditThreshold'], 'currency' => $currency, 'lastupdate' => $crdate ]; if (!empty($data['eppPassword'])) { $eppPassword = password_hash($data['eppPassword'], PASSWORD_ARGON2ID, ['memory_cost' => 1024 * 128, 'time_cost' => 6, 'threads' => 4]); $updateData['pw'] = $eppPassword; } $db->update( 'registrar', $updateData, [ 'clid' => $registrar ] ); $registrar_id = $db->selectValue( 'SELECT id FROM registrar WHERE clid = ?', [$registrar] ); $db->update( 'registrar_contact', [ 'first_name' => $data['owner']['first_name'], 'last_name' => $data['owner']['last_name'], 'org' => $data['owner']['org'], 'street1' => $data['owner']['street1'], 'city' => $data['owner']['city'], 'sp' => $data['owner']['sp'], 'pc' => $data['owner']['pc'], 'cc' => strtolower($data['owner']['cc']), 'voice' => $data['owner']['voice'], 'email' => $data['owner']['email'] ], [ 'registrar_id' => $registrar_id, 'type' => 'owner' ] ); $db->update( 'registrar_contact', [ 'first_name' => $data['billing']['first_name'], 'last_name' => $data['billing']['last_name'], 'org' => $data['billing']['org'], 'street1' => $data['billing']['street1'], 'city' => $data['billing']['city'], 'sp' => $data['billing']['sp'], 'pc' => $data['billing']['pc'], 'cc' => strtolower($data['billing']['cc']), 'voice' => $data['billing']['voice'], 'email' => $data['billing']['email'] ], [ 'registrar_id' => $registrar_id, 'type' => 'billing' ] ); $db->update( 'registrar_contact', [ 'first_name' => $data['abuse']['first_name'], 'last_name' => $data['abuse']['last_name'], 'org' => $data['abuse']['org'], 'street1' => $data['abuse']['street1'], 'city' => $data['abuse']['city'], 'sp' => $data['abuse']['sp'], 'pc' => $data['abuse']['pc'], 'cc' => strtolower($data['abuse']['cc']), 'voice' => $data['abuse']['voice'], 'email' => $data['abuse']['email'] ], [ 'registrar_id' => $registrar_id, 'type' => 'abuse' ] ); if (!empty($data['ipAddress'])) { $db->delete( 'registrar_whitelist', [ 'registrar_id' => $registrar_id ] ); foreach ($data['ipAddress'] as $ip) { $db->insert( 'registrar_whitelist', [ 'registrar_id' => $registrar_id, 'addr' => $ip ] ); } } if ($data['panelPassword']) { $panelPassword = password_hash($data['panelPassword'], PASSWORD_ARGON2ID, ['memory_cost' => 1024 * 128, 'time_cost' => 6, 'threads' => 4]); $db->update( 'users', [ 'password' => $panelPassword, ], [ 'email' => $data['reg_email'] ] ); } $db->commit(); } catch (Exception $e) { $db->rollBack(); $this->container->get('flash')->addMessage('error', 'Database failure during update: ' . $e->getMessage()); return $response->withHeader('Location', '/registrar/update/'.$registrar)->withStatus(302); } $this->container->get('flash')->addMessage('success', 'Registrar ' . $data['name'] . ' has been updated successfully on ' . $update); return $response->withHeader('Location', '/registrar/update/'.$registrar)->withStatus(302); } } }