diff --git a/DuoApi.Examples/DuoApi.Examples.csproj b/DuoApi.Examples/DuoApi.Examples.csproj
new file mode 100644
index 0000000..8b31ff7
--- /dev/null
+++ b/DuoApi.Examples/DuoApi.Examples.csproj
@@ -0,0 +1,12 @@
+
+
+
+ Exe
+ netcoreapp3.1
+
+
+
+
+
+
+
diff --git a/examples/Program.cs b/DuoApi.Examples/Program.cs
similarity index 76%
rename from examples/Program.cs
rename to DuoApi.Examples/Program.cs
index 110606b..ef6c6ce 100644
--- a/examples/Program.cs
+++ b/DuoApi.Examples/Program.cs
@@ -23,8 +23,7 @@ static int Main(string[] args)
var r = client.JSONApiCall>(
"GET", "/admin/v1/info/authentication_attempts", parameters);
var attempts = r["authentication_attempts"] as Dictionary;
- foreach (KeyValuePair info in attempts)
- {
+ foreach (KeyValuePair info in attempts) {
var s = String.Format("{0} authentication(s) ended with {1}.",
info.Value,
info.Key);
@@ -35,28 +34,23 @@ static int Main(string[] args)
var users = client.JSONApiCall(
"GET", "/admin/v1/users", parameters);
System.Console.WriteLine(String.Format("{0} users.", users.Count));
- foreach (Dictionary user in users)
- {
+ foreach (Dictionary user in users) {
System.Console.WriteLine(
"\t" + "Username: " + (user["username"] as string));
}
// paging call
int? offset = 0;
- while (offset != null)
- {
- var jsonResponse = client.JSONPagingApiCall("GET", "/admin/v1/users", parameters, (int)offset, 10);
- var pagedUsers = jsonResponse["response"] as System.Collections.ArrayList;
+ while (offset != null) {
+ var pagedUsers = client.JSONPagingApiCall("GET", "/admin/v1/users", parameters, (int)offset, 10, out var metadata);
System.Console.WriteLine(String.Format("{0} users at offset {1}", pagedUsers.Count, offset));
- foreach (Dictionary user in pagedUsers)
- {
+ foreach (Dictionary user in pagedUsers) {
System.Console.WriteLine(
"\t" + "Username: " + (user["username"] as string));
}
- var metadata = jsonResponse["metadata"] as Dictionary;
- if (metadata.ContainsKey("next_offset"))
+ if (metadata.next_offset.HasValue)
{
- offset = metadata["next_offset"] as int?;
+ offset = metadata.next_offset.Value;
}
else
{
diff --git a/test/ApiCallTest.cs b/DuoApi.Tests/ApiCallTest.cs
similarity index 96%
rename from test/ApiCallTest.cs
rename to DuoApi.Tests/ApiCallTest.cs
index e2d27fc..540d413 100644
--- a/test/ApiCallTest.cs
+++ b/DuoApi.Tests/ApiCallTest.cs
@@ -391,10 +391,10 @@ public void TestValidJsonPagingResponseNoParameters()
return "{\"stat\": \"OK\", \"response\": \"hello, world!\", \"metadata\": {\"next_offset\":10}}";
};
var parameters = new Dictionary();
- var jsonResponse = api.JSONPagingApiCall("GET", "/json_ok", parameters, 0, 10);
- Assert.Equal("hello, world!", jsonResponse["response"]);
- var metadata = jsonResponse["metadata"] as Dictionary;
- Assert.Equal(10, metadata["next_offset"]);
+ var jsonResponse = api.JSONPagingApiCall("GET", "/json_ok", parameters, 0, 10, out var metadata);
+ Assert.Equal("hello, world!", jsonResponse);
+
+ Assert.Equal(10, metadata.next_offset);
// make sure parameters was not changed as a side-effect
Assert.Empty(parameters);
}
@@ -411,10 +411,10 @@ public void TestValidJsonPagingResponseExistingParameters()
{"offset", "0"},
{"limit", "10"}
};
- var jsonResponse = api.JSONPagingApiCall("GET", "/json_ok", parameters, 10, 20);
- Assert.Equal("hello, world!", jsonResponse["response"]);
- var metadata = jsonResponse["metadata"] as Dictionary;
- Assert.False(metadata.ContainsKey("next_offset"));
+ var jsonResponse = api.JSONPagingApiCall("GET", "/json_ok", parameters, 10, 20, out var metadata);
+ Assert.Equal("hello, world!", jsonResponse);
+
+ Assert.NotNull(metadata);
// make sure parameters was not changed as a side-effect
Assert.Equal(2, parameters.Count);
Assert.Equal("0", parameters["offset"]);
@@ -461,7 +461,7 @@ public void TestJsonResponseMissingField()
});
Assert.NotNull(ex);
- var e = Assert.IsType(ex);
+ var e = Assert.IsType(ex);
Assert.Equal(400, e.HttpStatus);
diff --git a/test/CertPinningTest.cs b/DuoApi.Tests/CertPinningTest.cs
similarity index 100%
rename from test/CertPinningTest.cs
rename to DuoApi.Tests/CertPinningTest.cs
diff --git a/DuoApi.Tests/DuoApi.Tests.csproj b/DuoApi.Tests/DuoApi.Tests.csproj
new file mode 100644
index 0000000..e39f0bd
--- /dev/null
+++ b/DuoApi.Tests/DuoApi.Tests.csproj
@@ -0,0 +1,26 @@
+
+
+
+ netcoreapp3.1
+
+ false
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
diff --git a/test/QueryParamsTest.cs b/DuoApi.Tests/QueryParamsTest.cs
similarity index 99%
rename from test/QueryParamsTest.cs
rename to DuoApi.Tests/QueryParamsTest.cs
index 70956bb..76613bf 100644
--- a/test/QueryParamsTest.cs
+++ b/DuoApi.Tests/QueryParamsTest.cs
@@ -106,4 +106,4 @@ public void NextOffsetTest()
var expected = "foo=1&next_offset=fjaewoifjew&next_offset=473891274832917498";
Assert.Equal(expected, DuoApi.CanonicalizeParams(parameters));
}
-}
+}
\ No newline at end of file
diff --git a/test/SigningTest.cs b/DuoApi.Tests/SigningTest.cs
similarity index 99%
rename from test/SigningTest.cs
rename to DuoApi.Tests/SigningTest.cs
index 4c5d933..c078157 100644
--- a/test/SigningTest.cs
+++ b/DuoApi.Tests/SigningTest.cs
@@ -31,4 +31,4 @@ public void HmacSha512()
var expected = "Basic dGVzdF9pa2V5OjA1MDgwNjUwMzVhMDNiMmExZGUyZjQ1M2U2MjllNzkxZDE4MDMyOWUxNTdmNjVkZjZiM2UwZjA4Mjk5ZDQzMjFlMWM1YzdhN2M3ZWU2YjllNWZjODBkMWZiNmZiZjNhZDVlYjdjNDRkZDNiMzk4NWEwMmMzN2FjYTUzZWMzNjk4";
Assert.Equal(expected, actual);
}
-}
+}
\ No newline at end of file
diff --git a/duo_api_csharp/CertificatePinnerFactory.cs b/DuoApi/CertificatePinnerFactory.cs
similarity index 98%
rename from duo_api_csharp/CertificatePinnerFactory.cs
rename to DuoApi/CertificatePinnerFactory.cs
index 8026eb1..f29afc3 100644
--- a/duo_api_csharp/CertificatePinnerFactory.cs
+++ b/DuoApi/CertificatePinnerFactory.cs
@@ -130,7 +130,7 @@ internal static X509CertificateCollection GetDuoCertCollection()
internal static string[] ReadCertsFromFile()
{
var certs = "";
- using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("duo_api_csharp.ca_certs.pem"))
+ using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream($"{Assembly.GetExecutingAssembly().GetName().Name}.ca_certs.pem"))
using (StreamReader reader = new StreamReader(stream))
{
certs = reader.ReadToEnd();
diff --git a/DuoApi/DataEnvelope.cs b/DuoApi/DataEnvelope.cs
new file mode 100644
index 0000000..25694a6
--- /dev/null
+++ b/DuoApi/DataEnvelope.cs
@@ -0,0 +1,43 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Duo
+{
+
+ ///
+ ///
+ ///
+ ///
+ public class DataEnvelope
+ {
+ ///
+ ///
+ ///
+ [Required]
+ public DuoApiResponseStatus stat { get; set; }
+
+ ///
+ ///
+ ///
+ public int? code { get; set; }
+
+ ///
+ ///
+ ///
+ public T response { get; set; }
+
+ ///
+ /// Upon error, basic error information
+ ///
+ public string message { get; set; }
+
+ ///
+ /// Upon error, detailed error information
+ ///
+ public string message_detail { get; set; }
+
+ ///
+ ///
+ ///
+ public PagingInfo metadata { get; set; }
+ }
+}
diff --git a/duo_api_csharp/Duo.cs b/DuoApi/Duo.cs
similarity index 80%
rename from duo_api_csharp/Duo.cs
rename to DuoApi/Duo.cs
index 5b8ea18..75af066 100644
--- a/duo_api_csharp/Duo.cs
+++ b/DuoApi/Duo.cs
@@ -4,25 +4,24 @@
*/
using System;
-using System.Configuration;
using System.Collections.Generic;
+using System.Configuration;
+using System.Globalization;
using System.IO;
using System.Net;
+using System.Net.Security;
+using System.Runtime.InteropServices;
using System.Security.Cryptography;
-using System.Text.RegularExpressions;
+using System.Security.Cryptography.X509Certificates;
using System.Text;
-using System.Web.Script.Serialization;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using System.Text.RegularExpressions;
using System.Web;
-using System.Globalization;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Security.Cryptography.X509Certificates;
-using System.Net.Security;
-
namespace Duo
{
- public class DuoApi
+ public class DuoApi
{
public string DEFAULT_AGENT = "DuoAPICSharp/1.0";
@@ -297,9 +296,12 @@ private HttpWebRequest PrepareHttpRequest(String method, String url, String auth
request.Headers.Add("Authorization", auth);
request.Headers.Add("X-Duo-Date", date);
request.UserAgent = this.user_agent;
+
+ //todo: Understand, handle and test proxy config
+
// If no proxy, check for and use WinHTTP proxy as autoconfig won't pick this up when run from a service
- if (!HasProxyServer(request))
- request.Proxy = GetWinhttpProxy();
+ //if (!HasProxyServer(request))
+ //request.Proxy = GetWinhttpProxy();
if (method.Equals("POST") || method.Equals("PUT"))
{
@@ -377,45 +379,41 @@ private HttpWebResponse AttemptRetriableHttpRequest(
/// calls (particularly in the Auth APIs) will not
/// return a complete JSON response.
/// raises if JSON response indicates an error
- private Dictionary BaseJSONApiCall(string method,
+ private T BaseJSONApiCall(string method,
string path,
Dictionary parameters,
int timeout,
- DateTime date)
+ DateTime date,
+ out PagingInfo metaData)
{
HttpStatusCode statusCode;
string res = this.ApiCall(method, path, parameters, timeout, date, out statusCode);
- var jss = new JavaScriptSerializer();
try
{
- var dict = jss.Deserialize>(res);
- if (dict["stat"] as string == "OK")
+ var options = new JsonSerializerOptions
+ {
+ PropertyNameCaseInsensitive = true
+ };
+
+ options.Converters.Add(new JsonStringEnumConverter());
+
+ var dict = JsonSerializer.Deserialize>(res, options);
+ if (dict.stat == DuoApiResponseStatus.Ok)
{
- return dict;
+ metaData = dict.metadata;
+ return dict.response;
}
else
{
- int? check = dict["code"] as int?;
- int code;
- if (check.HasValue)
- {
- code = check.Value;
- }
- else
- {
- code = 0;
- }
- String message_detail = "";
- if (dict.ContainsKey("message_detail"))
- {
- message_detail = dict["message_detail"] as string;
- }
+
+ int code = dict.code.GetValueOrDefault();
+
throw new ApiException(code,
(int)statusCode,
- dict["message"] as string,
- message_detail);
+ dict.message,
+ dict.message_detail);
}
}
catch (ApiException)
@@ -470,17 +468,17 @@ public T JSONApiCall(string method,
DateTime date)
where T : class
{
- var dict = BaseJSONApiCall(method, path, parameters, timeout, date);
- return dict["response"] as T;
+ return BaseJSONApiCall(method, path, parameters, timeout, date, out _);
}
- public Dictionary JSONPagingApiCall(string method,
+ public T JSONPagingApiCall(string method,
string path,
Dictionary parameters,
int offset,
- int limit)
+ int limit,
+ out PagingInfo metaData)
{
- return JSONPagingApiCall(method, path, parameters, offset, limit, 0, DateTime.UtcNow);
+ return JSONPagingApiCall(method, path, parameters, offset, limit, 0, DateTime.UtcNow, out metaData);
}
/// The current date and time, used to authenticate
@@ -503,20 +501,21 @@ public Dictionary JSONPagingApiCall(string method,
/// return a JSON dictionary with top level keys: stat, response, metadata.
/// The actual requested data is in 'response'. 'metadata' contains a
/// 'next_offset' key which should be used to fetch the next page.
- public Dictionary JSONPagingApiCall(string method,
+ public T JSONPagingApiCall(string method,
string path,
Dictionary parameters,
int offset,
int limit,
int timeout,
- DateTime date)
+ DateTime date,
+ out PagingInfo metaData)
{
// copy parameters so we don't cause any side-effects
parameters = new Dictionary(parameters);
parameters["offset"] = offset.ToString(); // overrides caller value
parameters["limit"] = limit.ToString();
- return this.BaseJSONApiCall(method, path, parameters, timeout, date);
+ return this.BaseJSONApiCall(method, path, parameters, timeout, date, out metaData);
}
@@ -578,98 +577,98 @@ private static string DateToRFC822(DateTime date)
return date_string;
}
- ///
- /// Gets the WinHTTP proxy.
- ///
- ///
- /// Normally, C# picks up these proxy settings by default, but when run under the SYSTEM account, it does not.
- ///
- ///
- private static System.Net.WebProxy GetWinhttpProxy()
- {
- string[] proxyServerNames = null;
- string primaryProxyServer = null;
- string[] bypassHostnames = null;
- bool enableLocalBypass = false;
- System.Net.WebProxy winhttpProxy = null;
-
- // Has a proxy been configured?
- // No. Is a WinHTTP proxy set?
- int internetHandle = WinHttpOpen("DuoTest", WinHttp_Access_Type.WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, null, null, 0);
- if (internetHandle != 0)
- {
- // Yes, use it. This is normal when run under the SYSTEM account and a WinHTTP proxy is configured. When run as a normal user,
- // the Proxy property will already be configured correctly. To resolve this for SYSTEM, manually read proxy settings and configure.
- var proxyInfo = new WINHTTP_PROXY_INFO();
- WinHttpGetDefaultProxyConfiguration(proxyInfo);
- if (proxyInfo.lpszProxy != null)
- {
- if (proxyInfo.lpszProxy != null)
- {
- proxyServerNames = proxyInfo.lpszProxy.Split(new char[] { ' ', '\t', ';' });
- if ((proxyServerNames == null) || (proxyServerNames.Length == 0))
- primaryProxyServer = proxyInfo.lpszProxy;
- else
- primaryProxyServer = proxyServerNames[0];
- }
- if (proxyInfo.lpszProxyBypass != null)
- {
- bypassHostnames = proxyInfo.lpszProxyBypass.Split(new char[] { ' ', '\t', ';' });
- if ((bypassHostnames == null) || (bypassHostnames.Length == 0))
- bypassHostnames = new string[] { proxyInfo.lpszProxyBypass };
- if (bypassHostnames != null)
- enableLocalBypass = bypassHostnames.Contains("local", StringComparer.InvariantCultureIgnoreCase);
- }
- if (primaryProxyServer != null)
- winhttpProxy = new System.Net.WebProxy(proxyServerNames[0], enableLocalBypass, bypassHostnames);
- }
- WinHttpCloseHandle(internetHandle);
- internetHandle = 0;
- }
- else
- {
- throw new Exception(String.Format("WinHttp init failed {0}", System.Runtime.InteropServices.Marshal.GetLastWin32Error()));
- }
-
- return winhttpProxy;
- }
-
- ///
- /// Determines if the specified web request is using a proxy server.
- ///
- ///
- /// If no proxy is set, the Proxy member is typically non-null and set to an object type that includes but hides IWebProxy with no address,
- /// so it cannot be inspected. Resolving this requires reflection to extract the hidden webProxy object and check it's Address member.
- ///
- /// Request to check
- /// TRUE if a proxy is in use, else FALSE
- public static bool HasProxyServer(HttpWebRequest requestObject)
- {
- WebProxy actualProxy = null;
- bool hasProxyServer = false;
-
- if (requestObject.Proxy != null)
- {
- // WebProxy is described as the base class for IWebProxy, so we should always see this type as the field is initialized by the framework.
- if (!(requestObject.Proxy is WebProxy))
- {
- var webProxyField = requestObject.Proxy.GetType().GetField("webProxy", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);
- if (webProxyField != null)
- actualProxy = webProxyField.GetValue(requestObject.Proxy) as WebProxy;
- }
- else
- {
- actualProxy = requestObject.Proxy as WebProxy;
- }
- hasProxyServer = (actualProxy.Address != null);
- }
- else
- {
- hasProxyServer = false;
- }
-
- return hasProxyServer;
- }
+ /////
+ ///// Gets the WinHTTP proxy.
+ /////
+ /////
+ ///// Normally, C# picks up these proxy settings by default, but when run under the SYSTEM account, it does not.
+ /////
+ /////
+ //private static System.Net.WebProxy GetWinhttpProxy()
+ //{
+ // string[] proxyServerNames = null;
+ // string primaryProxyServer = null;
+ // string[] bypassHostnames = null;
+ // bool enableLocalBypass = false;
+ // System.Net.WebProxy winhttpProxy = null;
+
+ // // Has a proxy been configured?
+ // // No. Is a WinHTTP proxy set?
+ // int internetHandle = WinHttpOpen("DuoTest", WinHttp_Access_Type.WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, null, null, 0);
+ // if (internetHandle != 0)
+ // {
+ // // Yes, use it. This is normal when run under the SYSTEM account and a WinHTTP proxy is configured. When run as a normal user,
+ // // the Proxy property will already be configured correctly. To resolve this for SYSTEM, manually read proxy settings and configure.
+ // var proxyInfo = new WINHTTP_PROXY_INFO();
+ // WinHttpGetDefaultProxyConfiguration(proxyInfo);
+ // if (proxyInfo.lpszProxy != null)
+ // {
+ // if (proxyInfo.lpszProxy != null)
+ // {
+ // proxyServerNames = proxyInfo.lpszProxy.Split(new char[] { ' ', '\t', ';' });
+ // if ((proxyServerNames == null) || (proxyServerNames.Length == 0))
+ // primaryProxyServer = proxyInfo.lpszProxy;
+ // else
+ // primaryProxyServer = proxyServerNames[0];
+ // }
+ // if (proxyInfo.lpszProxyBypass != null)
+ // {
+ // bypassHostnames = proxyInfo.lpszProxyBypass.Split(new char[] { ' ', '\t', ';' });
+ // if ((bypassHostnames == null) || (bypassHostnames.Length == 0))
+ // bypassHostnames = new string[] { proxyInfo.lpszProxyBypass };
+ // if (bypassHostnames != null)
+ // enableLocalBypass = bypassHostnames.Contains("local", StringComparer.InvariantCultureIgnoreCase);
+ // }
+ // if (primaryProxyServer != null)
+ // winhttpProxy = new System.Net.WebProxy(proxyServerNames[0], enableLocalBypass, bypassHostnames);
+ // }
+ // WinHttpCloseHandle(internetHandle);
+ // internetHandle = 0;
+ // }
+ // else
+ // {
+ // throw new Exception(String.Format("WinHttp init failed {0}", System.Runtime.InteropServices.Marshal.GetLastWin32Error()));
+ // }
+
+ // return winhttpProxy;
+ //}
+
+ /////
+ ///// Determines if the specified web request is using a proxy server.
+ /////
+ /////
+ ///// If no proxy is set, the Proxy member is typically non-null and set to an object type that includes but hides IWebProxy with no address,
+ ///// so it cannot be inspected. Resolving this requires reflection to extract the hidden webProxy object and check it's Address member.
+ /////
+ ///// Request to check
+ ///// TRUE if a proxy is in use, else FALSE
+ //public static bool HasProxyServer(HttpWebRequest requestObject)
+ //{
+ // WebProxy actualProxy = null;
+ // bool hasProxyServer = false;
+
+ // if (requestObject.Proxy != null)
+ // {
+ // // WebProxy is described as the base class for IWebProxy, so we should always see this type as the field is initialized by the framework.
+ // if (!(requestObject.Proxy is WebProxy))
+ // {
+ // var webProxyField = requestObject.Proxy.GetType().GetField("webProxy", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);
+ // if (webProxyField != null)
+ // actualProxy = webProxyField.GetValue(requestObject.Proxy) as WebProxy;
+ // }
+ // else
+ // {
+ // actualProxy = requestObject.Proxy as WebProxy;
+ // }
+ // hasProxyServer = (actualProxy.Address != null);
+ // }
+ // else
+ // {
+ // hasProxyServer = false;
+ // }
+
+ // return hasProxyServer;
+ //}
#endregion Private Methods
#region Private DllImport
@@ -707,7 +706,7 @@ private static extern int WinHttpOpen([MarshalAs(UnmanagedType.LPWStr)] string p
private static extern bool WinHttpCloseHandle(int hInternet);
#endregion Private DllImport
}
-
+
[Serializable]
public class DuoException : Exception
{
diff --git a/DuoApi/DuoApi.csproj b/DuoApi/DuoApi.csproj
new file mode 100644
index 0000000..9849be6
--- /dev/null
+++ b/DuoApi/DuoApi.csproj
@@ -0,0 +1,19 @@
+
+
+
+ netstandard2.1
+ enable
+ True
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/DuoApi/DuoApiResponseStatus.cs b/DuoApi/DuoApiResponseStatus.cs
new file mode 100644
index 0000000..d1bd0d8
--- /dev/null
+++ b/DuoApi/DuoApiResponseStatus.cs
@@ -0,0 +1,7 @@
+namespace Duo
+{
+ public enum DuoApiResponseStatus {
+ Fail = 0,
+ Ok = 1
+ }
+}
diff --git a/DuoApi/PagingInfo.cs b/DuoApi/PagingInfo.cs
new file mode 100644
index 0000000..bb07c75
--- /dev/null
+++ b/DuoApi/PagingInfo.cs
@@ -0,0 +1,12 @@
+namespace Duo
+{
+ ///
+ /// Information of dataset paging
+ ///
+ public struct PagingInfo
+ {
+ public int total_objects { get; set; }
+ public int? next_offset { get; set; }
+ public int prev_offset { get; set; }
+ }
+}
diff --git a/DuoApi/TestFriends.cs b/DuoApi/TestFriends.cs
new file mode 100644
index 0000000..35962b1
--- /dev/null
+++ b/DuoApi/TestFriends.cs
@@ -0,0 +1,3 @@
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("DuoApi.Tests")]
diff --git a/duo_api_csharp/ca_certs.pem b/DuoApi/ca_certs.pem
similarity index 100%
rename from duo_api_csharp/ca_certs.pem
rename to DuoApi/ca_certs.pem
diff --git a/duo_api_csharp.sln b/duo_api_csharp.sln
index 743ca5f..596cdaf 100644
--- a/duo_api_csharp.sln
+++ b/duo_api_csharp.sln
@@ -2,17 +2,17 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.32126.317
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "duo_api_csharp", "duo_api_csharp\duo_api_csharp.csproj", "{6E96C9D9-0825-4D26-83C7-8A62180F8FB9}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DuoApiTest", "test\DuoApiTest.csproj", "{6B97B9FB-E553-494C-BD50-4BF7DB5C2184}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E739E3FE-D923-480A-9B01-3B2A623067E3}"
ProjectSection(SolutionItems) = preProject
LICENSE = LICENSE
README.md = README.md
EndProjectSection
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Examples", "Examples\Examples.csproj", "{C089A10B-646D-407E-A2B8-848C6C522B13}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DuoApi", "DuoApi\DuoApi.csproj", "{83919561-1430-4928-B231-02A77D8B9AD3}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DuoApi.Tests", "DuoApi.Tests\DuoApi.Tests.csproj", "{A0508DF1-F0F6-4A5E-B1F8-015D8C37E165}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DuoApi.Examples", "DuoApi.Examples\DuoApi.Examples.csproj", "{834D5CD4-19F2-4434-A35C-9D6C3FBCED1B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -20,18 +20,18 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {6E96C9D9-0825-4D26-83C7-8A62180F8FB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {6E96C9D9-0825-4D26-83C7-8A62180F8FB9}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {6E96C9D9-0825-4D26-83C7-8A62180F8FB9}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {6E96C9D9-0825-4D26-83C7-8A62180F8FB9}.Release|Any CPU.Build.0 = Release|Any CPU
- {6B97B9FB-E553-494C-BD50-4BF7DB5C2184}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {6B97B9FB-E553-494C-BD50-4BF7DB5C2184}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {6B97B9FB-E553-494C-BD50-4BF7DB5C2184}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {6B97B9FB-E553-494C-BD50-4BF7DB5C2184}.Release|Any CPU.Build.0 = Release|Any CPU
- {C089A10B-646D-407E-A2B8-848C6C522B13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C089A10B-646D-407E-A2B8-848C6C522B13}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C089A10B-646D-407E-A2B8-848C6C522B13}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C089A10B-646D-407E-A2B8-848C6C522B13}.Release|Any CPU.Build.0 = Release|Any CPU
+ {83919561-1430-4928-B231-02A77D8B9AD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {83919561-1430-4928-B231-02A77D8B9AD3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {83919561-1430-4928-B231-02A77D8B9AD3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {83919561-1430-4928-B231-02A77D8B9AD3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A0508DF1-F0F6-4A5E-B1F8-015D8C37E165}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A0508DF1-F0F6-4A5E-B1F8-015D8C37E165}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A0508DF1-F0F6-4A5E-B1F8-015D8C37E165}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A0508DF1-F0F6-4A5E-B1F8-015D8C37E165}.Release|Any CPU.Build.0 = Release|Any CPU
+ {834D5CD4-19F2-4434-A35C-9D6C3FBCED1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {834D5CD4-19F2-4434-A35C-9D6C3FBCED1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {834D5CD4-19F2-4434-A35C-9D6C3FBCED1B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {834D5CD4-19F2-4434-A35C-9D6C3FBCED1B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/duo_api_csharp/AssemblyInfo.cs b/duo_api_csharp/AssemblyInfo.cs
deleted file mode 100644
index 75fbbb2..0000000
--- a/duo_api_csharp/AssemblyInfo.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-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("duo_api_csharp")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("duo_api_csharp")]
-[assembly: AssemblyCopyright("Copyright © 2022")]
-[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("b15c44a4-74d6-45b7-8a30-a313c2818083")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
-
-// Allow tests to access internal methods for easier testing
-[assembly: InternalsVisibleTo("DuoApiTest")]
diff --git a/duo_api_csharp/duo_api_csharp.csproj b/duo_api_csharp/duo_api_csharp.csproj
deleted file mode 100644
index 86f8272..0000000
--- a/duo_api_csharp/duo_api_csharp.csproj
+++ /dev/null
@@ -1,60 +0,0 @@
-
-
- Debug
- AnyCPU
- {6E96C9D9-0825-4D26-83C7-8A62180F8FB9}
- Library
- false
- ClassLibrary
- v4.8
- 512
-
-
-
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
- false
-
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
- false
-
-
- duo_api_csharp
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/examples/App.config b/examples/App.config
deleted file mode 100644
index 193aecc..0000000
--- a/examples/App.config
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/examples/Examples.csproj b/examples/Examples.csproj
deleted file mode 100644
index 35bc283..0000000
--- a/examples/Examples.csproj
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
-
-
- Debug
- AnyCPU
- {C089A10B-646D-407E-A2B8-848C6C522B13}
- Exe
- Examples
- Examples
- v4.8
- 512
- true
- true
-
-
- AnyCPU
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- AnyCPU
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {6e96c9d9-0825-4d26-83c7-8a62180f8fb9}
- duo_api_csharp
-
-
-
-
\ No newline at end of file
diff --git a/examples/Properties/AssemblyInfo.cs b/examples/Properties/AssemblyInfo.cs
deleted file mode 100644
index 6a556c3..0000000
--- a/examples/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-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("Examples")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("Examples")]
-[assembly: AssemblyCopyright("Copyright © 2022")]
-[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("c089a10b-646d-407e-a2b8-848c6c522b13")]
-
-// 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/test/DuoApiTest.csproj b/test/DuoApiTest.csproj
deleted file mode 100644
index 9aaa12f..0000000
--- a/test/DuoApiTest.csproj
+++ /dev/null
@@ -1,125 +0,0 @@
-
-
-
-
-
-
- Debug
- AnyCPU
- {6B97B9FB-E553-494C-BD50-4BF7DB5C2184}
- Library
- Properties
- DuoApiTest
- DuoApiTest
- v4.8
- 512
-
-
-
-
-
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
- false
-
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
- false
-
-
-
- ..\packages\Microsoft.Bcl.AsyncInterfaces.6.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
-
-
-
- ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
-
-
- ..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll
-
-
-
- ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
-
-
- ..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
-
-
- ..\packages\System.Text.Encodings.Web.6.0.0\lib\net461\System.Text.Encodings.Web.dll
-
-
- ..\packages\System.Text.Json.6.0.2\lib\net461\System.Text.Json.dll
-
-
- ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll
-
-
- ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll
-
-
-
-
-
-
- ..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll
-
-
- ..\packages\xunit.assert.2.4.1\lib\netstandard1.1\xunit.assert.dll
-
-
- ..\packages\xunit.extensibility.core.2.4.1\lib\net452\xunit.core.dll
-
-
- ..\packages\xunit.extensibility.execution.2.4.1\lib\net452\xunit.execution.desktop.dll
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {6e96c9d9-0825-4d26-83c7-8a62180f8fb9}
- duo_api_csharp
-
-
-
-
-
- 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/test/Makefile b/test/Makefile
deleted file mode 100644
index 4d6e7b5..0000000
--- a/test/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-DLLS := SigningTest.dll QueryParamsTest.dll
-
-test: $(DLLS)
- nunit-console $^
-
-%.dll: %.cs ../Duo.cs
- dmcs /target:library -r:System.Web.Services -r:System.Web.Extensions -r:System.Web -r:nunit.framework.dll $< ../Duo.cs -out:$@
-
-clean:
- rm -f $(DLLS) *~ TestResult.xml
diff --git a/test/Properties/AssemblyInfo.cs b/test/Properties/AssemblyInfo.cs
deleted file mode 100644
index 80f68e1..0000000
--- a/test/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-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("DuoApiTest")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("Cisco Systems")]
-[assembly: AssemblyProduct("DuoApiTest")]
-[assembly: AssemblyCopyright("Copyright © 2022")]
-[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("ee1b0852-a526-4b1f-bbda-178c88e8e2fa")]
-
-// 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/test/app.config b/test/app.config
deleted file mode 100644
index 1696df6..0000000
--- a/test/app.config
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/packages.config b/test/packages.config
deleted file mode 100644
index 9462602..0000000
--- a/test/packages.config
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file