diff --git a/automation/config.php.dist b/automation/config.php.dist index 4cdfee5..2373dcb 100644 --- a/automation/config.php.dist +++ b/automation/config.php.dist @@ -13,12 +13,18 @@ return [ 'escrow_deposit_path' => '/opt/escrow', 'escrow_deleteXML' => false, 'escrow_RDEupload' => false, + 'escrow_BRDAupload' => false, 'escrow_keyPath' => '/opt/escrow/escrowKey.asc', + 'escrow_keyPath_brda' => '/opt/escrow/icann-brda-gpg.pub', 'escrow_privateKey' => '/opt/escrow/privatekey.asc', 'escrow_sftp_host' => 'your.sftp.server.com', 'escrow_sftp_username' => 'your_username', 'escrow_sftp_password' => 'your_password', 'escrow_sftp_remotepath' => '/path/on/sftp/server/', + 'brda_sftp_host' => 'your.sftp.server.com', + 'brda_sftp_username' => 'your_username', + 'brda_sftp_password' => 'your_password', + 'brda_sftp_remotepath' => '/path/on/sftp/server/', 'escrow_report_url' => 'https://ry-api.icann.org/report/', 'escrow_report_username' => 'your_username', 'escrow_report_password' => 'your_password', diff --git a/automation/escrow.php b/automation/escrow.php index 821b578..764867f 100644 --- a/automation/escrow.php +++ b/automation/escrow.php @@ -57,7 +57,7 @@ try { continue; } - // Starting the XML for this TLD + // Starting the escrow deposit for this TLD // Initializing XMLWriter $xml = new XMLWriter(); $xml->openMemory(); @@ -583,6 +583,306 @@ try { // Save the report file $reportFilePath = $c['escrow_deposit_path']."/{$tldname}_".date('Y-m-d')."_full_R{$finalDepositId}.rep"; file_put_contents($reportFilePath, $reps, LOCK_EX); + + // Start BRDA generation + $xml = new XMLWriter(); + $xml->openMemory(); + $xml->startDocument('1.0', 'UTF-8'); + + // Start the rde:deposit element with the necessary attributes + $xml->startElementNS('rde', 'deposit', 'urn:ietf:params:xml:ns:rde-1.0'); + $xml->writeAttribute('type', 'FULL'); + $paddedFinalDepositId = str_pad($finalDepositId, 3, '0', STR_PAD_LEFT); + $depositId = date('Ymd') . $paddedFinalDepositId; + $xml->writeAttribute('id', $depositId); + + // Add the necessary XML namespaces + $xml->writeAttributeNS('xmlns', 'domain', null, 'urn:ietf:params:xml:ns:domain-1.0'); + $xml->writeAttributeNS('xmlns', 'contact', null, 'urn:ietf:params:xml:ns:contact-1.0'); + $xml->writeAttributeNS('xmlns', 'secDNS', null, 'urn:ietf:params:xml:ns:secDNS-1.1'); + $xml->writeAttributeNS('xmlns', 'rdeHeader', null, 'urn:ietf:params:xml:ns:rdeHeader-1.0'); + $xml->writeAttributeNS('xmlns', 'rdeDomain', null, 'urn:ietf:params:xml:ns:rdeDomain-1.0'); + $xml->writeAttributeNS('xmlns', 'rdeHost', null, 'urn:ietf:params:xml:ns:rdeHost-1.0'); + $xml->writeAttributeNS('xmlns', 'rdeContact', null, 'urn:ietf:params:xml:ns:rdeContact-1.0'); + $xml->writeAttributeNS('xmlns', 'rdeRegistrar', null, 'urn:ietf:params:xml:ns:rdeRegistrar-1.0'); + $xml->writeAttributeNS('xmlns', 'rdeIDN', null, 'urn:ietf:params:xml:ns:rdeIDN-1.0'); + $xml->writeAttributeNS('xmlns', 'rdeNNDN', null, 'urn:ietf:params:xml:ns:rdeNNDN-1.0'); + $xml->writeAttributeNS('xmlns', 'rdeEppParams', null, 'urn:ietf:params:xml:ns:rdeEppParams-1.0'); + $xml->writeAttributeNS('xmlns', 'rdePolicy', null, 'urn:ietf:params:xml:ns:rdePolicy-1.0'); + $xml->writeAttributeNS('xmlns', 'epp', null, 'urn:ietf:params:xml:ns:epp-1.0'); + + $xml->startElementNS('rde', 'watermark', null); + $previousDayWatermark = date('Y-m-d', strtotime('-1 day')) . 'T23:59:59Z'; + $xml->text($previousDayWatermark); + $xml->endElement(); // End rde:watermark + + // Start the rde:rdeMenu element + $xml->startElementNS('rde', 'rdeMenu', null); + + // Write the rde:version element + $xml->startElementNS('rde', 'version', null); + $xml->text('1.0'); + $xml->endElement(); // End rde:version + + // Array of objURI values + $objURIs = [ + 'urn:ietf:params:xml:ns:rdeHeader-1.0', + 'urn:ietf:params:xml:ns:rdeContact-1.0', + 'urn:ietf:params:xml:ns:rdeHost-1.0', + 'urn:ietf:params:xml:ns:rdeDomain-1.0', + 'urn:ietf:params:xml:ns:rdeRegistrar-1.0', + 'urn:ietf:params:xml:ns:rdeIDN-1.0', + 'urn:ietf:params:xml:ns:rdeNNDN-1.0', + 'urn:ietf:params:xml:ns:rdeEppParams-1.0' + ]; + + // Write each rde:objURI element + foreach ($objURIs as $objURI) { + $xml->startElementNS('rde', 'objURI', null); + $xml->text($objURI); + $xml->endElement(); // End rde:objURI + } + + // End the rde:rdeMenu element + $xml->endElement(); // End rde:rdeMenu + + $xml->startElementNS('rde', 'contents', null); + + $xml->startElement('rdeHeader:header'); + $xml->writeElement('rdeHeader:tld', $tld['tld']); + + $xml->startElement('rdeHeader:count'); + $xml->writeAttribute('uri', 'urn:ietf:params:xml:ns:rdeDomain-1.0'); + $xml->text($domainCount); + $xml->endElement(); + + $xml->startElement('rdeHeader:count'); + $xml->writeAttribute('uri', 'urn:ietf:params:xml:ns:rdeHost-1.0'); + $xml->text($hostCount); + $xml->endElement(); + + $xml->startElement('rdeHeader:count'); + $xml->writeAttribute('uri', 'urn:ietf:params:xml:ns:rdeContact-1.0'); + $xml->text($contactCount); + $xml->endElement(); + + $xml->startElement('rdeHeader:count'); + $xml->writeAttribute('uri', 'urn:ietf:params:xml:ns:rdeRegistrar-1.0'); + $xml->text($registrarCount); + $xml->endElement(); + + $xml->startElement('rdeHeader:count'); + $xml->writeAttribute('uri', 'urn:ietf:params:xml:ns:rdeIDN-1.0'); + $xml->text('0'); + $xml->endElement(); + + $xml->startElement('rdeHeader:count'); + $xml->writeAttribute('uri', 'urn:ietf:params:xml:ns:rdeNNDN-1.0'); + $xml->text('0'); + $xml->endElement(); + + $xml->startElement('rdeHeader:count'); + $xml->writeAttribute('uri', 'urn:ietf:params:xml:ns:rdeEppParams-1.0'); + $xml->text('0'); + $xml->endElement(); + + $xml->endElement(); // Closing rdeHeader:header + + // Fetch domain details for this TLD + $stmt = $dbh->prepare("SELECT * FROM domain WHERE tldid = :tldid AND crdate <= :endOfPreviousDay"); + $stmt->bindParam(':tldid', $tld['id']); + $stmt->bindParam(':endOfPreviousDay', $endOfPreviousDay); + $stmt->execute(); + $domains = $stmt->fetchAll(); + + foreach ($domains as $domain) { + $xml->startElement('rdeDom:domain'); + $xml->writeElement('rdeDom:name', $domain['name']); + $xml->writeElement('rdeDom:roid', 'D' . $domain['id']); + $xml->writeElement('rdeDom:uName', $domain['name']); + $xml->writeElement('rdeDom:idnTableId', 'Latn'); + + // Fetch domain status + $stmt = $dbh->prepare("SELECT * FROM domain_status WHERE domain_id = :domain_id;"); + $stmt->bindParam(':domain_id', $domain['id']); + $stmt->execute(); + $status = $stmt->fetch(); + $xml->writeElement('rdeDom:status', $status['status'] ?? 'okk'); + + $xml->writeElement('rdeDom:registrant', $domain['registrant']); + + // Fetch domain contacts + $stmt = $dbh->prepare("SELECT * FROM domain_contact_map WHERE domain_id = :domain_id;"); + $stmt->bindParam(':domain_id', $domain['id']); + $stmt->execute(); + $domain_contacts = $stmt->fetchAll(); + foreach ($domain_contacts as $contact) { + $xml->startElement('rdeDom:contact'); + $xml->writeAttribute('type', $contact['type']); + $xml->text($contact['contact_id']); + $xml->endElement(); // Closing rdeDom:contact + } + + // Fetch domain hosts and incorporate into XML + $stmt = $dbh->prepare("SELECT host.name FROM domain_host_map JOIN host ON domain_host_map.host_id = host.id WHERE domain_host_map.domain_id = :domain_id;"); + $stmt->bindParam(':domain_id', $domain['id']); + $stmt->execute(); + $domain_hosts = $stmt->fetchAll(); + $xml->startElement('rdeDom:ns'); + foreach ($domain_hosts as $host) { + $xml->writeElement('domain:hostObj', $host['name']); + } + $xml->endElement(); // Closing rdeDom:ns + + $xml->writeElement('rdeDom:clID', $domain['clid']); + $xml->writeElement('rdeDom:crRr', $domain['crid']); + $crDate = DateTime::createFromFormat('Y-m-d H:i:s.v', $domain['crdate']); + $xml->writeElement('rdeDom:crDate', $crDate->format("Y-m-d\\TH:i:s.v\\Z")); + $exDate = DateTime::createFromFormat('Y-m-d H:i:s.v', $domain['exdate']); + $xml->writeElement('rdeDom:exDate', $exDate->format("Y-m-d\\TH:i:s.v\\Z")); + + $xml->endElement(); // Closing rdeDom:domain + } + + // Fetch and incorporate registrar details + $stmt = $dbh->prepare("SELECT * FROM registrar WHERE crdate <= :endOfPreviousDay"); + $stmt->bindParam(':endOfPreviousDay', $endOfPreviousDay); + $stmt->execute(); + $registrars = $stmt->fetchAll(); + + $xml->startElement('rdeRegistrar:registrar'); + foreach ($registrars as $registrar) { + $xml->writeElement('rdeRegistrar:id', $registrar['clid']); + $xml->writeElement('rdeRegistrar:name', $registrar['name']); + $xml->writeElement('rdeRegistrar:gurid', $registrar['iana_id']); + $xml->writeElement('rdeRegistrar:status', 'ok'); + + // Fetch and incorporate registrar contact details + $stmt = $dbh->prepare("SELECT * FROM registrar_contact WHERE registrar_id = :registrar_id;"); + $stmt->bindParam(':registrar_id', $registrar['id']); + $stmt->execute(); + $registrar_contacts = $stmt->fetchAll(); + + foreach ($registrar_contacts as $contact) { + $xml->startElement('rdeRegistrar:postalInfo'); + $xml->writeAttribute('type', 'int'); + $xml->startElement('rdeRegistrar:addr'); + $xml->writeElement('rdeRegistrar:street', $contact['street1']); + $xml->writeElement('rdeRegistrar:city', $contact['city']); + $xml->writeElement('rdeRegistrar:pc', $contact['pc']); + $xml->writeElement('rdeRegistrar:cc', $contact['cc']); + $xml->endElement(); // Closing rdeRegistrar:addr + $xml->endElement(); // Closing rdeRegistrar:postalInfo + + $xml->writeElement('rdeRegistrar:voice', $contact['voice']); + $xml->writeElement('rdeRegistrar:fax', $contact['fax']); + $xml->writeElement('rdeRegistrar:email', $contact['email']); + } + + $xml->writeElement('rdeRegistrar:url', $registrar['url']); + $xml->startElement('rdeRegistrar:whoisInfo'); + $xml->writeElement('rdeRegistrar:name', $registrar['whois_server']); + $xml->writeElement('rdeRegistrar:url', $registrar['whois_server']); + $xml->endElement(); // Closing rdeRegistrar:whoisInfo + + $crDate = DateTime::createFromFormat('Y-m-d H:i:s.v', $registrar['crdate']); + $xml->writeElement('rdeRegistrar:crDate', $crDate->format("Y-m-d\\TH:i:s.v\\Z")); + } + $xml->endElement(); // Closing rdeRegistrar:registrar + + // End the rde:contents element + $xml->endElement(); // End rde:contents + + $xml->endElement(); // Closing the 'rde:deposit' element + $deposit = $xml->outputMemory(); + + // Define the base name without the extension + $baseFileName = "{$tldname}_".date('Y-m-d')."_brda_S1_R{$finalDepositId}"; + + // XML, tar, and gzip filenames + $xmlFileName = $baseFileName . ".xml"; + $tarFileName = $baseFileName . ".tar"; + $gzipFileName = $baseFileName . ".tar.gz"; + + // Save the main XML file + file_put_contents($c['escrow_deposit_path']."/".$xmlFileName, $deposit, LOCK_EX); + + // Compress the XML file using tar + $phar = new PharData($c['escrow_deposit_path']."/".$tarFileName); + $phar->addFile($c['escrow_deposit_path']."/".$xmlFileName, $xmlFileName); + + // Compress the tar archive using gzip + $phar->compress(Phar::GZ); + + // Delete the original tar file + unlink($c['escrow_deposit_path']."/".$tarFileName); + + // Check if the $c['escrow_deleteXML'] variable is set to true and delete the original XML file + if ($c['escrow_deleteXML']) { + unlink($c['escrow_deposit_path']."/".$xmlFileName); + } + + // Initialize a GnuPG instance + $res = gnupg_init(); + + // Get information about the public key from its content + $publicKeyInfo = gnupg_import($res, file_get_contents($c['escrow_keyPath_brda'])); + $fingerprint = $publicKeyInfo['fingerprint']; + + // Check if the key is already in the keyring + $existingKeys = gnupg_keyinfo($res, $fingerprint); + + if (!$existingKeys) { + // If not, import the public key + gnupg_import($res, file_get_contents($c['escrow_keyPath_brda'])); + } + + // Read the .tar.gz file contents + $fileData = file_get_contents($c['escrow_deposit_path'] . "/" . $gzipFileName); + + // Add the encryption key + gnupg_addencryptkey($res, $fingerprint); + + // Encrypt the file data using the public key + $encryptedData = gnupg_encrypt($res, $fileData); + + if (!$encryptedData) { + $log->error('Error encrypting data: ' . gnupg_geterror($res)); + } + + // Save the encrypted data to a new file + file_put_contents($c['escrow_deposit_path'] . "/" . $baseFileName . ".ryde", $encryptedData); + + // Delete the original .tar.gz file + unlink($c['escrow_deposit_path'] . "/" . $gzipFileName); + + $encryptedFilePathBrda = $c['escrow_deposit_path'] . "/" . $baseFileName . ".ryde"; + + // Initialize the GnuPG extension + $gpg = new gnupg(); + $gpg->seterrormode(gnupg::ERROR_EXCEPTION); // throw exceptions on errors + + // Import your private key (if it's not already in the keyring) + $privateKeyData = file_get_contents($c['escrow_privateKey']); + $importResult = $gpg->import($privateKeyData); + + // Set the key to be used for signing + $privateKeyId = $importResult['fingerprint']; + $gpg->addsignkey($privateKeyId); + + // Specify the detached signature mode + $gpg->setsignmode(GNUPG_SIG_MODE_DETACH); + + // Sign the encrypted data + $encryptedData = file_get_contents($encryptedFilePathBrda); + $signature = $gpg->sign($encryptedData); + + // Save the signature to a .sig file + $signatureFilePathBrda = $c['escrow_deposit_path'] . '/' . pathinfo($encryptedFilePathBrda, PATHINFO_FILENAME) . '.sig'; + file_put_contents($signatureFilePathBrda, $signature); + + // Optionally, delete the encrypted file if you don't need it anymore + // unlink($encryptedFilePathBrda); if ($c['escrow_RDEupload']) { // Connect to the SFTP server @@ -644,6 +944,34 @@ try { } + if ($c['escrow_BRDAupload']) { + // Connect to the SFTP server + $sftp = new SFTP($c['brda_sftp_host']); + + // Login with username and password + if (!$sftp->login($c['brda_sftp_username'], $c['brda_sftp_password'])) { + $log->error('SFTP Login failed'); + } + + // Define the remote directory where you want to upload the files + $remoteDir = $c['brda_sftp_remotepath']; + + // Upload the files + $filesToUpload = [ + $encryptedFilePathBrda, + $signatureFilePathBrda + ]; + + foreach ($filesToUpload as $filePath) { + $remoteFile = $remoteDir . basename($filePath); + if (!$sftp->put($remoteFile, $filePath, SFTP::SOURCE_LOCAL_FILE)) { + $log->error('Failed to upload ' . basename($filePath)); + } else { + $log->info('Successfully uploaded ' . basename($filePath)); + } + } + } + $depositDate = date('Y-m-d'); $fileName = $c['escrow_deposit_path'] . "/" . $baseFileName . ".ryde"; $fileFormat = 'XML';