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
234 changes: 163 additions & 71 deletions EppLib.UnitTests/LocalTest.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><epp xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:ietf:params:xml:ns:epp-1.0"><command><update><contact:update xmlns:contact="urn:ietf:params:xml:ns:contact-1.0" xsi:schemaLocation="urn:ietf:params:xml:ns:contact-1.0 contact-1.0.xsd"><contact:id>CONTACT-1234</contact:id><contact:chg><contact:disclose flag="1"><contact:org type="int" /><contact:addr type="int" /></contact:disclose></contact:chg><contact:authInfo><contact:pw>2fooBAR</contact:pw></contact:authInfo></contact:update></update><clTRID>ABC-12345</clTRID></command></epp>
<?xml version="1.0" encoding="UTF-8" standalone="no"?><epp xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:ietf:params:xml:ns:epp-1.0"><command><update><contact:update xmlns:contact="urn:ietf:params:xml:ns:contact-1.0" xsi:schemaLocation="urn:ietf:params:xml:ns:contact-1.0 contact-1.0.xsd"><contact:id>CONTACT-1234</contact:id><contact:chg><contact:authInfo><contact:pw>2fooBAR</contact:pw></contact:authInfo><contact:disclose flag="1"><contact:org type="int" /><contact:addr type="int" /></contact:disclose></contact:chg></contact:update></update><clTRID>ABC-12345</clTRID></command></epp>
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><epp xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:ietf:params:xml:ns:epp-1.0"><command><update><contact:update xmlns:contact="urn:ietf:params:xml:ns:contact-1.0" xsi:schemaLocation="urn:ietf:params:xml:ns:contact-1.0 contact-1.0.xsd"><contact:id>CONTACT-1234</contact:id><contact:chg><contact:disclose flag="0"><contact:org type="int" /><contact:addr type="int" /></contact:disclose></contact:chg><contact:authInfo><contact:pw>2fooBAR</contact:pw></contact:authInfo></contact:update></update><clTRID>ABC-12345</clTRID></command></epp>
<?xml version="1.0" encoding="UTF-8" standalone="no"?><epp xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:ietf:params:xml:ns:epp-1.0"><command><update><contact:update xmlns:contact="urn:ietf:params:xml:ns:contact-1.0" xsi:schemaLocation="urn:ietf:params:xml:ns:contact-1.0 contact-1.0.xsd"><contact:id>CONTACT-1234</contact:id><contact:chg><contact:authInfo><contact:pw>2fooBAR</contact:pw></contact:authInfo><contact:disclose flag="0"><contact:org type="int" /><contact:addr type="int" /></contact:disclose></contact:chg></contact:update></update><clTRID>ABC-12345</clTRID></command></epp>
5 changes: 5 additions & 0 deletions EppLib/Entities/Contact/ContactChange.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ public class ContactChange
public Telephone Voice;
public Telephone Fax;
public string Email;

/// <summary>
/// New authorization information (password) for the contact.
/// </summary>
public string AuthInfo;
public bool? DiscloseFlag;
public Contact.DiscloseFlags DiscloseMask;

Expand Down
47 changes: 47 additions & 0 deletions EppLib/Entities/Contact/ContactTransfer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// 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.Xml;

namespace EppLib.Entities
{
/// <summary>
/// Contact transfer command (RFC 5733 section 3.2.4). Set Password to the contact's authorization
/// information; registries require it for a request and may require it for a query.
/// </summary>
public class ContactTransfer : ContactBase<ContactTransferResponse>
{
private readonly string contactId;

public ContactTransfer(string contactId)
{
this.contactId = contactId;
}

public TransferOperation Operation { get; set; } = TransferOperation.Request;

protected override XmlElement BuildCommandElement(XmlDocument doc, XmlElement commandRootElement)
{
var contactTransfer = BuildCommandElement(doc, "transfer", commandRootElement, Operation.ToEppValue());

AddXmlElement(doc, contactTransfer, "contact:id", contactId, namespaceUri);

return contactTransfer;
}

public override ContactTransferResponse FromBytes(byte[] bytes)
{
return new ContactTransferResponse(bytes);
}
}
}
71 changes: 71 additions & 0 deletions EppLib/Entities/Contact/ContactTransferResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// 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.Xml;

namespace EppLib.Entities
{
/// <summary>
/// Response to a contact transfer command (RFC 5733 section 3.2.4).
/// </summary>
public class ContactTransferResponse : EppResponse
{
public ContactTransferResponse(byte[] bytes) : base(bytes) { }

public ContactTransferResponse(string xml) : base(xml) { }

public string ContactId { get; private set; }

/// <summary>
/// Transfer status: clientApproved, clientCancelled, clientRejected, pending, serverApproved or serverCancelled.
/// </summary>
public string TransferStatus { get; private set; }

/// <summary>
/// The client that requested the transfer (reID).
/// </summary>
public string RequestClientId { get; private set; }

/// <summary>
/// When the transfer was requested (reDate), as sent by the registry.
/// </summary>
public string RequestDate { get; private set; }

/// <summary>
/// The client that should act on the transfer (acID).
/// </summary>
public string ActionClientId { get; private set; }

/// <summary>
/// When action was completed or is due (acDate), as sent by the registry.
/// </summary>
public string ActionDate { get; private set; }

protected override void ProcessDataNode(XmlDocument doc, XmlNamespaceManager namespaces)
{
namespaces.AddNamespace("contact", "urn:ietf:params:xml:ns:contact-1.0");

var trnData = doc.SelectSingleNode("/ns:epp/ns:response/ns:resData/contact:trnData", namespaces);

if (trnData != null)
{
ContactId = trnData.SelectSingleNode("contact:id", namespaces)?.InnerText;
TransferStatus = trnData.SelectSingleNode("contact:trStatus", namespaces)?.InnerText;
RequestClientId = trnData.SelectSingleNode("contact:reID", namespaces)?.InnerText;
RequestDate = trnData.SelectSingleNode("contact:reDate", namespaces)?.InnerText;
ActionClientId = trnData.SelectSingleNode("contact:acID", namespaces)?.InnerText;
ActionDate = trnData.SelectSingleNode("contact:acDate", namespaces)?.InnerText;
}
}
}
}
40 changes: 26 additions & 14 deletions EppLib/Entities/Contact/ContactUpdate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,31 +42,34 @@ protected override XmlElement BuildCommandElement(XmlDocument doc, XmlElement co

AddXmlElement(doc, contact_update, "contact:id", ContactId, namespaceUri);

var add_element = getAddRemoveElement(doc, ToAdd);
var add_element = getAddRemoveElement(doc, ToAdd, "contact:add");

if (add_element != null)
{
contact_update.AppendChild(add_element);
}

var remove_element = getAddRemoveElement(doc, ToRemove);
var remove_element = getAddRemoveElement(doc, ToRemove, "contact:rem");

if (remove_element != null)
{
contact_update.AppendChild(remove_element);
}

if (ContactChange != null)
// RFC 5733 puts authInfo inside chg; the Password property would otherwise land after it.
var authInfo = ContactChange?.AuthInfo ?? (string.IsNullOrWhiteSpace(Password) ? null : Password);

if (ContactChange != null || authInfo != null)
{
var change_element = doc.CreateElement("contact:chg", namespaceUri);

if (ContactChange.PostalInfo != null)
if (ContactChange?.PostalInfo != null)
{
var xml = AddressToXml(doc, "contact:postalInfo", ContactChange.PostalInfo);
change_element.AppendChild(xml);
}

if (ContactChange.Voice != null)
if (ContactChange?.Voice != null)
{
var voice = AddXmlElement(doc, change_element, "contact:voice", ContactChange.Voice.Value, namespaceUri);

Expand All @@ -76,7 +79,7 @@ protected override XmlElement BuildCommandElement(XmlDocument doc, XmlElement co
}
}

if (ContactChange.Fax != null)
if (ContactChange?.Fax != null)
{
var voice = AddXmlElement(doc, change_element, "contact:fax", ContactChange.Fax.Value, namespaceUri);

Expand All @@ -86,24 +89,31 @@ protected override XmlElement BuildCommandElement(XmlDocument doc, XmlElement co
}
}

if (ContactChange.DiscloseFlag != null)
// RFC 5733 order: postalInfo, voice, fax, email, authInfo, disclose.
if (ContactChange?.Email != null)
{
AddXmlElement(doc, change_element, "contact:email", ContactChange.Email, namespaceUri);
}

if (authInfo != null)
{
var authInfoElement = AddXmlElement(doc, change_element, "contact:authInfo", null, namespaceUri);
AddXmlElement(doc, authInfoElement, "contact:pw", authInfo, namespaceUri);
}

if (ContactChange?.DiscloseFlag != null)
{
var disclose = DiscloseToXml(doc, ContactChange.DiscloseMask, (bool)ContactChange.DiscloseFlag);
change_element.AppendChild(disclose);
}

if (ContactChange.Email != null)
{
AddXmlElement(doc, change_element, "contact:email", ContactChange.Email, namespaceUri);
}

contact_update.AppendChild(change_element);
}

return contact_update;
}

private static XmlElement getAddRemoveElement(XmlDocument doc, EppContactUpdateAddRemove addRemoveItems)
private XmlElement getAddRemoveElement(XmlDocument doc, EppContactUpdateAddRemove addRemoveItems, string tagName)
{
XmlElement add_remove_element = null;

Expand All @@ -112,10 +122,12 @@ private static XmlElement getAddRemoveElement(XmlDocument doc, EppContactUpdateA
if (addRemoveItems.Status != null &&
addRemoveItems.Status.Count > 0)
{
add_remove_element = doc.CreateElement(tagName, namespaceUri);

foreach (var status in addRemoveItems.Status)
{

var status_element = AddXmlElement(doc, add_remove_element, "contact:status", status.Value);
var status_element = AddXmlElement(doc, add_remove_element, "contact:status", status.Value, namespaceUri);

status_element.SetAttribute("s", status.Type);

Expand Down
36 changes: 35 additions & 1 deletion EppLib/Entities/Domain/DomainTransfer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
using System.Collections.Generic;
using System.Globalization;
using System.Xml;

namespace EppLib.Entities
Expand Down Expand Up @@ -44,12 +45,45 @@ public DomainTransfer(string mName, string registrantContactId, string adminCont
this.registrantContactId = registrantContactId;
}

/// <summary>
/// The transfer operation; defaults to Request.
/// </summary>
public TransferOperation Operation { get; set; } = TransferOperation.Request;

/// <summary>
/// Years or months to add to the registration when the transfer completes. Only used with Request.
/// </summary>
public DomainPeriod Period { get; set; }

/// <summary>
/// The repository object ID of the contact whose authorization information is in Password,
/// when it is a contact's rather than the domain's (the pw roid attribute).
/// </summary>
public string AuthInfoRoid { get; set; }

protected override XmlElement BuildCommandElement(XmlDocument doc, XmlElement commandRootElement)
{
var domainTransfer = BuildCommandElement(doc, "transfer", commandRootElement, "request");
var domainTransfer = BuildCommandElement(doc, "transfer", commandRootElement, Operation.ToEppValue());

AddXmlElement(doc, domainTransfer, "domain:name", m_name, namespaceUri);

if (Period != null)
{
var period = AddXmlElement(doc, domainTransfer, "domain:period", Period.Value.ToString(CultureInfo.InvariantCulture), namespaceUri);
period.SetAttribute("unit", Period.Unit);
}

if (!string.IsNullOrWhiteSpace(Password))
{
var authInfo = AddXmlElement(doc, domainTransfer, "domain:authInfo", null, namespaceUri);
var pw = AddXmlElement(doc, authInfo, "domain:pw", Password, namespaceUri);

if (AuthInfoRoid != null)
{
pw.SetAttribute("roid", AuthInfoRoid);
}
}

return domainTransfer;
}

Expand Down
2 changes: 1 addition & 1 deletion EppLib/Entities/Host/HostCreateResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,6 @@ protected override void ProcessDataNode(XmlDocument doc, XmlNamespaceManager nam
}
}

protected HostCreateResult HostCreateResult { get; set; }
public HostCreateResult HostCreateResult { get; protected set; }
}
}
35 changes: 35 additions & 0 deletions EppLib/Entities/TransferOperation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// 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.
namespace EppLib.Entities
{
/// <summary>
/// The op attribute of an EPP transfer command (RFC 5730 section 2.9.3.4).
/// </summary>
public enum TransferOperation
{
Request,
Query,
Approve,
Reject,
Cancel
}

internal static class TransferOperationExtensions
{
public static string ToEppValue(this TransferOperation operation)
{
return operation.ToString().ToLowerInvariant();
}
}
}
7 changes: 5 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.8.0</Version>
<Version>1.9.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,14 +13,17 @@
<RepositoryUrl>https://github.com/CodeMakerInc/EppLib.NET.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageReleaseNotes>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.</PackageReleaseNotes>
<PackageReleaseNotes>ContactUpdate no longer throws when adding or removing statuses, can change the contact's authorization information (ContactChange.AuthInfo, or Password, now placed inside chg), and sends email before disclose as RFC 5733 requires. DomainTransfer supports every operation (Operation: request, query, approve, reject, cancel), a Period and the pw roid attribute (AuthInfoRoid). New ContactTransfer command and ContactTransferResponse. HostCreateResponse.HostCreateResult is now public.</PackageReleaseNotes>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
<ItemGroup>
<Compile Include="Entities\AuthInfo.cs" />
<Compile Include="Entities\Contact\ContactCheckResult.cs" />
<Compile Include="Entities\Contact\ContactTransfer.cs" />
<Compile Include="Entities\Contact\ContactTransferResponse.cs" />
<Compile Include="Entities\TransferOperation.cs" />
<Compile Include="Entities\Domain\DomainReleaseResponse.cs" />
<Compile Include="Entities\Domain\DomainRelease.cs" />
<Compile Include="Extensions\Fury\FuryContactCreateExtension.cs" />
Expand Down
Loading