11<?php
22/**
3- * Indera EPP registrar module for FOSSBilling (https://fossbilling.org/)
3+ * EPP RFC Registrar Module for FOSSBilling (https://fossbilling.org/)
44 *
5- * Written in 2023 by Taras Kondratyuk (https://getpinga.com)
6- * Based on Generic EPP with DNSsec Registrar Module for WHMCS written in 2019 by Lilian Rudenco ([email protected] ) 7- * Work of Lilian Rudenco is under http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
5+ * Developed in 2024 by the Namingo Team (https://namingo.org, [email protected] ) 6+ *
7+ * This project is based on:
8+ * - The "Generic EPP with DNSsec Registrar Module for WHMCS," originally developed in 2019 by Lilian Rudenco ([email protected] ) 9+ * and licensed under the Academic Free License (AFL 3.0) - http://opensource.org/licenses/afl-3.0.php
810 *
911 * @license MIT
1012 */
13+
14+ use Symfony \Contracts \HttpClient \Exception \HttpExceptionInterface ;
15+
1116class Registrar_Adapter_EPP extends Registrar_AdapterAbstract
1217{
1318 public $ config = array ();
@@ -40,6 +45,11 @@ public function __construct($options)
4045 if (isset ($ options ['ssl_ca ' ])) {
4146 $ this ->config ['ssl_ca ' ] = $ options ['ssl_ca ' ];
4247 }
48+ if (isset ($ options ['min_data_set ' ])) {
49+ $ this ->config ['min_data_set ' ] = (bool )$ options ['min_data_set ' ];
50+ } else {
51+ $ this ->config ['min_data_set ' ] = false ;
52+ }
4353 if (isset ($ options ['use_tls_12 ' ])) {
4454 $ this ->config ['use_tls_12 ' ] = (bool )$ options ['use_tls_12 ' ];
4555 } else {
@@ -98,11 +108,16 @@ public static function getConfig()
98108 'required ' => false ,
99109 ),
100110 ),
111+ 'min_data_set ' => array ('radio ' , array (
112+ 'multiOptions ' => array ('1 ' =>'Yes ' , '0 ' =>'No ' ),
113+ 'label ' => 'Enable Minimum Data Set ' ,
114+ ),
115+ ),
101116 'use_tls_12 ' => array ('radio ' , array (
102- 'multiOptions ' => array ('1 ' =>'Yes ' , '0 ' =>'No ' ),
103- 'label ' => 'Use TLS 1.2 instead of 1.3 ' ,
104- ),
105- ),
117+ 'multiOptions ' => array ('1 ' =>'Yes ' , '0 ' =>'No ' ),
118+ 'label ' => 'Use TLS 1.2 instead of 1.3 ' ,
119+ ),
120+ ),
106121 ),
107122 );
108123 }
@@ -264,6 +279,7 @@ public function modifyNs(Registrar_Domain $domain)
264279 $ return = array (
265280 'error ' => $ e ->getMessage ()
266281 );
282+ throw new Registrar_Exception ('Error: ' . $ e ->getMessage ());
267283 }
268284
269285 if (!empty ($ s )) {
@@ -479,73 +495,75 @@ public function registerDomain(Registrar_Domain $domain)
479495 }
480496
481497 if (0 == (int )$ r ->cd [0 ]->name ->attributes ()->avail ) {
482- throw new exception ($ r ->cd [0 ]->name . ' ' . $ reason );
498+ throw new Registrar_Exception ($ r ->cd [0 ]->name . ' ' . $ reason );
483499 }
484500
485- // contact:create
486- $ from = $ to = array ();
487- $ from [] = '/{{ id }}/ ' ;
488- $ c_id = strtoupper ($ this ->generateRandomString ());
489- $ to [] = $ c_id ;
490- $ from [] = '/{{ name }}/ ' ;
491- $ to [] = htmlspecialchars ($ client ->getFirstName () . ' ' . $ client ->getLastName ());
492- $ from [] = '/{{ org }}/ ' ;
493- $ to [] = htmlspecialchars ($ client ->getCompany ());
494- $ from [] = '/{{ street1 }}/ ' ;
495- $ to [] = htmlspecialchars ($ client ->getAddress1 ());
496- $ from [] = '/{{ city }}/ ' ;
497- $ to [] = htmlspecialchars ($ client ->getCity ());
498- $ from [] = '/{{ state }}/ ' ;
499- $ to [] = htmlspecialchars ($ client ->getState ());
500- $ from [] = '/{{ postcode }}/ ' ;
501- $ to [] = htmlspecialchars ($ client ->getZip ());
502- $ from [] = '/{{ country }}/ ' ;
503- $ to [] = htmlspecialchars ($ client ->getCountry ());
504- $ from [] = '/{{ phonenumber }}/ ' ;
505- $ to [] = htmlspecialchars ('+ ' .$ client ->getTelCc ().'. ' .$ client ->getTel ());
506- $ from [] = '/{{ email }}/ ' ;
507- $ to [] = htmlspecialchars ($ client ->getEmail ());
508- $ from [] = '/{{ authInfo }}/ ' ;
509- $ to [] = htmlspecialchars ($ this ->generateObjectPW ());
510- $ from [] = '/{{ clTRID }}/ ' ;
511- $ clTRID = str_replace ('. ' , '' , round (microtime (1 ), 3 ));
512- $ to [] = htmlspecialchars ($ this ->config ['registrarprefix ' ] . '-contact-create- ' . $ clTRID );
513- $ xml = preg_replace ($ from , $ to , '<?xml version="1.0" encoding="UTF-8" standalone="no"?>
514- <epp xmlns="urn:ietf:params:xml:ns:epp-1.0"
515- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
516- xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
517- <command>
518- <create>
519- <contact:create
520- xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
521- <contact:id>{{ id }}</contact:id>
522- <contact:postalInfo type="int">
523- <contact:name>{{ name }}</contact:name>
524- <contact:org>{{ org }}</contact:org>
525- <contact:addr>
526- <contact:street>{{ street1 }}</contact:street>
527- <contact:street></contact:street>
528- <contact:street></contact:street>
529- <contact:city>{{ city }}</contact:city>
530- <contact:sp>{{ state }}</contact:sp>
531- <contact:pc>{{ postcode }}</contact:pc>
532- <contact:cc>{{ country }}</contact:cc>
533- </contact:addr>
534- </contact:postalInfo>
535- <contact:voice>{{ phonenumber }}</contact:voice>
536- <contact:fax></contact:fax>
537- <contact:email>{{ email }}</contact:email>
538- <contact:authInfo>
539- <contact:pw>{{ authInfo }}</contact:pw>
540- </contact:authInfo>
541- </contact:create>
542- </create>
543- <clTRID>{{ clTRID }}</clTRID>
544- </command>
545- </epp> ' );
546- $ r = $ this ->write ($ xml , __FUNCTION__ );
547- $ r = $ r ->response ->resData ->children ('urn:ietf:params:xml:ns:contact-1.0 ' )->creData ;
548- $ contacts = $ r ->id ;
501+ if ($ this ->config ['min_data_set ' ] === false ) {
502+ // contact:create
503+ $ from = $ to = array ();
504+ $ from [] = '/{{ id }}/ ' ;
505+ $ c_id = strtoupper ($ this ->generateRandomString ());
506+ $ to [] = $ c_id ;
507+ $ from [] = '/{{ name }}/ ' ;
508+ $ to [] = htmlspecialchars ($ client ->getFirstName () . ' ' . $ client ->getLastName ());
509+ $ from [] = '/{{ org }}/ ' ;
510+ $ to [] = htmlspecialchars ($ client ->getCompany ());
511+ $ from [] = '/{{ street1 }}/ ' ;
512+ $ to [] = htmlspecialchars ($ client ->getAddress1 ());
513+ $ from [] = '/{{ city }}/ ' ;
514+ $ to [] = htmlspecialchars ($ client ->getCity ());
515+ $ from [] = '/{{ state }}/ ' ;
516+ $ to [] = htmlspecialchars ($ client ->getState ());
517+ $ from [] = '/{{ postcode }}/ ' ;
518+ $ to [] = htmlspecialchars ($ client ->getZip ());
519+ $ from [] = '/{{ country }}/ ' ;
520+ $ to [] = htmlspecialchars ($ client ->getCountry ());
521+ $ from [] = '/{{ phonenumber }}/ ' ;
522+ $ to [] = htmlspecialchars ('+ ' .$ client ->getTelCc ().'. ' .$ client ->getTel ());
523+ $ from [] = '/{{ email }}/ ' ;
524+ $ to [] = htmlspecialchars ($ client ->getEmail ());
525+ $ from [] = '/{{ authInfo }}/ ' ;
526+ $ to [] = htmlspecialchars ($ this ->generateObjectPW ());
527+ $ from [] = '/{{ clTRID }}/ ' ;
528+ $ clTRID = str_replace ('. ' , '' , round (microtime (1 ), 3 ));
529+ $ to [] = htmlspecialchars ($ this ->config ['registrarprefix ' ] . '-contact-create- ' . $ clTRID );
530+ $ xml = preg_replace ($ from , $ to , '<?xml version="1.0" encoding="UTF-8" standalone="no"?>
531+ <epp xmlns="urn:ietf:params:xml:ns:epp-1.0"
532+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
533+ xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
534+ <command>
535+ <create>
536+ <contact:create
537+ xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
538+ <contact:id>{{ id }}</contact:id>
539+ <contact:postalInfo type="int">
540+ <contact:name>{{ name }}</contact:name>
541+ <contact:org>{{ org }}</contact:org>
542+ <contact:addr>
543+ <contact:street>{{ street1 }}</contact:street>
544+ <contact:street></contact:street>
545+ <contact:street></contact:street>
546+ <contact:city>{{ city }}</contact:city>
547+ <contact:sp>{{ state }}</contact:sp>
548+ <contact:pc>{{ postcode }}</contact:pc>
549+ <contact:cc>{{ country }}</contact:cc>
550+ </contact:addr>
551+ </contact:postalInfo>
552+ <contact:voice>{{ phonenumber }}</contact:voice>
553+ <contact:fax></contact:fax>
554+ <contact:email>{{ email }}</contact:email>
555+ <contact:authInfo>
556+ <contact:pw>{{ authInfo }}</contact:pw>
557+ </contact:authInfo>
558+ </contact:create>
559+ </create>
560+ <clTRID>{{ clTRID }}</clTRID>
561+ </command>
562+ </epp> ' );
563+ $ r = $ this ->write ($ xml , __FUNCTION__ );
564+ $ r = $ r ->response ->resData ->children ('urn:ietf:params:xml:ns:contact-1.0 ' )->creData ;
565+ $ contacts = $ r ->id ;
566+ }
549567
550568 //host create
551569 foreach (['ns1 ' , 'ns2 ' , 'ns3 ' , 'ns4 ' ] as $ ns ) {
@@ -635,21 +653,33 @@ public function registerDomain(Registrar_Domain $domain)
635653 $ from [] = '/{{ ns4 }}/ ' ;
636654 $ to [] = '' ;
637655 }
638- $ from [] = '/{{ cID_1 }}/ ' ;
639- $ to [] = htmlspecialchars ($ contacts );
640- $ from [] = '/{{ cID_2 }}/ ' ;
641- $ to [] = htmlspecialchars ($ contacts );
642- $ from [] = '/{{ cID_3 }}/ ' ;
643- $ to [] = htmlspecialchars ($ contacts );
644- $ from [] = '/{{ cID_4 }}/ ' ;
645- $ to [] = htmlspecialchars ($ contacts );
656+ if ($ this ->config ['min_data_set ' ] === false ) {
657+ $ from [] = '/{{ cID_1 }}/ ' ;
658+ $ to [] = htmlspecialchars ($ contacts );
659+ $ from [] = '/{{ cID_2 }}/ ' ;
660+ $ to [] = htmlspecialchars ($ contacts );
661+ $ from [] = '/{{ cID_3 }}/ ' ;
662+ $ to [] = htmlspecialchars ($ contacts );
663+ $ from [] = '/{{ cID_4 }}/ ' ;
664+ $ to [] = htmlspecialchars ($ contacts );
665+ }
646666 $ from [] = '/{{ authInfo }}/ ' ;
647667 $ to [] = htmlspecialchars ($ this ->generateObjectPW ());
648668 $ from [] = '/{{ clTRID }}/ ' ;
649669 $ clTRID = str_replace ('. ' , '' , round (microtime (1 ), 3 ));
650670 $ to [] = htmlspecialchars ($ this ->config ['registrarprefix ' ] . '-domain-create- ' . $ clTRID );
651671 $ from [] = "/<\w+:\w+>\s*<\/\w+:\w+>\s+/ims " ;
652672 $ to [] = '' ;
673+
674+ $ contact_section = '' ;
675+ if ($ this ->config ['min_data_set ' ] === false ) {
676+ $ contact_section = '
677+ <domain:registrant>{{ cID_1 }}</domain:registrant>
678+ <domain:contact type="admin">{{ cID_2 }}</domain:contact>
679+ <domain:contact type="tech">{{ cID_3 }}</domain:contact>
680+ <domain:contact type="billing">{{ cID_4 }}</domain:contact> ' ;
681+ }
682+
653683 $ xml = preg_replace ($ from , $ to , '<?xml version="1.0" encoding="UTF-8" standalone="no"?>
654684 <epp xmlns="urn:ietf:params:xml:ns:epp-1.0"
655685 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -665,11 +695,7 @@ public function registerDomain(Registrar_Domain $domain)
665695 <domain:hostObj>{{ ns2 }}</domain:hostObj>
666696 <domain:hostObj>{{ ns3 }}</domain:hostObj>
667697 <domain:hostObj>{{ ns4 }}</domain:hostObj>
668- </domain:ns>
669- <domain:registrant>{{ cID_1 }}</domain:registrant>
670- <domain:contact type="admin">{{ cID_2 }}</domain:contact>
671- <domain:contact type="tech">{{ cID_3 }}</domain:contact>
672- <domain:contact type="billing">{{ cID_4 }}</domain:contact>
698+ </domain:ns> ' . $ contact_section . '
673699 <domain:authInfo>
674700 <domain:pw>{{ authInfo }}</domain:pw>
675701 </domain:authInfo>
@@ -685,6 +711,7 @@ public function registerDomain(Registrar_Domain $domain)
685711 $ return = array (
686712 'error ' => $ e ->getMessage ()
687713 );
714+ throw new Registrar_Exception ('Error: ' . $ e ->getMessage ());
688715 }
689716
690717 if (!empty ($ s )) {
@@ -769,6 +796,11 @@ public function renewDomain(Registrar_Domain $domain)
769796 public function modifyContact (Registrar_Domain $ domain )
770797 {
771798 $ this ->getLog ()->debug ('Updating contact info: ' . $ domain ->getName ());
799+
800+ if ($ this ->config ['min_data_set ' ] === true ) {
801+ throw new Registrar_Exception ("Contact update not possible as the Minimum Data Set is enabled. " );
802+ }
803+
772804 $ client = $ domain ->getContactRegistrar ();
773805 $ return = array ();
774806 try {
@@ -1330,7 +1362,7 @@ public function connect()
13301362 $ this ->socket = stream_socket_client ($ tls .":// {$ host }: {$ port }" , $ errno , $ errmsg , $ timeout , STREAM_CLIENT_CONNECT , $ context );
13311363
13321364 if (!$ this ->socket ) {
1333- throw new exception ("Cannot connect to server ' {$ host }': {$ errmsg }" );
1365+ throw new Registrar_Exception ("Cannot connect to server ' {$ host }': {$ errmsg }" );
13341366 }
13351367
13361368 return $ this ->read ();
@@ -1403,10 +1435,10 @@ public function read()
14031435 {
14041436 $ hdr = stream_get_contents ($ this ->socket , 4 );
14051437 if ($ hdr === false ) {
1406- throw new exception ('Connection appears to have closed. ' );
1438+ throw new Registrar_Exception ('Connection appears to have closed. ' );
14071439 }
14081440 if (strlen ($ hdr ) < 4 ) {
1409- throw new exception ('Failed to read header from the connection. ' );
1441+ throw new Registrar_Exception ('Failed to read header from the connection. ' );
14101442 }
14111443 $ unpacked = unpack ('N ' , $ hdr );
14121444 $ xml = fread ($ this ->socket , ($ unpacked [1 ] - 4 ));
@@ -1417,24 +1449,24 @@ public function read()
14171449 public function write ($ xml )
14181450 {
14191451 if (fwrite ($ this ->socket , pack ('N ' , (strlen ($ xml ) + 4 )) . $ xml ) === false ) {
1420- throw new exception ('Error writing to the connection. ' );
1452+ throw new Registrar_Exception ('Error writing to the connection. ' );
14211453 }
14221454 $ xml_string = $ this ->read ();
14231455 libxml_use_internal_errors (true );
14241456
14251457 $ r = simplexml_load_string ($ xml_string , 'SimpleXMLElement ' , LIBXML_DTDLOAD | LIBXML_NOENT );
1426- if ($ r instanceof SimpleXMLElement) {
1427- $ r ->registerXPathNamespace ('e ' , 'urn:ietf:params:xml:ns:epp-1.0 ' );
1428- $ r ->registerXPathNamespace ('xsi ' , 'http://www.w3.org/2001/XMLSchema-instance ' );
1429- $ r ->registerXPathNamespace ('domain ' , 'urn:ietf:params:xml:ns:domain-1.0 ' );
1430- $ r ->registerXPathNamespace ('contact ' , 'urn:ietf:params:xml:ns:contact-1.0 ' );
1431- $ r ->registerXPathNamespace ('host ' , 'urn:ietf:params:xml:ns:host-1.0 ' );
1432- $ r ->registerXPathNamespace ('rgp ' , 'urn:ietf:params:xml:ns:rgp-1.0 ' );
1433- }
1458+ if ($ r instanceof SimpleXMLElement) {
1459+ $ r ->registerXPathNamespace ('e ' , 'urn:ietf:params:xml:ns:epp-1.0 ' );
1460+ $ r ->registerXPathNamespace ('xsi ' , 'http://www.w3.org/2001/XMLSchema-instance ' );
1461+ $ r ->registerXPathNamespace ('domain ' , 'urn:ietf:params:xml:ns:domain-1.0 ' );
1462+ $ r ->registerXPathNamespace ('contact ' , 'urn:ietf:params:xml:ns:contact-1.0 ' );
1463+ $ r ->registerXPathNamespace ('host ' , 'urn:ietf:params:xml:ns:host-1.0 ' );
1464+ $ r ->registerXPathNamespace ('rgp ' , 'urn:ietf:params:xml:ns:rgp-1.0 ' );
1465+ }
14341466
1435- if (isset ($ r ->response ) && $ r ->response ->result ->attributes ()->code >= 2000 ) {
1436- throw new exception ($ r ->response ->result ->msg );
1437- }
1467+ if (isset ($ r ->response ) && $ r ->response ->result ->attributes ()->code >= 2000 ) {
1468+ throw new Registrar_Exception ($ r ->response ->result ->msg );
1469+ }
14381470 return $ r ;
14391471 }
14401472
@@ -1443,7 +1475,7 @@ public function disconnect()
14431475 {
14441476 $ result = fclose ($ this ->socket );
14451477 if (!$ result ) {
1446- throw new exception ('Error closing the connection. ' );
1478+ throw new Registrar_Exception ('Error closing the connection. ' );
14471479 }
14481480 $ this ->socket = null ;
14491481 return $ result ;
0 commit comments