diff --git a/.gitignore b/.gitignore
index 27ae6f1..9b121a2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -373,3 +373,6 @@ FodyWeavers.xsd
# Local History for Visual Studio Code
.history/
+# TestResults & Packages
+packages/
+TestResults/
diff --git a/Cloudfare DNS Updater.sln b/Cloudfare DNS Updater.sln
new file mode 100644
index 0000000..878f8e2
--- /dev/null
+++ b/Cloudfare DNS Updater.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29230.47
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cloudfare DNS Updater", "Cloudfare DNS Updater\Cloudfare DNS Updater.csproj", "{3D48B0D8-39A9-4C68-841D-8D8764F2501E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudflareDNSTests", "CloudflareDNSTests\CloudflareDNSTests.csproj", "{B9DBC686-8430-4F83-9E27-012844B6CBBB}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {3D48B0D8-39A9-4C68-841D-8D8764F2501E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3D48B0D8-39A9-4C68-841D-8D8764F2501E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3D48B0D8-39A9-4C68-841D-8D8764F2501E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3D48B0D8-39A9-4C68-841D-8D8764F2501E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B9DBC686-8430-4F83-9E27-012844B6CBBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B9DBC686-8430-4F83-9E27-012844B6CBBB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B9DBC686-8430-4F83-9E27-012844B6CBBB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B9DBC686-8430-4F83-9E27-012844B6CBBB}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {6C21ED63-C9F0-402E-9295-68A38F11BEFC}
+ EndGlobalSection
+EndGlobal
diff --git a/Cloudfare DNS Updater/App.config b/Cloudfare DNS Updater/App.config
new file mode 100644
index 0000000..56efbc7
--- /dev/null
+++ b/Cloudfare DNS Updater/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Cloudfare DNS Updater/Cloudfare DNS Updater.csproj b/Cloudfare DNS Updater/Cloudfare DNS Updater.csproj
new file mode 100644
index 0000000..7ed6ba8
--- /dev/null
+++ b/Cloudfare DNS Updater/Cloudfare DNS Updater.csproj
@@ -0,0 +1,72 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {3D48B0D8-39A9-4C68-841D-8D8764F2501E}
+ Exe
+ Cloudfare_DNS_Updater
+ Cloudfare DNS Updater
+ v4.7.2
+ 512
+ true
+ true
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll
+
+
+
+
+ ..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll
+
+
+ ..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll
+
+
+ ..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll
+
+
+ ..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll
+
+
+ ..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Cloudfare DNS Updater/Program.cs b/Cloudfare DNS Updater/Program.cs
new file mode 100644
index 0000000..57a853d
--- /dev/null
+++ b/Cloudfare DNS Updater/Program.cs
@@ -0,0 +1,472 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.IO;
+using System.Net;
+using System.Threading;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Data;
+using System.Web.Helpers;
+using System.Web.Razor.Text;
+using System.ComponentModel;
+
+namespace Cloudfare_DNS_Updater
+{
+ public class Program
+ {
+ static bool silent = false;
+ public static readonly string[] IPHelperURLS = new string[]
+ {
+ "http://ifconfig.me/ip",
+ "http://ifconfig.co/ip",
+ "http://ident.me/"
+ };
+
+ public enum StatusCode
+ {
+ Normal,
+ IpUpdated,
+ IpGetFailiure,
+ FileWriteFailiure,
+ GetRecordFailiure,
+ SetRecordFailiure
+ }
+
+ static Task[] currentTasks;
+ static void Main(string[] args)
+ {
+ StatusCode status = StatusCode.Normal;
+ if (args.Contains("\\s"))
+ {
+ silent = true;
+ }
+ // Load the data to be used
+ object[] loadState = LoadData(Environment.CurrentDirectory + "\\Credentials.dat");
+ status = (StatusCode)loadState[0];
+ if(status == StatusCode.Normal)
+ {
+ List authorities = (List)loadState[1];
+ foreach (Authority authority in authorities)
+ {
+ status = Task.Run(() => GetRequest(authority)).Result;
+ Console.WriteLine(status.ToString());
+ }
+ }
+ if(currentTasks != null && currentTasks.Length > 0)
+ {
+ Task.WaitAll(currentTasks);
+ }
+ Environment.Exit((int)status);
+ }
+
+ static async Task GetRequest(Authority authority)
+ {
+ StatusCode status = StatusCode.Normal;
+ string currentIp = "";
+ string localIp = "";
+ string type = "";
+ int ttl = 0;
+ bool proxiedstate = false;
+
+ using (HttpClient ipGrabber = new HttpClient())
+ {
+ bool validIp = false;
+ int domainInc = 0;
+ while (!validIp && domainInc < IPHelperURLS.Length)
+ {
+ HttpResponseMessage httpResponse = await ipGrabber.GetAsync(IPHelperURLS[domainInc]);
+ if (httpResponse.IsSuccessStatusCode)
+ {
+ string provided_ip = await httpResponse.Content.ReadAsStringAsync();
+ provided_ip = provided_ip.Trim();
+ IPAddress address = null;
+ if (IPAddress.TryParse(provided_ip, out address))
+ {
+ localIp = provided_ip;
+ validIp = true;
+ Console.WriteLine("Our IP: " + provided_ip);
+ }
+ }
+ domainInc++;
+ }
+ }
+ if (localIp != "")
+ {
+ HttpClient httpClient = new HttpClient();
+ httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", " Bearer " + authority.KeyTag.EvaluateAll());
+ httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json");
+ HttpCompletionOption httpCompletionOption = HttpCompletionOption.ResponseContentRead;
+
+ // Get the current settings
+ HttpResponseMessage response = await httpClient.GetAsync(Authority.cloudfare_api_url + "zones/" + authority.ZoneTag.EvaluateAll() + "/dns_records/" + authority.DnsTag.EvaluateAll(), httpCompletionOption, CancellationToken.None);
+ if (response.IsSuccessStatusCode)
+ {
+ using (HttpContent content = response.Content)
+ {
+ Console.WriteLine("Retrieving IP data from the server");
+ string s = await content.ReadAsStringAsync();
+ dynamic recieved_content = Json.Decode(s);
+ currentIp = recieved_content.result.content;
+ type = recieved_content.result.type;
+ ttl = recieved_content.result.ttl;
+ proxiedstate = recieved_content.result.proxied;
+ }
+ // Now check if the IP matches...
+ if (currentIp != localIp)
+ {
+ Console.WriteLine("IP {0} doesn't match our current IP {1}. Updating...", currentIp, localIp);
+ Dictionary UpdateContent = new Dictionary();
+ UpdateContent.Add("type", type);
+ UpdateContent.Add("name", authority.DomainTag.EvaluateAll());
+ UpdateContent.Add("content", localIp); // IP Field. Update this as necessary
+ UpdateContent.Add("ttl", ttl);
+ UpdateContent.Add("proxied", proxiedstate);
+ string updateContent = Json.Encode(UpdateContent);
+ byte[] putBytes = Encoding.UTF8.GetBytes(updateContent);
+ HttpContent putContent = new ByteArrayContent(putBytes);
+ HttpResponseMessage putResponse = await httpClient.PutAsync(Authority.cloudfare_api_url + "zones/" + authority.ZoneTag.EvaluateAll() + "/dns_records/" + authority.DnsTag.EvaluateAll(), putContent);
+ if (!putResponse.IsSuccessStatusCode)
+ {
+ status = StatusCode.SetRecordFailiure;
+ }
+ else
+ {
+ status = StatusCode.IpUpdated;
+ }
+ Console.WriteLine("Got {0} updating IP to {1}", putResponse.StatusCode, localIp);
+ }
+ else
+ {
+ Console.WriteLine("DNS IP {0} matches our IP", currentIp);
+ }
+ }
+ else
+ {
+ status = StatusCode.GetRecordFailiure;
+ }
+ }
+ else
+ {
+ status = StatusCode.IpGetFailiure;
+ }
+ return status;
+ }
+
+ public static object[] LoadData(string filePath)
+ {
+ StatusCode status = StatusCode.Normal;
+ // Decode or encode
+ try
+ {
+ Console.WriteLine("Reading data...");
+ List authorities = new List(5);
+ using (FileStream fileStream = File.OpenRead(filePath))
+ {
+ const string EndTag = "-###";
+ List authoritySections = new List(5);
+ long[] section = new long[] { 0, fileStream.Length };
+ string tag = "";
+ while(fileStream.Position < fileStream.Length)
+ {
+ char c = (char)fileStream.ReadByte();
+ if (tag == EndTag)
+ {
+ section[1] = fileStream.Position - EndTag.Length;
+ authoritySections.Add(section);
+ section = new long[] { fileStream.Position, fileStream.Length };
+ tag = "";
+ }
+ else if (c == EndTag[tag.Length])
+ {
+ tag += c;
+ }
+ else
+ {
+ tag = "";
+ }
+ }
+ authoritySections.Add(section);
+ foreach (long[] foundSection in authoritySections)
+ {
+ Authority authority = new Authority();
+ authority.ReadValues(fileStream, foundSection[0], foundSection[1]);
+ authorities.Add(authority);
+ }
+ }
+
+ return new object[] { status, authorities };
+ }
+ catch (FileNotFoundException e)
+ {
+ if (silent)
+ {
+ // If the app is running in silent, we have no vector to supply new data, so throw the exception
+ throw e;
+ }
+ else
+ {
+ Console.WriteLine("File not found.");
+ Console.WriteLine("Please enter the Domain: ");
+ string domain = Console.ReadLine();
+ Console.WriteLine("Please enter the Authorisation Email Address: ");
+ string email = Console.ReadLine();
+ Console.WriteLine("Please enter the Authorisation Key: ");
+ string key = Console.ReadLine();
+ Console.WriteLine("Please enter the Zone ID: ");
+ string zone = Console.ReadLine();
+ Console.WriteLine("Please enter the Dns ID: ");
+ string dns = Console.ReadLine();
+ // Schedule an update to the credentials file (runs asynchronously as it may encounter io errors)
+ if (currentTasks == null)
+ {
+ currentTasks = new Task[] { Task.Run(() => WriteFile(Environment.CurrentDirectory + "\\Credentials.dat", new string[] { Authority.auth_domain_tag + " = " + domain, Authority.auth_email_tag + " = " + email, Authority.auth_key_tag + " = " + key, Authority.auth_zone_tag + " = " + zone, Authority.auth_dns_tag + " = " + dns })) };
+ }
+ else
+ {
+ currentTasks.Append(Task.Run(() => WriteFile(Environment.CurrentDirectory + "\\Credentials.dat", new string[] { Authority.auth_domain_tag + " = " + domain, Authority.auth_email_tag + " = " + email, Authority.auth_key_tag + " = " + key, Authority.auth_zone_tag + " = " + zone, Authority.auth_dns_tag + " = " + dns })));
+ }
+ Authority authority = new Authority();
+ authority.DnsTag = authority.ReadBytes(new MemoryStream(Encoding.UTF8.GetBytes(dns)), 0, Encoding.UTF8.GetBytes(dns).Length);
+ authority.DomainTag = authority.ReadBytes(new MemoryStream(Encoding.UTF8.GetBytes(domain)), 0, Encoding.UTF8.GetBytes(domain).Length);
+ authority.EmailTag = authority.ReadBytes(new MemoryStream(Encoding.UTF8.GetBytes(email)), 0, Encoding.UTF8.GetBytes(email).Length);
+ authority.KeyTag = authority.ReadBytes(new MemoryStream(Encoding.UTF8.GetBytes(key)), 0, Encoding.UTF8.GetBytes(key).Length);
+ authority.ZoneTag = authority.ReadBytes(new MemoryStream(Encoding.UTF8.GetBytes(zone)), 0, Encoding.UTF8.GetBytes(zone).Length);
+ List authorities = new List(1);
+ return new object[] { status , authorities };
+ }
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ status = StatusCode.FileWriteFailiure;
+ return new object[] { status };
+ }
+ }
+ public static void WriteFile(string path, string[] data)
+ {
+ bool success = false;
+ int attemptLimit = 5;
+ int attemptsCount = 0;
+ while (!success && attemptsCount < attemptLimit)
+ {
+ try
+ {
+ FileStream fileStream = File.OpenWrite(path);
+ foreach (var line in data)
+ {
+ fileStream.Write(Encoding.UTF8.GetBytes(line + Environment.NewLine), 0, Encoding.UTF8.GetBytes(line + Environment.NewLine).Length);
+ }
+ success = true;
+ fileStream.Dispose();
+ }
+ catch
+ {
+ attemptsCount++;
+ Thread.Sleep(500);
+ }
+ }
+ }
+ }
+ public class Authority : IDisposable
+ {
+ public const string auth_domain_tag = "X-AUTH-DOMAIN";
+ public const string auth_email_tag = "X-AUTH-EMAIL";
+ public const string auth_key_tag = "X-AUTH-KEY";
+ public const string auth_zone_tag = "X-AUTH-ZONE";
+ public const string auth_dns_tag = "X-AUTH-DNS";
+ public const string cloudfare_api_url = "https://api.cloudflare.com/client/v4/";
+
+ public ObfusctedBytes DomainTag { get; set; }
+ public ObfusctedBytes EmailTag { get; set; }
+ public ObfusctedBytes KeyTag { get; set; }
+ public ObfusctedBytes ZoneTag { get; set; }
+ public ObfusctedBytes DnsTag { get; set; }
+
+ public void Dispose()
+ {
+ if (DomainTag != null) DomainTag.Dispose();
+ if (EmailTag != null) EmailTag.Dispose();
+ if (KeyTag != null) KeyTag.Dispose();
+ if (ZoneTag != null) ZoneTag.Dispose();
+ if (DnsTag != null) DnsTag.Dispose();
+ }
+
+ public void ReadValues(Stream source, long start=-1, long end=-1)
+ {
+ if (start == -1) start = source.Position;
+ else source.Position = start;
+ if (end == -1) end = source.Length;
+ // Start by finding the constraints of our pairs
+ Dictionary keyValuePairs = new Dictionary(5);
+ long[] constraints = new long[] {start, end};
+ long returnPos = -1;
+ bool findData = false;
+ string key = "";
+ while (source.Position < end)
+ {
+ int r = source.ReadByte();
+ if(findData)
+ {
+ while (r == ' ')
+ {
+ r = source.ReadByte();
+ }
+ findData = false;
+ long currentPos = source.Position;
+ source.Position = start;
+ for (int i = 0; i < currentPos; i++)
+ {
+ Console.Write((char)source.ReadByte());
+ }
+ constraints[0] = source.Position;
+ }
+ else if(r == '=')
+ {
+ findData = true;
+ }
+ else if(r == '\r')
+ {
+ returnPos = source.Position;
+ }
+ else if(r == '\n')
+ {
+ constraints[1] = (returnPos > -1) ? returnPos : source.Position;
+ returnPos = -1;
+ keyValuePairs.Add(key, constraints);
+ constraints = new long[] {source.Position, end };
+ key = "";
+ }
+ // If this value would match
+ else if(auth_domain_tag.Contains(key + (char)r) ||
+ auth_dns_tag.Contains(key + (char)r) ||
+ auth_email_tag.Contains(key + (char)r) ||
+ auth_key_tag.Contains(key + (char)r) ||
+ auth_zone_tag.Contains(key + (char)r))
+ {
+ key += (char)r;
+ }
+
+ }
+ keyValuePairs.Add(key, constraints);
+ // Use the keys to create our objects
+ foreach (var item in keyValuePairs)
+ {
+ switch (item.Key)
+ {
+ case auth_domain_tag:
+ DomainTag = ReadBytes(source, item.Value[0], item.Value[1]);
+ break;
+ case auth_dns_tag:
+ DnsTag = ReadBytes(source, item.Value[0], item.Value[1]);
+ break;
+ case auth_email_tag:
+ EmailTag = ReadBytes(source, item.Value[0], item.Value[1]);
+ break;
+ case auth_key_tag:
+ KeyTag = ReadBytes(source, item.Value[0], item.Value[1]);
+ break;
+ case auth_zone_tag:
+ ZoneTag = ReadBytes(source, item.Value[0], item.Value[1]);
+ break;
+ default:
+ break;
+ }
+ }
+
+ }
+ public ObfusctedBytes ReadBytes(Stream source, long start, long end)
+ {
+ source.Position = start-1;
+ ObfusctedBytes bytes = new ObfusctedBytes(source.ReadByte());
+ while (source.Position < end-1)
+ {
+ bytes.LinkNext(source.ReadByte());
+ }
+ return bytes;
+ }
+
+ ///
+ /// An obfuscated byte helps mask the data in memory.
+ /// Based on a linked-list, data should not be expected to be contiguous.
+ /// Also includes simple bitwise motion to prevent passerby reading.
+ ///
+ public class ObfusctedBytes : IDisposable
+ {
+ ObfusctedBytes nextByte = null;
+ int position;
+ private readonly int mask = 0b_1110_0011;
+ byte[] values;
+
+ public ObfusctedBytes(int value, int position=0)
+ {
+ Random prngle = new Random();
+ this.position = position;
+ int byte1 = prngle.Next(0, 255); // start with a base number
+ byte1 &= mask; // Zero our target bits
+ byte1 |= ((value >> 5) << 2); // bitshift the value and mask it into the byte
+
+ int byte2 = prngle.Next(0, 255);
+ byte2 &= mask;
+ byte2 |= value & ~mask;
+
+ int byte3 = prngle.Next(0, 255);
+ byte3 &= mask;
+ byte3 |= (value & 0b_0000_0011) << 2;
+
+ values = new byte[] { (byte)byte1,(byte)byte2,(byte)byte3};
+ }
+ ///
+ /// Evaluates the current byte, from the provided data
+ ///
+ /// an int representing the original data
+ private int Evaluate()
+ {
+ int mask = 0b_1110_0011;
+ return (((values[0] & ~mask) << 3) | (values[1] & ~mask) | ((values[2] >> 2) & 0b_0000_0011));
+ }
+
+ public string EvaluateAll()
+ {
+ string result = string.Empty + (char)Evaluate();
+ ObfusctedBytes obfusctedBytes = this;
+ while(obfusctedBytes.nextByte != null)
+ {
+ int t = obfusctedBytes.nextByte.Evaluate();
+ result += (char)t;
+ obfusctedBytes = obfusctedBytes.nextByte;
+ }
+ return result;
+ }
+
+ public void LinkNext(int value)
+ {
+ int nextPosition = position;
+ ObfusctedBytes nextElement = this;
+ while (nextElement.nextByte != null)
+ {
+ nextElement = nextElement.nextByte;
+ nextPosition++;
+ }
+ ObfusctedBytes nextByte = new ObfusctedBytes(value, ++nextPosition);
+ nextElement.nextByte = nextByte;
+ }
+
+ public void Dispose()
+ {
+ if (nextByte != null)
+ {
+ nextByte.Dispose();
+ }
+ for (int i = 0; i < values.Length; i++)
+ {
+ values[i] = 0;
+ }
+ values = null;
+ nextByte = null;
+ }
+ }
+ }
+}
diff --git a/Cloudfare DNS Updater/Properties/AssemblyInfo.cs b/Cloudfare DNS Updater/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..17f5ea5
--- /dev/null
+++ b/Cloudfare DNS Updater/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Cloudfare DNS Updater")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Cloudfare DNS Updater")]
+[assembly: AssemblyCopyright("Copyright © 2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("3d48b0d8-39a9-4c68-841d-8d8764f2501e")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Cloudfare DNS Updater/packages.config b/Cloudfare DNS Updater/packages.config
new file mode 100644
index 0000000..3eaa60e
--- /dev/null
+++ b/Cloudfare DNS Updater/packages.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CloudflareDNSTests/CloudflareDNSTests.csproj b/CloudflareDNSTests/CloudflareDNSTests.csproj
new file mode 100644
index 0000000..19fe897
--- /dev/null
+++ b/CloudflareDNSTests/CloudflareDNSTests.csproj
@@ -0,0 +1,74 @@
+
+
+
+
+
+ Debug
+ AnyCPU
+ {B9DBC686-8430-4F83-9E27-012844B6CBBB}
+ Library
+ Properties
+ CloudflareDNSTests
+ CloudflareDNSTests
+ v4.7.2
+ 512
+ {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ 15.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+ $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
+ False
+ UnitTest
+
+
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ ..\packages\MSTest.TestFramework.2.1.1\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll
+
+
+ ..\packages\MSTest.TestFramework.2.1.1\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {3d48b0d8-39a9-4c68-841d-8d8764f2501e}
+ Cloudfare DNS Updater
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CloudflareDNSTests/Properties/AssemblyInfo.cs b/CloudflareDNSTests/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..7479f94
--- /dev/null
+++ b/CloudflareDNSTests/Properties/AssemblyInfo.cs
@@ -0,0 +1,20 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("CloudflareDNSTests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("CloudflareDNSTests")]
+[assembly: AssemblyCopyright("Copyright © 2020")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+[assembly: ComVisible(false)]
+
+[assembly: Guid("b9dbc686-8430-4f83-9e27-012844b6cbbb")]
+
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/CloudflareDNSTests/UnitTest1.cs b/CloudflareDNSTests/UnitTest1.cs
new file mode 100644
index 0000000..f62547f
--- /dev/null
+++ b/CloudflareDNSTests/UnitTest1.cs
@@ -0,0 +1,72 @@
+using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Cloudfare_DNS_Updater;
+using System.IO;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace CloudflareDNSTests
+{
+ [TestClass]
+ public class UnitTest1
+ {
+ [TestInitialize]
+ public void TestInitilisation()
+ {
+ Program.WriteFile(Environment.CurrentDirectory + "\\Credentials.dat", new string[] { Authority.auth_domain_tag + " = " + "test", Authority.auth_email_tag + " = " + "tester@test.com", Authority.auth_key_tag + " = " + "1234", Authority.auth_zone_tag + " = " + "te", Authority.auth_dns_tag + " = " + "tester" });
+ Program.WriteFile(Environment.CurrentDirectory + "\\CredentialsMultiple.dat",
+ new string[] { Authority.auth_domain_tag + " = " + "test", Authority.auth_email_tag + " = " + "tester@test.com", Authority.auth_key_tag + " = " + "1234", Authority.auth_zone_tag + " = " + "te", Authority.auth_dns_tag + " = " + "tester",
+ "-###",
+ Authority.auth_domain_tag + " = " + "test2", Authority.auth_email_tag + " = " + "tester2@test.com", Authority.auth_key_tag + " = " + "21234", Authority.auth_zone_tag + " = " + "te2", Authority.auth_dns_tag + " = " + "tester2"});
+ }
+
+ [TestCleanup]
+ public void TestCleanup()
+ {
+ int attempts = 0;
+ while (attempts++ < 10)
+ {
+ try
+ {
+ File.Delete(Environment.CurrentDirectory + "\\Credentials.dat");
+ File.Delete(Environment.CurrentDirectory + "\\CredentialsMultiple.dat");
+ attempts = 10;
+ }
+ catch
+ {
+
+ }
+ Thread.Sleep(500);
+ }
+ }
+ [TestMethod]
+ public void TestLoadFile()
+ {
+ object[] data1 = Program.LoadData(Environment.CurrentDirectory + "\\Credentials.dat");
+ List authorities = (List)data1[1];
+ Assert.AreEqual(authorities[0].DomainTag.EvaluateAll(), "test");
+ Assert.AreEqual(authorities[0].EmailTag.EvaluateAll(), "tester@test.com");
+ Assert.AreEqual(authorities[0].KeyTag.EvaluateAll(), "1234");
+ Assert.AreEqual(authorities[0].ZoneTag.EvaluateAll(), "te");
+ Assert.AreEqual(authorities[0].DnsTag.EvaluateAll(), "tester");
+ }
+
+ [TestMethod]
+ public void TestLoadFileDouble()
+ {
+ object[] data1 = Program.LoadData(Environment.CurrentDirectory + "\\CredentialsMultiple.dat");
+ List authorities = (List)data1[1];
+ Assert.AreEqual(authorities[0].DomainTag.EvaluateAll(), "test");
+ Assert.AreEqual(authorities[0].EmailTag.EvaluateAll(), "tester@test.com");
+ Assert.AreEqual(authorities[0].KeyTag.EvaluateAll(), "1234");
+ Assert.AreEqual(authorities[0].ZoneTag.EvaluateAll(), "te");
+ Assert.AreEqual(authorities[0].DnsTag.EvaluateAll(), "tester");
+
+ Assert.AreEqual(authorities[1].DomainTag.EvaluateAll(), "test2");
+ Assert.AreEqual(authorities[1].EmailTag.EvaluateAll(), "tester2@test.com");
+ Assert.AreEqual(authorities[1].KeyTag.EvaluateAll(), "21234");
+ Assert.AreEqual(authorities[1].ZoneTag.EvaluateAll(), "te2");
+ Assert.AreEqual(authorities[1].DnsTag.EvaluateAll(), "tester2");
+ }
+ }
+}
diff --git a/CloudflareDNSTests/packages.config b/CloudflareDNSTests/packages.config
new file mode 100644
index 0000000..7079f81
--- /dev/null
+++ b/CloudflareDNSTests/packages.config
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file