QCloudDnsChallengeHandler.cs

using ACMESharp.ACME;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace ACMESharp.Providers.QCloud
{
    public class QCloudDnsChallengeHandler : IChallengeHandler
    {
        public string SecretId { get; set; }
        public string SecretKey { get; set; }
        public string Line { get; set; } = "默认";
 
        public bool IsDisposed { get; private set; }
 
        public void CleanUp(ChallengeHandlingContext ctx)
        {
            throw new NotSupportedException("provider does not support clean up");
        }
 
        public void Dispose()
        {
            IsDisposed = true;
        }
 
        public void Handle(ChallengeHandlingContext ctx)
        {
            if (string.IsNullOrEmpty(SecretId))
                throw new ArgumentNullException(nameof(SecretId));
            if (string.IsNullOrEmpty(SecretKey))
                throw new ArgumentNullException(nameof(SecretKey));
            if (string.IsNullOrEmpty(Line))
                throw new ArgumentNullException(nameof(Line));
 
            DnsChallenge dnsChallenge = (DnsChallenge)ctx.Challenge;
 
            var cns = new QCloudAPI_SDK.Module.Cns();
            cns.setConfig(new SortedDictionary<string, object>(StringComparer.Ordinal) { { "SecretId", SecretId }, { "SecretKey", SecretKey }, { "RequestMethod", "GET" } });
 
            var recordName = dnsChallenge.RecordName;
            var topAndSecondLevelName = new StringBuilder();
            var subDomainName = new StringBuilder();
            byte level = 0;
            for (int i = recordName.Length - 1; i >= 0; i--)
            {
                if (recordName[i] == '.' && level < 2)
                    level++;
                if (level < 2)
                    topAndSecondLevelName.Insert(0, recordName[i]);
                else
                    subDomainName.Insert(0, recordName[i]);
            }
            ctx.Out.WriteLine("Getting domain information for " + recordName + '.');
            var recordListResponse = (JObject)JsonConvert.DeserializeObject(cns.Call("RecordList", new SortedDictionary<string, object>(StringComparer.Ordinal)
            {
                {"domain", topAndSecondLevelName },
                {"offset", 0 },
                {"length", 100 },
                {"subDomain", subDomainName },
                {"recordType", "TXT" },
            }));
 
            ThrowQCloudError(recordListResponse);
 
            var record = (JArray)recordListResponse["data"]["records"];
 
            ctx.Out.WriteLine(record.Count + " existing record for " + recordName + " is found.");
 
            if (record.Count == 1)
            {
                //If record already exist.
                ctx.Out.WriteLine("Adding new record " + subDomainName + " in domain " + topAndSecondLevelName + ".");
                var domainListResponse = (JObject)JsonConvert.DeserializeObject(cns.Call("RecordModify", new SortedDictionary<string, object>(StringComparer.Ordinal)
                {
                    {"domain", topAndSecondLevelName },
                    {"recordId", (int)record[0]["id"] },
                    {"subDomain", subDomainName },
                    {"recordType", "TXT" },
                    {"recordLine", (string)record[0]["line"] },
                    {"value", dnsChallenge.RecordValue },
                }));
                ThrowQCloudError(domainListResponse);
                ctx.Out.WriteLine("Updated DNS record of type [TXT] with name [{0}]",
                        dnsChallenge.RecordName);
            }
            else if (record.Count == 0)
            {
                //If record does not exist.
                ctx.Out.WriteLine("Updating record " + subDomainName + " in domain " + topAndSecondLevelName + ".");
                var domainListResponse = (JObject)JsonConvert.DeserializeObject(cns.Call("RecordCreate", new SortedDictionary<string, object>(StringComparer.Ordinal)
                {
                    {"domain", topAndSecondLevelName },
                    {"subDomain", subDomainName },
                    {"recordType", "TXT" },
                    {"recordLine", Line },
                    {"value", dnsChallenge.RecordValue },
                }));
                ThrowQCloudError(domainListResponse);
                ctx.Out.WriteLine("Created DNS record of type [TXT] with name [{0}]",
                        dnsChallenge.RecordName);
            }
            else
            {
                throw new InvalidOperationException("There should not be more than one DNS txt record for the name.");
            }
        }
 
        private static void ThrowQCloudError(JObject response)
        {
            if ((int)response["code"] != 0)
            {
                throw new QCloudCnsRequestException("Error requesting DNS data from QCloud CNS. " + response["message"].ToString());
            }
 
        }
    }
}