diff --git a/README.md b/README.md index b8398d7..4072a2b 100644 --- a/README.md +++ b/README.md @@ -15,11 +15,7 @@ We're on a mission to make **Namingo** the best it can be, and we need your expe We've completed the core development of Namingo, including WHOIS, DAS, EPP, RDAP servers, and control panel. The system handles 150,000 domains efficiently (on a VPS with 2 cores, 4GB of RAM, and a 100GB SSD) and has passed basic QA and security tests. -Current focuses: - -- Fee extension (RFC8748) integration. - -- Launch phase extension (RFC8334) implementation. +Our current focus is on implementing the launch phase extension as outlined in RFC8334. We're currently in the phase of external testing and are aware that there might be bugs or incomplete features in the project. If you're able to identify and fix any issues, we encourage you to submit a pull request. If you're not sure how to fix an issue, please don't hesitate to report it to us, and we'll work on addressing it. Your contributions and feedback are valuable in helping us improve Namingo. For any inquiries or suggestions, feel free to reach out. diff --git a/epp/src/EppWriter.php b/epp/src/EppWriter.php index 5655ccf..cf9a440 100644 --- a/epp/src/EppWriter.php +++ b/epp/src/EppWriter.php @@ -740,7 +740,6 @@ class EppWriter { $writer->endElement(); // End of 'fee:period' $writer->startElement('fee:fee'); - $writer->writeAttribute('description', 'Fee'); $writer->writeAttribute('refundable', 1); $writer->writeAttribute('grace-period', 'P5D'); $writer->text($fee['fee']); @@ -787,6 +786,27 @@ class EppWriter { $writer->writeElement('domain:exDate', $exDateFormatted); $writer->endElement(); // End of 'domain:creData' $writer->endElement(); // End of 'resData' + + if (isset($resp['fee_include']) && $resp['fee_include'] == true) { + $writer->startElement('extension'); + + $writer->startElement('fee:creData'); + $writer->writeAttribute('xmlns:fee', 'urn:ietf:params:xml:ns:epp:fee-1.0'); + + $writer->writeElement('fee:currency', 'USD'); + $writer->startElement('fee:fee'); + $writer->writeAttribute('refundable', 1); + $writer->writeAttribute('grace-period', 'P5D'); + $writer->text($resp['fee_price']); + $writer->endElement(); // End of 'fee:fee' + $writer->writeElement('fee:balance', $resp['fee_balance']); + $writer->writeElement('fee:creditLimit', $resp['fee_creditLimit']); + + $writer->endElement(); // End of 'fee:creData' + $writer->endElement(); // End of 'extension' + } + + } $this->_postamble($writer, $resp); diff --git a/epp/src/epp-check.php b/epp/src/epp-check.php index 242c94f..e0916bf 100644 --- a/epp/src/epp-check.php +++ b/epp/src/epp-check.php @@ -341,15 +341,29 @@ function processDomainCheck($conn, $db, $xml, $trans) { $returnValue = getDomainPrice($db, $domainName, $tld_id, $date_add, $commandName); $price = $returnValue['price']; - // Add to fee response array - $feeResponses[] = [ - 'command' => $commandName, - 'period' => $period, - 'period_unit' => $period_unit, - 'avail' => $domainEntry[1], - 'fee' => $price, - 'name' => $domainName, - ]; + $sth = $db->prepare("SELECT price FROM domain_restore_price WHERE tldid = ? LIMIT 1"); + $sth->execute([$tld_id]); + $restore_price = $sth->fetchColumn(); + + if ($commandName == 'restore') { + $feeResponses[] = [ + 'command' => $commandName, + 'period' => $period, + 'period_unit' => $period_unit, + 'avail' => $domainEntry[1], + 'fee' => $restore_price, + 'name' => $domainName, + ]; + } else { + $feeResponses[] = [ + 'command' => $commandName, + 'period' => $period, + 'period_unit' => $period_unit, + 'avail' => $domainEntry[1], + 'fee' => $price, + 'name' => $domainName, + ]; + } } else { $feeResponses[] = [ 'command' => $commandName, diff --git a/epp/src/epp-create.php b/epp/src/epp-create.php index 4625fdc..0137424 100644 --- a/epp/src/epp-create.php +++ b/epp/src/epp-create.php @@ -574,6 +574,11 @@ function processDomainCreate($conn, $db, $xml, $clid, $database_type, $trans) { $domainName = $xml->command->create->children('urn:ietf:params:xml:ns:domain-1.0')->create->name; $clTRID = (string) $xml->command->clTRID; + $extensionNode = $xml->command->extension; + if (isset($extensionNode)) { + $fee_create = $xml->xpath('//fee:create')[0] ?? null; + } + $parts = extractDomainAndTLD($domainName); $label = $parts['domain']; $domain_extension = $parts['tld']; @@ -1038,6 +1043,24 @@ function processDomainCreate($conn, $db, $xml, $clid, $database_type, $trans) { try { $db->beginTransaction(); + $response = []; + if (isset($fee_create)) { + $response['fee_fee'] = (string) $fee_create->children('urn:ietf:params:xml:ns:epp:fee-1.0')->fee; + + if ($response['fee_fee'] >= $price) { + $response['fee_currency'] = (string) $fee_create->children('urn:ietf:params:xml:ns:epp:fee-1.0')->currency; + $response['fee_price'] = $price; + $response['fee_balance'] = $registrar_balance; + $response['fee_creditLimit'] = $creditLimit; + $response['fee_include'] = true; + } else { + $response['fee_include'] = false; + $db->rollBack(); + sendEppError($conn, $db, 2004, "Provided fee is less than the server domain fee", $clTRID, $trans); + return; + } + } + $domainSql = "INSERT INTO domain (name,tldid,registrant,crdate,exdate,lastupdate,clid,crid,upid,trdate,trstatus,reid,redate,acid,acdate,rgpstatus,addPeriod) VALUES(:name, :tld_id, :registrant_id, CURRENT_TIMESTAMP(3), DATE_ADD(CURRENT_TIMESTAMP(3), INTERVAL :date_add MONTH), NULL, :registrar_id, :registrar_id, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'addPeriod', :date_add2)"; @@ -1072,10 +1095,12 @@ function processDomainCreate($conn, $db, $xml, $clid, $database_type, $trans) { // Data sanity checks // Validate keyTag if (!isset($keyTag) || !is_int($keyTag)) { + $db->rollBack(); sendEppError($conn, $db, 2005, 'Incomplete keyTag provided', $clTRID, $trans); return; } if ($keyTag < 0 || $keyTag > 65535) { + $db->rollBack(); sendEppError($conn, $db, 2006, 'Invalid keyTag provided', $clTRID, $trans); return; } @@ -1083,12 +1108,14 @@ function processDomainCreate($conn, $db, $xml, $clid, $database_type, $trans) { // Validate alg $validAlgorithms = [2, 3, 5, 6, 7, 8, 10, 13, 14, 15, 16]; if (!isset($alg) || !in_array($alg, $validAlgorithms)) { + $db->rollBack(); sendEppError($conn, $db, 2006, 'Invalid algorithm', $clTRID, $trans); return; } // Validate digestType and digest if (!isset($digestType) || !is_int($digestType)) { + $db->rollBack(); sendEppError($conn, $db, 2005, 'Invalid digestType', $clTRID, $trans); return; } @@ -1098,10 +1125,12 @@ function processDomainCreate($conn, $db, $xml, $clid, $database_type, $trans) { 4 => 96 // SHA-384 ]; if (!isset($validDigests[$digestType])) { + $db->rollBack(); sendEppError($conn, $db, 2006, 'Unsupported digestType', $clTRID, $trans); return; } if (!isset($digest) || strlen($digest) != $validDigests[$digestType] || !ctype_xdigit($digest)) { + $db->rollBack(); sendEppError($conn, $db, 2006, 'Invalid digest length or format', $clTRID, $trans); return; } @@ -1122,24 +1151,28 @@ function processDomainCreate($conn, $db, $xml, $clid, $database_type, $trans) { // Validate flags $validFlags = [256, 257]; if (isset($flags) && !in_array($flags, $validFlags)) { + $db->rollBack(); sendEppError($conn, $db, 2005, 'Invalid flags', $clTRID, $trans); return; } // Validate protocol if (isset($protocol) && $protocol != 3) { + $db->rollBack(); sendEppError($conn, $db, 2006, 'Invalid protocol', $clTRID, $trans); return; } // Validate algKeyData if (isset($algKeyData)) { + $db->rollBack(); sendEppError($conn, $db, 2005, 'Invalid algKeyData encoding', $clTRID, $trans); return; } // Validate pubKey if (isset($pubKey) && base64_encode(base64_decode($pubKey, true)) !== $pubKey) { + $db->rollBack(); sendEppError($conn, $db, 2005, 'Invalid pubKey encoding', $clTRID, $trans); return; } @@ -1329,7 +1362,7 @@ function processDomainCreate($conn, $db, $xml, $clid, $database_type, $trans) { $stmt->execute(); } $db->exec("UPDATE statistics SET created_domains = created_domains + 1 WHERE date = CURDATE()"); - + $db->commit(); } catch (Exception $e) { $db->rollBack(); @@ -1337,18 +1370,16 @@ function processDomainCreate($conn, $db, $xml, $clid, $database_type, $trans) { sendEppError($conn, $db, 2400, "Database failure: " . $e->getMessage(), $clTRID, $trans); } $svTRID = generateSvTRID(); - $response = [ - 'command' => 'create_domain', - 'resultCode' => 1000, - 'lang' => 'en-US', - 'message' => 'Command completed successfully', - 'name' => $domainName, - 'crDate' => $crdate, - 'exDate' => $exdate, - 'clTRID' => $clTRID, - 'svTRID' => $svTRID, - ]; - + $response['command'] = 'create_domain'; + $response['resultCode'] = 1000; + $response['lang'] = 'en-US'; + $response['message'] = 'Command completed successfully'; + $response['name'] = $domainName; + $response['crDate'] = $crdate; + $response['exDate'] = $exdate; + $response['clTRID'] = $clTRID; + $response['svTRID'] = $svTRID; + $epp = new EPP\EppWriter(); $xml = $epp->epp_writer($response); updateTransaction($db, 'create', 'domain', $domainName, 1000, 'Command completed successfully', $svTRID, $xml, $trans);