Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 28 additions & 8 deletions EppLib.UnitTests/LocalTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ public class LocalTest

public TestContext TestContext { get; set; }

[TestInitialize]
public void TestSetup()
{
var testName = TestContext.TestName;
var method = new StackFrame().GetMethod().DeclaringType.GetMethod(testName);
var attributes = method.GetCustomAttributes(typeof(DeploymentItemAttribute), false);
DeploymentUtility.CopyDeploymentItems(attributes);
[TestInitialize]
public void TestSetup()
{
var testName = TestContext.TestName;
var method = new StackFrame().GetMethod().DeclaringType.GetMethod(testName);
var attributes = method.GetCustomAttributes(typeof(DeploymentItemAttribute), false);
DeploymentUtility.CopyDeploymentItems(attributes);
}

public LocalTest()
Expand Down Expand Up @@ -1072,6 +1072,21 @@ public void TestDomainRenewCommand1()
Assert.AreEqual(expected, command.ToXml().InnerXml);
}

/// <summary>
/// Domain renew command given a full UTC date-time, as returned in exDate. The date must not shift with the local timezone.
/// </summary>
[TestMethod]
[TestCategory("LocalCommand")]
[DeploymentItem("TestData/DomainRenewCommand1.xml")]
public void TestDomainRenewCommandWithUtcDateTime()
{
string expected = File.ReadAllText("DomainRenewCommand1.xml");

var command = new DomainRenew("example.com", "2000-04-03T22:00:00.0Z", new DomainPeriod(5, "y"));
command.TransactionId = "ABC-12345";
Assert.AreEqual(expected, command.ToXml().InnerXml);
}

/// <summary>
/// Domain renew response, example RFC5731
/// </summary>
Expand All @@ -1080,7 +1095,12 @@ public void TestDomainRenewCommand1()
[DeploymentItem("TestData/DomainRenewResponse1.xml")]
public void TestDomainRenewResponse1()
{
Assert.Inconclusive("Not implemented");
var response = new DomainRenewResponse(File.ReadAllBytes("DomainRenewResponse1.xml"));

Assert.AreEqual("1000", response.Code);
Assert.IsNotNull(response.ExDate);
Assert.AreEqual(new DateTime(2005, 4, 3, 22, 0, 0, DateTimeKind.Utc), response.ExDate.Value);
Assert.AreEqual(DateTimeKind.Utc, response.ExDate.Value.Kind);
}

#endregion
Expand Down
12 changes: 8 additions & 4 deletions EppLib.UnitTests/NominetExtensionLocalTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,11 @@ public void TestNominetContactInfoResponse1()
Assert.AreEqual("invalid", response.DataQuality.Status);
Assert.AreEqual("Incorrect Address", response.DataQuality.Reason);
Assert.IsTrue(response.DataQuality.DateCommenced.HasValue);
Assert.AreEqual(new DateTime(2015,5,7,13,20,4).ToString(), response.DataQuality.DateCommenced.Value.ToString());
Assert.AreEqual(new DateTime(2015, 5, 7, 13, 20, 4, DateTimeKind.Utc), response.DataQuality.DateCommenced.Value);
Assert.AreEqual(DateTimeKind.Utc, response.DataQuality.DateCommenced.Value.Kind);
Assert.IsTrue(response.DataQuality.DateToSuspend.HasValue);
Assert.AreEqual(new DateTime(2015, 6, 6, 13, 20, 4).ToString(), response.DataQuality.DateToSuspend.Value.ToString());
Assert.AreEqual(new DateTime(2015, 6, 6, 13, 20, 4, DateTimeKind.Utc), response.DataQuality.DateToSuspend.Value);
Assert.AreEqual(DateTimeKind.Utc, response.DataQuality.DateToSuspend.Value.Kind);
Assert.IsTrue(response.DataQuality.LockApplied.HasValue);
Assert.IsTrue(response.DataQuality.LockApplied.Value);
Assert.IsNotNull(response.DataQuality.DomainList);
Expand Down Expand Up @@ -314,7 +316,8 @@ public void TestAbuseNotification()
Assert.AreEqual("www.youve.been.phished.co.uk", notification.HostName);
Assert.AreEqual("http://www.youve.been.phished.co.uk/give/us/your/money.htm", notification.Url);
Assert.IsNotNull(notification.Date);
Assert.AreEqual(new DateTime(2011, 3, 1, 11, 44, 1), notification.Date.Value);
Assert.AreEqual(new DateTime(2011, 3, 1, 11, 44, 1, DateTimeKind.Utc), notification.Date.Value);
Assert.AreEqual(DateTimeKind.Utc, notification.Date.Value.Kind);
Assert.AreEqual("213.135.134.24", notification.Ip);
Assert.AreEqual("ns0.crooked.dealings.net", notification.Nameserver);
Assert.AreEqual("hostmaster@crooked.dealings.net", notification.DnsAdmin);
Expand Down Expand Up @@ -350,7 +353,8 @@ public void TestDomainsSuspendedNotification()

Assert.AreEqual("Data Quality", notification.SuspendedReason);
Assert.IsNotNull(notification.CancelDate);
Assert.AreEqual(new DateTime(2009, 12, 12, 0, 0, 13, DateTimeKind.Utc), notification.CancelDate.Value.ToUniversalTime());
Assert.AreEqual(new DateTime(2009, 12, 12, 0, 0, 13, DateTimeKind.Utc), notification.CancelDate.Value);
Assert.AreEqual(DateTimeKind.Utc, notification.CancelDate.Value.Kind);
Assert.IsNotNull(notification.SuspendedDomains);
Assert.AreEqual(2, notification.SuspendedDomains.Count);
Assert.AreEqual("epp-example1.co.uk", notification.SuspendedDomains.First());
Expand Down
2 changes: 1 addition & 1 deletion EppLib/Entities/Domain/DomainRenew.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ protected override XmlElement BuildCommandElement(XmlDocument doc, XmlElement co
var domainRenew = BuildCommandElement(doc, "renew", commandRootElement);

AddXmlElement(doc, domainRenew, "domain:name", DomainName, namespaceUri);
AddXmlElement(doc, domainRenew, "domain:curExpDate", DateTime.Parse(CurrentExpirationDate, CultureInfo.InvariantCulture).ToString("yyyy-MM-dd", CultureInfo.InvariantCulture), namespaceUri);
AddXmlElement(doc, domainRenew, "domain:curExpDate", EppDateTime.Parse(CurrentExpirationDate).ToString("yyyy-MM-dd", CultureInfo.InvariantCulture), namespaceUri);

if (m_period != null)
{
Expand Down
2 changes: 1 addition & 1 deletion EppLib/Entities/Domain/DomainRenewResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

public class DomainRenewResponse : EppResponse
{
protected DateTime? _exDate;

Check warning on line 21 in EppLib/Entities/Domain/DomainRenewResponse.cs

View workflow job for this annotation

GitHub Actions / build and test

Identifier '_exDate' is not CLS-compliant

Check warning on line 21 in EppLib/Entities/Domain/DomainRenewResponse.cs

View workflow job for this annotation

GitHub Actions / build and test

Identifier '_exDate' is not CLS-compliant
public virtual DateTime? ExDate
{
get { return _exDate; }
Expand All @@ -41,7 +41,7 @@
if (exDateNode != null)
{
DateTime exDate;
if (DateTime.TryParse(exDateNode.InnerText, out exDate))
if (EppDateTime.TryParse(exDateNode.InnerText, out exDate))
{
this._exDate = exDate;
}
Expand Down
38 changes: 38 additions & 0 deletions EppLib/EppDateTime.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// 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;
using System.Globalization;

namespace EppLib
{
/// <summary>
/// Parses EPP date-time values. RFC 5730-5733 require every date-time to be UTC, so values
/// are returned as UTC (DateTimeKind.Utc). Values with an offset are converted to UTC, and
/// values without a zone designator, which some registries send, are taken to be UTC.
/// </summary>
internal static class EppDateTime
{
private const DateTimeStyles Styles = DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal;

public static bool TryParse(string value, out DateTime result)
{
return DateTime.TryParse(value, CultureInfo.InvariantCulture, Styles, out result);
}

public static DateTime Parse(string value)
{
return DateTime.Parse(value, CultureInfo.InvariantCulture, Styles);
}
}
}
5 changes: 3 additions & 2 deletions EppLib/EppLib.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<TargetFrameworks>netstandard2.0;net10.0</TargetFrameworks>
<AssemblyName>EppLib</AssemblyName>
<PackageId>EppLib</PackageId>
<Version>1.5.0</Version>
<Version>1.6.0</Version>
<Authors>Code Maker Inc. and Contributors</Authors>
<Description>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.</Description>
<PackageTags>epp;registrar;registry;domain;rfc5730</PackageTags>
Expand All @@ -13,7 +13,7 @@
<RepositoryUrl>https://github.com/CodeMakerInc/EppLib.NET.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageReleaseNotes>Breaking: TcpTransport now validates the registry's server certificate (trusted chain and matching host name) instead of accepting any certificate. For test environments with self-signed certificates, set TcpTransport.ServerCertificateValidationCallback.</PackageReleaseNotes>
<PackageReleaseNotes>Breaking: parsed EPP dates (DomainRenewResponse.ExDate and the Nominet dates) are now returned in UTC (DateTimeKind.Utc) as RFC 5730-5733 require, instead of being converted to the machine's local time. Values without a zone designator are taken as UTC. Fixes DomainRenew sending the wrong curExpDate east of UTC when given a full date-time, and a culture-dependent Smallregistry birthDate.</PackageReleaseNotes>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
Expand Down Expand Up @@ -179,6 +179,7 @@
<Compile Include="Extensions\Smallregistry\ContactCreate\SmallregistryContactPMCreateExtension.cs" />
<Compile Include="Extensions\Smallregistry\ContactCreate\SmallregistryContactPPCreateExtension.cs" />
<Compile Include="Extensions\Smallregistry\SmallregistryExtensionBase.cs" />
<Compile Include="EppDateTime.cs" />
<Compile Include="ITransport.cs" />
<Compile Include="Service.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
_nomContact.Email = _contact.Email;
_nomContact.PostalInfo = _contact.PostalInfo;
_nomContact.Roid = _contact.Roid;
_nomContact.Status = _contact.Status;

Check warning on line 31 in EppLib/Extensions/Nominet/ContactInfo/NominetContactInfoResponse.cs

View workflow job for this annotation

GitHub Actions / build and test

'Contact.Status' is obsolete: 'Use StatusList'

Check warning on line 31 in EppLib/Extensions/Nominet/ContactInfo/NominetContactInfoResponse.cs

View workflow job for this annotation

GitHub Actions / build and test

'Contact.Status' is obsolete: 'Use StatusList'

Check warning on line 31 in EppLib/Extensions/Nominet/ContactInfo/NominetContactInfoResponse.cs

View workflow job for this annotation

GitHub Actions / build and test

'Contact.Status' is obsolete: 'Use StatusList'

Check warning on line 31 in EppLib/Extensions/Nominet/ContactInfo/NominetContactInfoResponse.cs

View workflow job for this annotation

GitHub Actions / build and test

'Contact.Status' is obsolete: 'Use StatusList'
_nomContact.StatusList = _contact.StatusList;
_nomContact.ClId = _contact.ClId;
_nomContact.CrId = _contact.CrId;
Expand Down Expand Up @@ -94,7 +94,7 @@
if (dateCommenced != null)
{
DateTime date;
if (DateTime.TryParse(dateCommenced.InnerText, out date))
if (EppDateTime.TryParse(dateCommenced.InnerText, out date))
{
_nomDataQuality.DateCommenced = date;
}
Expand All @@ -103,7 +103,7 @@
if (dateToSuspend != null)
{
DateTime date;
if (DateTime.TryParse(dateToSuspend.InnerText, out date))
if (EppDateTime.TryParse(dateToSuspend.InnerText, out date))
{
_nomDataQuality.DateToSuspend = date;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ protected override void ProcessDataNode(XmlDocument doc, XmlNamespaceManager nam
if (dateNode != null)
{
DateTime parsedDate;
if (DateTime.TryParse(dateNode.InnerText, out parsedDate))
if (EppDateTime.TryParse(dateNode.InnerText, out parsedDate))
{
Date = parsedDate;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ protected override void ProcessDataNode(XmlDocument doc, XmlNamespaceManager nam
if (cancelDateNode != null)
{
DateTime parsedDate;
if (DateTime.TryParse(cancelDateNode.InnerText, out parsedDate))
if (EppDateTime.TryParse(cancelDateNode.InnerText, out parsedDate))
{
CancelDate = parsedDate;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Globalization;
using System.Xml;

namespace EppLib.Extensions.Smallregistry
Expand All @@ -17,9 +18,9 @@

var person = AddXmlElement(doc, contact, "person", null);

if (BirthDate != null)

Check warning on line 21 in EppLib/Extensions/Smallregistry/ContactCreate/SmallregistryContactPPCreateExtension.cs

View workflow job for this annotation

GitHub Actions / build and test

The result of the expression is always 'true' since a value of type 'DateTime' is never equal to 'null' of type 'DateTime?'
{
AddXmlElement(doc, person, "birthDate", BirthDate.ToString("yyyy-MM-dd"));
AddXmlElement(doc, person, "birthDate", BirthDate.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture));
}

if (BirthPlace != null)
Expand Down
Loading