From 8db2cf274c801102f5fad40d811da54c559aaa5b Mon Sep 17 00:00:00 2001 From: Ademar Gonzalez Date: Thu, 24 Sep 2026 21:25:28 -0400 Subject: [PATCH] Fill the gaps found in the Esselink-nu and NoorDigitalAgency forks - HostInfoResponse.Host was protected, so host info could not be read. It is now public (NoorDigitalAgency). - DomainTransferResponse looked for domain:expDate instead of RFC 5731's domain:exDate, so ExpirationDate was always null. It now reads exDate (falling back to expDate) and the trStatus, reID, reDate, acID and acDate elements RFC 5731 requires (Esselink-nu). - Name servers can be sent as host attributes with glue addresses: DomainCreate.NameServerAttributes and EppDomainUpdateAddRemove.NameServerAttributes, alongside the existing host object lists; mixing both in one domain:ns throws. Info responses keep the addresses in Domain.NameServerAttributes (Esselink-nu's approach, reworked to stay source compatible). - PollResponse.DomainName falls back to the domain-1.0 name in the message, covering standard panData/trnData notifications and IIS updateNotify/deleteNotify/transferNotify (NoorDigitalAgency). Implements the host info and both domain transfer response tests that were Inconclusive placeholders. Credits both forks in CONTRIBUTORS. Bump to 1.8.0. Co-Authored-By: Claude Opus 5.5 --- CONTRIBUTORS | 2 + EppLib.UnitTests/LocalTest.cs | 157 +++++++++++++++--- EppLib/Entities/Domain/Domain.cs | 7 + EppLib/Entities/Domain/DomainBase.cs | 25 +++ EppLib/Entities/Domain/DomainCreate.cs | 10 +- EppLib/Entities/Domain/DomainHostAttribute.cs | 67 ++++++++ EppLib/Entities/Domain/DomainInfoResponse.cs | 15 ++ .../Entities/Domain/DomainTransferResponse.cs | 9 +- .../Entities/Domain/DomainTransferResult.cs | 25 +++ EppLib/Entities/Domain/DomainUpdate.cs | 17 +- EppLib/Entities/EppDomainUpdateAddRemove.cs | 1 + EppLib/Entities/Host/HostInfoResponse.cs | 2 +- EppLib/Entities/PollResponse.cs | 13 ++ EppLib/EppLib.csproj | 5 +- .../Extensions/Iis/IisDomainInfoResponse.cs | 1 + .../DomainInfo/NominetDomainInfoResponse.cs | 1 + 16 files changed, 323 insertions(+), 34 deletions(-) create mode 100644 EppLib/Entities/Domain/DomainHostAttribute.cs diff --git a/CONTRIBUTORS b/CONTRIBUTORS index dcd1562..c4ac09b 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -9,3 +9,5 @@ Paul Woodland Ross Pace Hogne Vevle Laurent Signorel +Esselink-nu (fork: host attributes, transfer response fields) +NoorDigitalAgency (fork: host info, poll domain names) diff --git a/EppLib.UnitTests/LocalTest.cs b/EppLib.UnitTests/LocalTest.cs index 2ffefdf..e4ec0b7 100644 --- a/EppLib.UnitTests/LocalTest.cs +++ b/EppLib.UnitTests/LocalTest.cs @@ -262,13 +262,9 @@ public void TestHostInfoCommand1() [DeploymentItem("TestData/HostInfoResponse1.xml")] public void TestHostInfoResponse1() { - Assert.Inconclusive("Not implemented"); - - /* byte[] input = File.ReadAllBytes("HostInfoResponse1.xml"); var response = new HostInfoResponse(input); - //var host = response.Host; - var host = new Host(); + var host = response.Host; Assert.AreEqual("1000", response.Code); Assert.AreEqual("Command completed successfully", response.Message); @@ -283,24 +279,13 @@ public void TestHostInfoResponse1() Assert.AreEqual("1999-12-03T09:00:00.0Z", host.UpDate); Assert.AreEqual("2000-04-08T09:00:00.0Z", host.TrDate); - var status = new List() - { - new Status("linked", null), - new Status("clientUpdateProhibited", null) - }; - CollectionAssert.AreEqual(status.ToArray(), host.Status.ToArray()); + CollectionAssert.AreEqual(new[] { "linked", "clientUpdateProhibited" }, host.Status.Select(s => s.Type).ToArray()); - var hosts = new List() - { - new HostAddress("192.0.2.2", "v4"), - new HostAddress("192.0.2.29", "v4"), - new HostAddress("1080:0:0:0:8:800:200C:417A", "v6") - }; - CollectionAssert.AreEqual(hosts.ToArray(), host.Addresses.ToArray()); + CollectionAssert.AreEqual(new[] { "192.0.2.2", "192.0.2.29", "1080:0:0:0:8:800:200C:417A" }, host.Addresses.Select(a => a.IPAddress).ToArray()); + CollectionAssert.AreEqual(new[] { "v4", "v4", "v6" }, host.Addresses.Select(a => a.IPVersion).ToArray()); Assert.AreEqual("ABC-12345", response.ClientTransactionId); Assert.AreEqual("54322-XYZ", response.ServerTransactionId); - */ } #endregion @@ -1126,7 +1111,17 @@ public void TestDomainTransferQueryCommand1() [DeploymentItem("TestData/DomainTransferQueryResponse1.xml")] public void TestDomainTransferQueryResponse1() { - Assert.Inconclusive("Not implemented"); + var response = new DomainTransferResponse(File.ReadAllBytes("DomainTransferQueryResponse1.xml")); + var result = response.DomainTransferResult; + + Assert.AreEqual("1000", response.Code); + Assert.AreEqual("example.com", result.DomainName); + Assert.AreEqual("pending", result.TransferStatus); + Assert.AreEqual("ClientX", result.RequestClientId); + Assert.AreEqual("2000-06-06T22:00:00.0Z", result.RequestDate); + Assert.AreEqual("ClientY", result.ActionClientId); + Assert.AreEqual("2000-06-11T22:00:00.0Z", result.ActionDate); + Assert.AreEqual("2002-09-08T22:00:00.0Z", result.ExpirationDate); } #endregion @@ -1152,7 +1147,17 @@ public void TestDomainTransferRequestCommand1() [DeploymentItem("TestData/DomainTransferRequestResponse1.xml")] public void TestDomainTransferRequestResponse1() { - Assert.Inconclusive("Not implemented"); + var response = new DomainTransferResponse(File.ReadAllBytes("DomainTransferRequestResponse1.xml")); + var result = response.DomainTransferResult; + + Assert.AreEqual("1001", response.Code); + Assert.AreEqual("example.com", result.DomainName); + Assert.AreEqual("pending", result.TransferStatus); + Assert.AreEqual("ClientX", result.RequestClientId); + Assert.AreEqual("2000-06-08T22:00:00.0Z", result.RequestDate); + Assert.AreEqual("ClientY", result.ActionClientId); + Assert.AreEqual("2000-06-13T22:00:00.0Z", result.ActionDate); + Assert.AreEqual("2002-09-08T22:00:00.0Z", result.ExpirationDate); } #endregion @@ -1254,5 +1259,115 @@ public void TestPollMsgsResponse2() } #endregion + + #region Fork gaps (1.8.0) + + /// + /// Domain create with name servers as host attributes (RFC 5731 hostAttr) + /// + [TestMethod] + [TestCategory("LocalCommand")] + public void TestDomainCreateHostAttributes() + { + var command = new DomainCreate("example.com", "jd1234"); + command.NameServerAttributes.Add(new DomainHostAttribute("ns1.example.net")); + command.NameServerAttributes.Add(new DomainHostAttribute("ns1.example.com", new HostAddress("192.0.2.2", "v4"), new HostAddress("1080:0:0:0:8:800:200C:417A", "v6"))); + command.TransactionId = "ABC-12345"; + + var xml = command.ToXml().InnerXml; + + StringAssert.Contains(xml, "ns1.example.net" + + "ns1.example.com192.0.2.2" + + "1080:0:0:0:8:800:200C:417A"); + Assert.IsFalse(xml.Contains("hostObj")); + } + + [TestMethod] + [TestCategory("LocalCommand")] + [ExpectedException(typeof(InvalidOperationException))] + public void TestDomainCreateRejectsHostObjectsAndAttributesTogether() + { + var command = new DomainCreate("example.com", "jd1234"); + command.NameServers.Add("ns1.example.net"); + command.NameServerAttributes.Add(new DomainHostAttribute("ns2.example.net")); + + command.ToXml(); + } + + /// + /// Domain update adding and removing host attributes + /// + [TestMethod] + [TestCategory("LocalCommand")] + public void TestDomainUpdateHostAttributes() + { + var command = new DomainUpdate("example.com"); + command.ToAdd.NameServerAttributes.Add(new DomainHostAttribute("ns2.example.com", new HostAddress("192.0.2.3", "v4"))); + command.ToRemove.NameServerAttributes.Add(new DomainHostAttribute("ns1.example.com")); + + var xml = command.ToXml().InnerXml; + + StringAssert.Contains(xml, "ns2.example.com192.0.2.3"); + StringAssert.Contains(xml, "ns1.example.com"); + } + + /// + /// Domain info response with host attributes keeps the glue addresses + /// + [TestMethod] + [TestCategory("LocalResponse")] + public void TestDomainInfoResponseHostAttributes() + { + var xml = "" + + "Command completed successfully" + + "example.comEXAMPLE1-REP" + + "ns1.example.com192.0.2.21080:0:0:0:8:800:200C:417A" + + "ns2.example.net" + + "ClientXABC-1234554322-XYZ"; + + var response = new DomainInfoResponse(xml); + var domain = response.Domain; + + CollectionAssert.AreEqual(new[] { "ns1.example.com", "ns2.example.net" }, domain.NameServers.ToArray()); + Assert.AreEqual(2, domain.NameServerAttributes.Count); + Assert.AreEqual("ns1.example.com", domain.NameServerAttributes[0].HostName); + CollectionAssert.AreEqual(new[] { "192.0.2.2", "1080:0:0:0:8:800:200C:417A" }, domain.NameServerAttributes[0].Addresses.Select(a => a.IPAddress).ToArray()); + CollectionAssert.AreEqual(new[] { "v4", "v6" }, domain.NameServerAttributes[0].Addresses.Select(a => a.IPVersion).ToArray()); + Assert.AreEqual(0, domain.NameServerAttributes[1].Addresses.Count); + } + + /// + /// Poll message with a standard pending action notification (RFC 5731 panData) + /// + [TestMethod] + [TestCategory("LocalResponse")] + [DeploymentItem("TestData/MessageDomainPendingComplete1.xml")] + public void TestPollDomainNameFromPanData() + { + var response = new PollResponse(File.ReadAllBytes("MessageDomainPendingComplete1.xml")); + + Assert.AreEqual("1301", response.Code); + Assert.AreEqual("example.com", response.DomainName); + } + + /// + /// Poll message with an IIS (.se/.nu) update notification wrapping domain:infData + /// + [TestMethod] + [TestCategory("LocalResponse")] + public void TestPollDomainNameFromIisUpdateNotify() + { + var xml = "" + + "Command completed successfully; ack to dequeue" + + "2025-06-19T10:00:00.0ZDomain updated" + + "example.seexample.se-1" + + "54322-XYZ"; + + var response = new PollResponse(System.Text.Encoding.UTF8.GetBytes(xml)); + + Assert.AreEqual("example.se", response.DomainName); + } + + #endregion } } diff --git a/EppLib/Entities/Domain/Domain.cs b/EppLib/Entities/Domain/Domain.cs index 701fc2f..b7d4a95 100755 --- a/EppLib/Entities/Domain/Domain.cs +++ b/EppLib/Entities/Domain/Domain.cs @@ -21,6 +21,7 @@ public class Domain public Domain() { NameServers = new List(); + NameServerAttributes = new List(); Hosts = new List(); Status = new List(); Contacts = new List(); @@ -56,6 +57,12 @@ public Domain() /// public IList NameServers { get; set; } + /// + /// Name servers the registry returned as host attributes, with their glue addresses. + /// Their names are also in . + /// + public IList NameServerAttributes { get; set; } + /// /// The identifier of the sponsoring Registrar /// diff --git a/EppLib/Entities/Domain/DomainBase.cs b/EppLib/Entities/Domain/DomainBase.cs index 247d679..276142f 100755 --- a/EppLib/Entities/Domain/DomainBase.cs +++ b/EppLib/Entities/Domain/DomainBase.cs @@ -36,5 +36,30 @@ protected XmlNode CreateNameServerElement(XmlDocument doc, IEnumerable n return nameServerElement; } + + /// + /// Builds domain:ns from either host object names (hostObj) or host attributes (hostAttr); RFC 5731 allows one form per element. + /// + protected XmlNode CreateNameServerElement(XmlDocument doc, ICollection hostObjects, ICollection hostAttributes) + { + if (hostObjects.Count > 0 && hostAttributes.Count > 0) + { + throw new InvalidOperationException("domain:ns takes either host objects (NameServers) or host attributes (NameServerAttributes), not both (RFC 5731 section 1.1)."); + } + + if (hostObjects.Count > 0) + { + return CreateNameServerElement(doc, hostObjects); + } + + var nameServerElement = doc.CreateElement("domain:ns", namespaceUri); + + foreach (var hostAttribute in hostAttributes) + { + nameServerElement.AppendChild(hostAttribute.ToXml(doc, namespaceUri)); + } + + return nameServerElement; + } } } diff --git a/EppLib/Entities/Domain/DomainCreate.cs b/EppLib/Entities/Domain/DomainCreate.cs index 4eefd67..60d5dd9 100755 --- a/EppLib/Entities/Domain/DomainCreate.cs +++ b/EppLib/Entities/Domain/DomainCreate.cs @@ -34,6 +34,12 @@ public IList NameServers get { return nameServers; } } + /// + /// Name servers as host attributes (name plus glue addresses), for registries that do not use host objects. + /// Use this or , not both. + /// + public IList NameServerAttributes { get; } = new List(); + public IList DomainContacts { get { return domainContacts; } @@ -58,9 +64,9 @@ protected override XmlElement BuildCommandElement(XmlDocument doc, XmlElement co period.SetAttribute("unit", Period.Unit); } - if (NameServers != null && NameServers.Count>0) + if (NameServers.Count > 0 || NameServerAttributes.Count > 0) { - domainCreate.AppendChild(CreateNameServerElement(doc, NameServers)); + domainCreate.AppendChild(CreateNameServerElement(doc, NameServers, NameServerAttributes)); } if (RegistrantContactId != null) diff --git a/EppLib/Entities/Domain/DomainHostAttribute.cs b/EppLib/Entities/Domain/DomainHostAttribute.cs new file mode 100644 index 0000000..a2966f3 --- /dev/null +++ b/EppLib/Entities/Domain/DomainHostAttribute.cs @@ -0,0 +1,67 @@ +// Copyright 2012 Code Maker Inc. (http://codemaker.net) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +using System.Collections.Generic; +using System.Xml; + +namespace EppLib.Entities +{ + /// + /// A name server given by name and, for hosts inside the domain, IP addresses: the domain:hostAttr + /// form of RFC 5731. Registries that do not use separate host objects expect this form. + /// + public class DomainHostAttribute + { + public DomainHostAttribute() + { + Addresses = new List(); + } + + public DomainHostAttribute(string hostName, params HostAddress[] addresses) + { + HostName = hostName; + Addresses = new List(addresses); + } + + public string HostName { get; set; } + + /// + /// Glue addresses; set IPVersion to "v4" or "v6". + /// + public IList Addresses { get; private set; } + + internal XmlElement ToXml(XmlDocument doc, string namespaceUri) + { + var hostAttr = doc.CreateElement("domain:hostAttr", namespaceUri); + + var hostName = doc.CreateElement("domain:hostName", namespaceUri); + hostName.InnerText = HostName; + hostAttr.AppendChild(hostName); + + foreach (var address in Addresses) + { + var hostAddr = doc.CreateElement("domain:hostAddr", namespaceUri); + hostAddr.InnerText = address.IPAddress; + + if (address.IPVersion != null) + { + hostAddr.SetAttribute("ip", address.IPVersion); + } + + hostAttr.AppendChild(hostAddr); + } + + return hostAttr; + } + } +} diff --git a/EppLib/Entities/Domain/DomainInfoResponse.cs b/EppLib/Entities/Domain/DomainInfoResponse.cs index 857b7a1..64dc4d5 100755 --- a/EppLib/Entities/Domain/DomainInfoResponse.cs +++ b/EppLib/Entities/Domain/DomainInfoResponse.cs @@ -136,6 +136,21 @@ protected override void ProcessDataNode(XmlDocument doc, XmlNamespaceManager nam Domain.NameServers.Add(hostName.InnerText); } } + + var hostNameNode = hostAttrNode.SelectSingleNode("domain:hostName", namespaces); + + if (hostNameNode != null) + { + var hostAttribute = new DomainHostAttribute { HostName = hostNameNode.InnerText }; + + foreach (XmlNode hostAddrNode in hostAttrNode.SelectNodes("domain:hostAddr", namespaces)) + { + var ip = hostAddrNode.Attributes?["ip"]; + hostAttribute.Addresses.Add(new HostAddress(hostAddrNode.InnerText, ip != null ? ip.Value : "v4")); + } + + Domain.NameServerAttributes.Add(hostAttribute); + } } } } diff --git a/EppLib/Entities/Domain/DomainTransferResponse.cs b/EppLib/Entities/Domain/DomainTransferResponse.cs index d0045f5..49d87c2 100755 --- a/EppLib/Entities/Domain/DomainTransferResponse.cs +++ b/EppLib/Entities/Domain/DomainTransferResponse.cs @@ -43,12 +43,19 @@ protected override void ProcessDataNode(XmlDocument doc, XmlNamespaceManager nam DomainTransferResult.CreatedDate = crDateNode.InnerText; } - var exDateNode = children.SelectSingleNode("domain:expDate", namespaces); + // RFC 5731 names it exDate; expDate is kept for registries that relied on the old lookup. + var exDateNode = children.SelectSingleNode("domain:exDate", namespaces) ?? children.SelectSingleNode("domain:expDate", namespaces); if (exDateNode != null) { DomainTransferResult.ExpirationDate = exDateNode.InnerText; } + + DomainTransferResult.TransferStatus = children.SelectSingleNode("domain:trStatus", namespaces)?.InnerText; + DomainTransferResult.RequestClientId = children.SelectSingleNode("domain:reID", namespaces)?.InnerText; + DomainTransferResult.RequestDate = children.SelectSingleNode("domain:reDate", namespaces)?.InnerText; + DomainTransferResult.ActionClientId = children.SelectSingleNode("domain:acID", namespaces)?.InnerText; + DomainTransferResult.ActionDate = children.SelectSingleNode("domain:acDate", namespaces)?.InnerText; } } } diff --git a/EppLib/Entities/Domain/DomainTransferResult.cs b/EppLib/Entities/Domain/DomainTransferResult.cs index d2d570a..6b95412 100755 --- a/EppLib/Entities/Domain/DomainTransferResult.cs +++ b/EppLib/Entities/Domain/DomainTransferResult.cs @@ -22,5 +22,30 @@ public class DomainTransferResult public string ExpirationDate { get; set; } public string DomainName { get; set; } + + /// + /// Transfer status: clientApproved, clientCancelled, clientRejected, pending, serverApproved or serverCancelled. + /// + public string TransferStatus { get; set; } + + /// + /// The client that requested the transfer (reID). + /// + public string RequestClientId { get; set; } + + /// + /// When the transfer was requested (reDate), as sent by the registry. + /// + public string RequestDate { get; set; } + + /// + /// The client that should act on the transfer (acID). + /// + public string ActionClientId { get; set; } + + /// + /// When action was completed or is due (acDate), as sent by the registry. + /// + public string ActionDate { get; set; } } } \ No newline at end of file diff --git a/EppLib/Entities/Domain/DomainUpdate.cs b/EppLib/Entities/Domain/DomainUpdate.cs index 2c243eb..b84dc56 100755 --- a/EppLib/Entities/Domain/DomainUpdate.cs +++ b/EppLib/Entities/Domain/DomainUpdate.cs @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +using System.Collections.Generic; using System.Xml; namespace EppLib.Entities @@ -54,10 +55,10 @@ protected override XmlElement BuildCommandElement(XmlDocument doc, XmlElement co if (DomainChange.RegistrantContactId != null) { AddXmlElement(doc, change_element, "domain:registrant", DomainChange.RegistrantContactId, namespaceUri); - } - - if (DomainChange.AuthInfo != null) { - var authInfoElement = AddXmlElement (doc, change_element, "domain:authInfo", null, namespaceUri); + } + + if (DomainChange.AuthInfo != null) { + var authInfoElement = AddXmlElement (doc, change_element, "domain:authInfo", null, namespaceUri); AddXmlElement (doc, authInfoElement, "domain:pw", DomainChange.AuthInfo, namespaceUri); } else if (DomainChange.NullAuthInfo) @@ -100,12 +101,14 @@ private XmlElement getAddRemoveElement(XmlDocument doc, EppDomainUpdateAddRemove if (add_remove_items != null) { - if (add_remove_items.NameServers != null && - add_remove_items.NameServers.Count > 0) + var nameServers = add_remove_items.NameServers ?? new List(); + var nameServerAttributes = add_remove_items.NameServerAttributes ?? new List(); + + if (nameServers.Count > 0 || nameServerAttributes.Count > 0) { add_remove_element = doc.CreateElement(tag_name, namespaceURI); - add_remove_element.AppendChild(CreateNameServerElement(doc, add_remove_items.NameServers)); + add_remove_element.AppendChild(CreateNameServerElement(doc, nameServers, nameServerAttributes)); } if (add_remove_items.DomainContacts != null && diff --git a/EppLib/Entities/EppDomainUpdateAddRemove.cs b/EppLib/Entities/EppDomainUpdateAddRemove.cs index bc6cccb..fed8460 100755 --- a/EppLib/Entities/EppDomainUpdateAddRemove.cs +++ b/EppLib/Entities/EppDomainUpdateAddRemove.cs @@ -18,6 +18,7 @@ namespace EppLib.Entities public class EppDomainUpdateAddRemove { public IList NameServers = new List(); + public IList NameServerAttributes = new List(); public IList DomainContacts = new List(); public IList Status = new List(); } diff --git a/EppLib/Entities/Host/HostInfoResponse.cs b/EppLib/Entities/Host/HostInfoResponse.cs index c932110..9972ba8 100755 --- a/EppLib/Entities/Host/HostInfoResponse.cs +++ b/EppLib/Entities/Host/HostInfoResponse.cs @@ -121,6 +121,6 @@ protected override void ProcessDataNode(XmlDocument doc, XmlNamespaceManager nam } - protected Host Host { get; set; } + public Host Host { get; protected set; } } } diff --git a/EppLib/Entities/PollResponse.cs b/EppLib/Entities/PollResponse.cs index a04e958..25e33bb 100755 --- a/EppLib/Entities/PollResponse.cs +++ b/EppLib/Entities/PollResponse.cs @@ -78,6 +78,19 @@ protected override void ProcessDataNode(XmlDocument doc, XmlNamespaceManager nam { DomainName = domainNameNode.InnerText; } + + // Standard domain notifications (domain:panData, domain:trnData) and registry wrappers + // such as IIS's updateNotify carry the name as a domain-1.0 name element. + if (string.IsNullOrEmpty(DomainName)) + { + namespaces.AddNamespace("pollDomain", "urn:ietf:params:xml:ns:domain-1.0"); + var nameNode = resData.SelectSingleNode(".//pollDomain:name", namespaces); + + if (nameNode != null) + { + DomainName = nameNode.InnerText; + } + } } } diff --git a/EppLib/EppLib.csproj b/EppLib/EppLib.csproj index 3de0418..560d2c4 100644 --- a/EppLib/EppLib.csproj +++ b/EppLib/EppLib.csproj @@ -4,7 +4,7 @@ netstandard2.0;net10.0 EppLib EppLib - 1.7.0 + 1.8.0 Code Maker Inc. and Contributors EppLib.NET provides a library that makes easy for registrars to interact with registries implementing the Extensible Provisioning Protocol (EPP). Includes extensions for CIRA (.CA), Nominet (.UK), IIS (.SE), Verisign Namestore, LaunchPhase and SecDNS. epp;registrar;registry;domain;rfc5730 @@ -13,7 +13,7 @@ https://github.com/CodeMakerInc/EppLib.NET.git git README.md - Completes the secDNS (DNSSEC, RFC 5910) extension (#31): keyData on create and update and inside dsData, remove-all, maxSigLife changes, the urgent flag, and SecDNSInfData for reading DNSSEC data from domain info responses. SecDNSData.KeyTag is now an int so key tags above 32767 work, DigestType can be set (for example SHA256) instead of always being SHA-1, and newer algorithms such as RSASHA256, ECDSAP256SHA256 and ED25519 are named in SecDNSAlgorithm. + HostInfoResponse.Host is now public, so host info responses can be read. DomainTransferResponse reads exDate (it looked for expDate, so ExpirationDate was always null) and the transfer status, requesting and acting clients and dates. Name servers can be sent as host attributes (hostAttr, with glue addresses) through DomainCreate.NameServerAttributes and EppDomainUpdateAddRemove.NameServerAttributes, and are returned in Domain.NameServerAttributes. PollResponse.DomainName is filled from standard domain notifications and IIS notifications. Thanks to the Esselink-nu and NoorDigitalAgency forks, which found these gaps. true false false @@ -97,6 +97,7 @@ + diff --git a/EppLib/Extensions/Iis/IisDomainInfoResponse.cs b/EppLib/Extensions/Iis/IisDomainInfoResponse.cs index f9ad3e5..5082c67 100644 --- a/EppLib/Extensions/Iis/IisDomainInfoResponse.cs +++ b/EppLib/Extensions/Iis/IisDomainInfoResponse.cs @@ -41,6 +41,7 @@ protected override void ProcessDataNode(XmlDocument doc, XmlNamespaceManager nam _iisDomain.Hosts = _domain.Hosts; _iisDomain.Name = _domain.Name; _iisDomain.NameServers = _domain.NameServers; + _iisDomain.NameServerAttributes = _domain.NameServerAttributes; _iisDomain.Password = _domain.Password; _iisDomain.RegistrantId = _domain.RegistrantId; _iisDomain.Roid = _domain.Roid; diff --git a/EppLib/Extensions/Nominet/DomainInfo/NominetDomainInfoResponse.cs b/EppLib/Extensions/Nominet/DomainInfo/NominetDomainInfoResponse.cs index a90ce06..3751ae2 100644 --- a/EppLib/Extensions/Nominet/DomainInfo/NominetDomainInfoResponse.cs +++ b/EppLib/Extensions/Nominet/DomainInfo/NominetDomainInfoResponse.cs @@ -26,6 +26,7 @@ protected override void ProcessDataNode(XmlDocument doc, XmlNamespaceManager nam _nomDomain.Hosts = _domain.Hosts; _nomDomain.Name = _domain.Name; _nomDomain.NameServers = _domain.NameServers; + _nomDomain.NameServerAttributes = _domain.NameServerAttributes; _nomDomain.Password = _domain.Password; _nomDomain.RegistrantId = _domain.RegistrantId; _nomDomain.Roid = _domain.Roid;