// Copyright (c) 2011, Outercurve Foundation. // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, this // list of conditions and the following disclaimer. // // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // - Neither the name of the Outercurve Foundation nor the names of its // contributors may be used to endorse or promote products derived from this // software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using System; using System.Collections; using System.Collections.Generic; using System.Text; using OrderBoxCoreLib; using OrderBoxDomainsLib; using WebsitePanel.EnterpriseServer; using System.IO; using System.Reflection; using System.Diagnostics; namespace WebsitePanel.Ecommerce.EnterpriseServer { public class DirectiRegistrar : SystemPluginBase, IDomainRegistrar { static DirectiRegistrar() { // Resolve OrderBoxCoreLib library AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_OrderBoxCoreLib_AssemblyResolve); // Resolve OrderBoxDomains library AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_OrderBoxDomainsLib_AssemblyResolve); } static System.Reflection.Assembly CurrentDomain_OrderBoxCoreLib_AssemblyResolve(object sender, ResolveEventArgs args) { // if (!args.Name.Contains("OrderBoxCoreLib")) return null; // string assemblyFile = String.Empty; // if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("ProgramFiles(x86)"))) { assemblyFile = Path.Combine(Environment.GetEnvironmentVariable("ProgramFiles(x86)"), "OrderBoxCoreLib\\OrderBoxCoreLib.dll"); } else { assemblyFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "OrderBoxCoreLib\\OrderBoxCoreLib.dll"); } // if (!File.Exists(assemblyFile)) { // EventLog.WriteEntry("WEBSITEPANELES:DIRECTI", "OrderBoxCoreLib assembly could not be found at " + assemblyFile, EventLogEntryType.Information); return null; } // return Assembly.LoadFrom(assemblyFile); } static System.Reflection.Assembly CurrentDomain_OrderBoxDomainsLib_AssemblyResolve(object sender, ResolveEventArgs args) { // if (!args.Name.Contains("OrderBoxDomainsLib")) return null; // string assemblyFile = String.Empty; // if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("ProgramFiles(x86)"))) { assemblyFile = Path.Combine(Environment.GetEnvironmentVariable("ProgramFiles(x86)"), "OrderBoxDomainsLib\\OrderBoxDomainsLib.dll"); } else { assemblyFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "OrderBoxDomainsLib\\OrderBoxDomainsLib.dll"); } // if (!File.Exists(assemblyFile)) { // EventLog.WriteEntry("WEBSITEPANELES:DIRECTI", "OrderBoxDomainsLib assembly could not be found at " + assemblyFile, EventLogEntryType.Information); return null; } // return Assembly.LoadFrom(assemblyFile); } #region Registrar's constants public const string DEMO_SERVICE_URL = "http://api.onlyfordemo.net/anacreon/servlet/APIv3-XML"; public const string LIVE_SERVICE_URL = "http://www.myorderbox.com/anacreon/servlet/APIv3-XML"; public const string DEMO_SECURE_SERVICE_URL = "https://api.onlyfordemo.net/anacreon/servlet/APIv3-XML"; public const string LIVE_SECURE_SERVICE_URL = "https://www.myorderbox.com/anacreon/servlet/APIv3-XML"; public const string SERVICE_LANGUAGE = "en"; public const string RESELLER_ROLE = "reseller"; public const string CONTACT_ID = "contactid"; public const string NO_INVOICE = "NoInvoice"; public const string STATUS = "status"; public const string ENTITY_ID = "entityid"; public const string NO_OF_YEARS = "noofyears"; public const string EXPIRY_DATE = "expirydate"; public const string ENDTIME = "endtime"; public const string EAQID = "eaqid"; public const string ACTION_STATUS_DESC = "actionstatusdesc"; public const string ERROR = "error"; public const string RECORDS_ON_PAGE = "recsonpage"; public const string RECORDS_IN_DB = "recsindb"; #endregion #region Properties public override string[] SecureSettings { get { return new string[] { DirectiSettings.PASSWORD }; } } /// /// Gets whether plug-in use SSL secure channel /// public bool SecureChannel { get { return Convert.ToBoolean(PluginSettings[DirectiSettings.SECURE_CHANNEL]); } } /// /// Gets whether plug-in running in live mode /// public bool LiveMode { get { return Convert.ToBoolean(PluginSettings[DirectiSettings.LIVE_MODE]); } } /// /// Gets service username /// public string Username { get { return PluginSettings[DirectiSettings.USERNAME]; } } /// /// Gets service password /// public string Password { get { return PluginSettings[DirectiSettings.PASSWORD]; } } /// /// Gets service account parent id /// public int ParentId { get { return Convert.ToInt32(PluginSettings[DirectiSettings.PARENT_ID]); } } /// /// Gets service url /// public string ServiceUrl { get { if (LiveMode) { if (SecureChannel) return LIVE_SECURE_SERVICE_URL; // return unsecured service url return LIVE_SERVICE_URL; } if (SecureChannel) return DEMO_SECURE_SERVICE_URL; // return unsecured channel return DEMO_SERVICE_URL; } } public bool SubAccountRequired { get { return true; } } #endregion #region Helper routines private static string[] GetDomainNames(params string[] domains) { List names = new List(); foreach (string domain in domains) { string[] parts = domain.Split('.'); names.Add(parts[0]); } return names.ToArray(); } private static string[] GetTopLevelDomains(params string[] domains) { int length = domains.Length; List tlds = new List(); foreach (string domain in domains) { string[] parts = domain.Split('.'); tlds.Add(parts[1]); } return tlds.ToArray(); } private string GetDialingAreaCode(string phone) { if (String.IsNullOrEmpty(phone)) return "000"; char[] symbols = phone.ToCharArray(); StringBuilder builder = new StringBuilder(); int count = 0, index = 0; while (count < 3 && index < symbols.Length) { if (Char.IsDigit(symbols[index])) { builder.Append(symbols[index]); count++; } index++; } return builder.ToString(); } private string GetDialingNumber(string number) { if (String.IsNullOrEmpty(number)) return "00000000000"; StringBuilder builder = new StringBuilder(); char[] symbols = number.ToCharArray(); int count = 0, index = 0; while (index < symbols.Length) { if (count == 3 && Char.IsDigit(symbols[index])) builder.Append(symbols[index]); else if (Char.IsDigit(symbols[index])) count++; index++; } return builder.ToString(); } private string GetCompanyName(string companyName) { if (String.IsNullOrEmpty(companyName)) return "For Personal Usage Only"; return companyName; } private string GetAddress(string address) { if (String.IsNullOrEmpty(address)) return "-"; return address; } #endregion #region IDomainRegistrar Members private string registrarName; public string RegistrarName { get { return registrarName; } set { registrarName = value; } } public void AssemlyResolverTest() { // OrderBoxCoreLib test Customer customer = new Customer(); // OrderBoxDomainsLib test DomOrder domOrder = new DomOrder(); } public bool CheckSubAccountExists(string emailAddress) { if (String.IsNullOrEmpty(emailAddress)) throw new ArgumentNullException("emailAddress"); // check sub account exists OrderBoxCoreLib.APIKit.Properties.Url = ServiceUrl; // create an instance OrderBoxCoreLib.Customer customer = new OrderBoxCoreLib.Customer(); // search a user by email address Hashtable srchResults = customer.list(Username, Password, RESELLER_ROLE, SERVICE_LANGUAGE, ParentId, null, null, emailAddress, null, null, null, null, null, null, null, null, null, 10, 1, null); // check search result if (Convert.ToInt32(srchResults[RECORDS_ON_PAGE]) > 0 && Convert.ToInt32(srchResults[RECORDS_IN_DB]) > 0) return true; // customer account not found return false; } public int GetCustomerAccountId(string emailAddress) { // check email address if (String.IsNullOrEmpty(emailAddress)) throw new ArgumentNullException("emailAddress"); // create a customer OrderBoxCoreLib.APIKit.Properties.Url = ServiceUrl; // init customer api OrderBoxCoreLib.Customer customer = new OrderBoxCoreLib.Customer(); // check does the user is already Directi customer int customerId = customer.getCustomerId(Username, Password, RESELLER_ROLE, SERVICE_LANGUAGE, ParentId, emailAddress); // throws an exception if (customerId <= 0) throw new Exception("Couldn't find customer with the specified email: " + emailAddress); // return customerId; } public int GetDefaultContactId(int customerId) { // Default Contact Section OrderBoxDomainsLib.APIKit.Properties.Url = ServiceUrl; // init contact api OrderBoxDomainsLib.DomContact contact = new OrderBoxDomainsLib.DomContact(); // check whether a contact is already exists Hashtable ctHash = contact.listNames(Username, Password, RESELLER_ROLE, SERVICE_LANGUAGE, ParentId, customerId); // throws an exception if (!ctHash.ContainsKey("1")) throw new Exception("Couldn't find default contact for the specified account"); // gets contact info Hashtable infoHash = (Hashtable)ctHash["1"]; // return result return Convert.ToInt32(infoHash[CONTACT_ID]); } public int CreateCustomerAccount(ContractAccount accountInfo) { // setup url OrderBoxCoreLib.APIKit.Properties.Url = ServiceUrl; // init customer api OrderBoxCoreLib.Customer customer = new OrderBoxCoreLib.Customer(); // create customer account if it doesn't exist int customerId = customer.addCustomer(Username, Password, RESELLER_ROLE, SERVICE_LANGUAGE, ParentId, accountInfo[ContractAccount.EMAIL], accountInfo[ContractAccount.PASSWORD], String.Concat(accountInfo[ContractAccount.FIRST_NAME], " ", accountInfo[ContractAccount.LAST_NAME]), GetCompanyName(accountInfo[ContractAccount.COMPANY_NAME]), GetAddress(accountInfo[ContractAccount.ADDRESS]), GetAddress(null), GetAddress(null), accountInfo[ContractAccount.CITY], accountInfo[ContractAccount.STATE], accountInfo[ContractAccount.COUNTRY], accountInfo[ContractAccount.ZIP], GetDialingAreaCode(accountInfo[ContractAccount.PHONE_NUMBER]), GetDialingNumber(accountInfo[ContractAccount.PHONE_NUMBER]), String.Empty, String.Empty, GetDialingAreaCode(accountInfo[ContractAccount.FAX_NUMBER]), GetDialingNumber(accountInfo[ContractAccount.FAX_NUMBER]), "en"); // setup url OrderBoxDomainsLib.APIKit.Properties.Url = ServiceUrl; // init contact api OrderBoxDomainsLib.DomContact contact = new OrderBoxDomainsLib.DomContact(); // create default contact int defaultContactId = contact.addDefaultContact(Username, Password, RESELLER_ROLE, SERVICE_LANGUAGE, ParentId, customerId); // return result return customerId; } public int AddCustomerContact(int customerId, string contactType, ContractAccount accountInfo, Hashtable extraInfo) { // setup url OrderBoxCoreLib.APIKit.Properties.Url = ServiceUrl; // init customer api OrderBoxDomainsLib.DomContact contact = new DomContact(); // create customer account if it doesn't exist int contactId = contact.addContact(Username, Password, RESELLER_ROLE, SERVICE_LANGUAGE, ParentId, String.Concat(accountInfo[ContractAccount.FIRST_NAME], " ", accountInfo[ContractAccount.LAST_NAME]), accountInfo[ContractAccount.COMPANY_NAME], accountInfo[ContractAccount.EMAIL], GetAddress(accountInfo[ContractAccount.ADDRESS]), GetAddress(null), GetAddress(null), accountInfo[ContractAccount.CITY], accountInfo[ContractAccount.STATE], accountInfo[ContractAccount.COUNTRY], accountInfo[ContractAccount.ZIP], GetDialingAreaCode(accountInfo[ContractAccount.PHONE_NUMBER]), GetDialingNumber(accountInfo[ContractAccount.PHONE_NUMBER]), GetDialingAreaCode(accountInfo[ContractAccount.FAX_NUMBER]), GetDialingNumber(accountInfo[ContractAccount.FAX_NUMBER]), customerId, contactType, extraInfo); // return contactId; } public bool IsContactValidForProduct(int contactId, string productKey) { // setup service url OrderBoxDomainsLib.APIKit.Properties.Url = ServiceUrl; // OrderBoxDomainsLib.DomContactExt contactExt = new DomContactExt(); // Hashtable result = contactExt.isValidRegistrantContact(Username, Password, RESELLER_ROLE, SERVICE_LANGUAGE, ParentId, new int[] {contactId}, new string[] { productKey }); // Hashtable product = (Hashtable)result[productKey]; // if (Convert.ToString(product[contactId.ToString()]) == "true") return true; // return false; } public DomainStatus CheckDomain(string domain) { // check domain not empty if (String.IsNullOrEmpty(domain)) throw new ArgumentNullException("domain"); // format values string[] domains = GetDomainNames(domain); string[] tlds = GetTopLevelDomains(domain); // setup service url OrderBoxDomainsLib.APIKit.Properties.Url = ServiceUrl; // init domain order api OrderBoxDomainsLib.DomOrder domOrder = new OrderBoxDomainsLib.DomOrder(); // check domain availability Hashtable directiResult = domOrder.checkAvailabilityMultiple( Username, Password, RESELLER_ROLE, SERVICE_LANGUAGE, ParentId, domains, tlds, false ); // get result by domain Hashtable bunch = (Hashtable)directiResult[domain]; // check result status if (String.Compare((String)bunch[STATUS], "available", true) == 0) return DomainStatus.NotFound; // return result return DomainStatus.Registered; } public void RegisterDomain(DomainNameSvc domainSvc, ContractAccount accountInfo, string[] nameServers) { int customerId = 0; // 1. check customer exists if (CheckSubAccountExists(accountInfo[ContractAccount.EMAIL])) customerId = GetCustomerAccountId(accountInfo[ContractAccount.EMAIL]); else customerId = CreateCustomerAccount(accountInfo); // obtain default contact id int contactId = GetDefaultContactId(customerId); // check for demo mode if so then set demo-nameservers. if (!LiveMode) nameServers = new string[] { "ns1.onlyfordemo.net", "ns2.onlyfordemo.net" }; // fill parameters hashtable Hashtable domainHash = new Hashtable(); // copy domain name domainHash[domainSvc.Fqdn] = domainSvc.PeriodLength.ToString(); // setup service url OrderBoxDomainsLib.APIKit.Properties.Url = ServiceUrl; // init domain order api OrderBoxDomainsLib.DomOrder domOrder = new OrderBoxDomainsLib.DomOrder(); // int validateAttempts = 0; VALIDATE_REGISTRATION: // validate params Hashtable valResult = domOrder.validateDomainRegistrationParams(Username, Password, RESELLER_ROLE, SERVICE_LANGUAGE, ParentId, domainHash, new ArrayList(nameServers), contactId, contactId, contactId, contactId, customerId, NO_INVOICE); // get domain name hashtable valResult = (Hashtable)valResult[domainSvc.Fqdn]; // check validation status if ((String)valResult[STATUS] == "error") { // try to update extended contact fields and re-validate params if (validateAttempts == 0 && domainSvc.Fqdn.EndsWith(".us")) { validateAttempts++; // OrderBoxDomainsLib.DomContactExt contactExt = new DomContactExt(); // fill extension hash Hashtable exthash = new Hashtable(); Hashtable domus = new Hashtable(); domus["nexusCategory"] = domainSvc["NexusCategory"]; domus["applicationPurpose"] = domainSvc["ApplicationPurpose"]; exthash["domus"] = domus; // set default contact extensions bool succeed = contactExt.setContactDetails(Username, Password, RESELLER_ROLE, SERVICE_LANGUAGE, ParentId, contactId, exthash, "domus"); // check result if (succeed) goto VALIDATE_REGISTRATION; } // throw new Exception((String)valResult[ERROR]); } // register domain Hashtable orderResult = domOrder.addWithoutValidation(Username, Password, RESELLER_ROLE, SERVICE_LANGUAGE, ParentId, domainHash, new ArrayList(nameServers), contactId, contactId, contactId, contactId, customerId, NO_INVOICE); // switch to the nested data bunch orderResult = (Hashtable)orderResult[domainSvc.Fqdn]; // check returned status switch ((String)orderResult[STATUS]) { case "error": // error throw new Exception(Convert.ToString(orderResult[ERROR])); case "Failed": // error throw new Exception(Convert.ToString(orderResult[ACTION_STATUS_DESC])); case "Success": // success case "InvoicePaid": // success // we are success so copy order number domainSvc[EAQID] = Convert.ToString(orderResult[EAQID]); domainSvc[ENTITY_ID] = Convert.ToString(orderResult[ENTITY_ID]); break; } } public void RenewDomain(DomainNameSvc domainSvc, ContractAccount accountInfo, string[] nameServers) { int customerId = GetCustomerAccountId(accountInfo[ContractAccount.EMAIL]); // setup service url OrderBoxDomainsLib.APIKit.Properties.Url = ServiceUrl; // init domain order api OrderBoxDomainsLib.DomOrder domOrder = new OrderBoxDomainsLib.DomOrder(); // Get all domain name registration details Hashtable domainDetails = domOrder.getDetailsByDomain(Username, Password, RESELLER_ROLE, SERVICE_LANGUAGE, ParentId, domainSvc.Fqdn, new ArrayList { "All" }); // fill parameters hashtable Hashtable domainHash = new Hashtable { { domainSvc.Fqdn, new Hashtable { {ENTITY_ID, domainDetails[ENTITY_ID]}, {NO_OF_YEARS, domainSvc.PeriodLength.ToString()}, {EXPIRY_DATE, domainDetails[ENDTIME]} } } }; // Send renewal request to the registrar Hashtable orderResult = domOrder.renewDomain(Username, Password, RESELLER_ROLE, SERVICE_LANGUAGE, ParentId, domainHash, NO_INVOICE); // switch to the nested data bunch of the result received orderResult = (Hashtable)orderResult[domainSvc.Fqdn]; // check returned status switch ((String)orderResult[STATUS]) { case "error": // error throw new Exception(Convert.ToString(orderResult[ERROR])); case "Failed": // error throw new Exception(Convert.ToString(orderResult[ACTION_STATUS_DESC])); case "Success": // success case "InvoicePaid": // success // we are success so copy order number domainSvc[EAQID] = Convert.ToString(orderResult[EAQID]); domainSvc[ENTITY_ID] = Convert.ToString(orderResult[ENTITY_ID]); break; } } public TransferDomainResult TransferDomain(CommandParams args, DomainContacts contacts) { throw new NotSupportedException(); } #endregion } }