Created
August 19, 2016 23:13
-
-
Save tstachl/df0d28dc7811b1ea052b27ab6f98b651 to your computer and use it in GitHub Desktop.
Desk.com API Client for C#
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Net; | |
using System.Text; | |
using System.IO; | |
using System.Security.Cryptography; | |
namespace DeskApi | |
{ | |
/// <summary> | |
/// Client allows you to interact with the Desk.com API. | |
/// </summary> | |
/// <remarks> | |
/// This wrapper is based on APIv2 and not officially supported by Desk.com. | |
/// </remarks> | |
public class Client | |
{ | |
private static Random random = new Random(); | |
/// <summary> | |
/// Stores the final endpoint, can be `https://devel.desk.com` or `https://support.devel.com`. | |
/// </summary> | |
private String _endpoint; | |
/// <summary> | |
/// Stores a Desk.com subdomain that is used to build the endpoint. | |
/// </summary> | |
private String _subdomain; | |
/// <summary> | |
/// Stores the Desk.com username for basic authentication. | |
/// </summary> | |
private String _username; | |
/// <summary> | |
/// Stores the Desk.com password for basic authentication. | |
/// </summary> | |
private String _password; | |
/// <summary> | |
/// Stores the access token for OAuth 1.0a. | |
/// </summary> | |
private String _token; | |
/// <summary> | |
/// Stores the access token secret for OAuth 1.0a. | |
/// </summary> | |
private String _tokenSecret; | |
/// <summary> | |
/// Stores the consumer key for OAuth 1.0a. | |
/// </summary> | |
private String _consumerKey; | |
/// <summary> | |
/// Stores the consumer secret for OAuth 1.0a. | |
/// </summary> | |
private String _consumerSecret; | |
/// <summary> | |
/// Either gets the endpoint or builds the endpoint based on the subdomain. | |
/// </summary> | |
/// <value>The endpoint.</value> | |
public String Endpoint | |
{ | |
get | |
{ | |
if (_endpoint == null && _subdomain != null) | |
{ | |
_endpoint = String.Format("https://{0}.desk.com", _subdomain); | |
} | |
return _endpoint; | |
} | |
set { _endpoint = value; } | |
} | |
public string Subdomain { get { return _subdomain; } set { _subdomain = value;} } | |
public string Username { get { return _username; } set { _username = value; } } | |
public string Password { get { return _password; } set { _password = value; } } | |
public string Token { get { return _token; } set { _token = value; } } | |
public string TokenSecret { get { return _tokenSecret; } set { _tokenSecret = value; } } | |
public string ConsumerKey { get { return _consumerKey; } set { _consumerKey = value; } } | |
public string ConsumerSecret { get { return _consumerSecret; } set { _consumerSecret = value; } } | |
public Client() { } | |
public Client(Dictionary<String, String> options) | |
{ | |
// set options if we have them | |
if (options.ContainsKey("Endpoint")) Endpoint = options["Endpoint"]; | |
if (options.ContainsKey("Subdomain")) Subdomain = options["Subdomain"]; | |
if (options.ContainsKey("Username")) Username = options["Username"]; | |
if (options.ContainsKey("Password")) Password = options["Password"]; | |
if (options.ContainsKey("Token")) Token = options["Token"]; | |
if (options.ContainsKey("TokenSecret")) TokenSecret = options["TokenSecret"]; | |
if (options.ContainsKey("ConsumerKey")) ConsumerKey = options["ConsumerKey"]; | |
if (options.ContainsKey("ConsumerSecret")) ConsumerSecret = options["ConsumerSecret"]; | |
} | |
public WebResponse Get(String path) | |
{ | |
return Request("GET", path); | |
} | |
public WebResponse Post(String path, String payload) | |
{ | |
return Request("POST", path, payload); | |
} | |
public WebResponse Patch(String path, String payload) | |
{ | |
return Request("PATCH", path, payload); | |
} | |
public WebResponse Delete(String path) | |
{ | |
return Request("DELETE", path); | |
} | |
private WebResponse Request(String method, String path) | |
{ | |
return Request(method, path, null); | |
} | |
private WebResponse Request(String method, String path, String payload) | |
{ | |
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(Endpoint + path); | |
req.UserAgent = "csharp-desk-client/0.1.0"; | |
req.Accept = "application/json"; | |
req.Method = method; | |
if (method == "PATCH") | |
{ | |
req.Method = "POST"; | |
req.Headers.Add("X-HTTP-Method-Override", "PATCH"); | |
} | |
AddAuth(req); | |
if (!String.IsNullOrEmpty(payload)) | |
{ | |
Byte[] body = Encoding.UTF8.GetBytes(payload); | |
req.ContentType = "application/json"; | |
req.ContentLength = body.Length; | |
using (Stream requestStream = req.GetRequestStream()) | |
{ | |
requestStream.Write(body, 0, body.Length); | |
} | |
} | |
else | |
{ | |
req.ContentLength = 0; | |
} | |
return req.GetResponse(); | |
} | |
private void AddAuth(HttpWebRequest req) | |
{ | |
if (!String.IsNullOrEmpty(Username) && !String.IsNullOrEmpty(Password)) | |
{ | |
BasicAuth(req); | |
} | |
else if (!String.IsNullOrEmpty(ConsumerKey) && !String.IsNullOrEmpty(ConsumerSecret) | |
&& !String.IsNullOrEmpty(Token) && !String.IsNullOrEmpty(TokenSecret)) | |
{ | |
OAuth(req); | |
} | |
} | |
private void BasicAuth(HttpWebRequest req) | |
{ | |
Byte[] auth = Encoding.UTF8.GetBytes(String.Format("{0}:{1}", _username, _password)); | |
req.Headers.Add(HttpRequestHeader.Authorization, "Basic " + Convert.ToBase64String(auth)); | |
} | |
private void OAuth(HttpWebRequest req) | |
{ | |
SortedDictionary<String, String> oauthParams = new SortedDictionary<String, String> | |
{ | |
{ "oauth_consumer_key", ConsumerKey }, | |
{ "oauth_nonce", random.Next(123400, 9999999).ToString() }, | |
{ "oauth_signature_method", "HMAC-SHA1" }, | |
{ "oauth_timestamp", GenerateTimeStamp() }, | |
{ "oauth_token", Token }, | |
{ "oauth_version", "1.0" } | |
}; | |
if (!String.IsNullOrEmpty(req.RequestUri.Query)) | |
{ | |
foreach (KeyValuePair<String, String> kvp in ParseParams(req.RequestUri.Query)) | |
{ | |
oauthParams.Add(kvp.Key, kvp.Value); | |
} | |
} | |
String baseString = ""; | |
foreach (KeyValuePair<String, String> kvp in oauthParams) | |
{ | |
baseString += kvp.Key + "=" + kvp.Value + "&"; | |
} | |
baseString = req.Method + "&" + | |
WebUtility.UrlEncode(req.RequestUri.OriginalString.Split('?')[0]) + "&" + | |
WebUtility.UrlEncode(baseString.Substring(0, baseString.LastIndexOf('&'))); | |
String header = GenerateHeader(oauthParams, WebUtility.UrlEncode(GenerateSignature(baseString))); | |
req.Headers.Add(HttpRequestHeader.Authorization, header); | |
} | |
private String GenerateSignature(String baseString) | |
{ | |
HMACSHA1 hmacsha1 = new HMACSHA1(); | |
hmacsha1.Key = Encoding.UTF8.GetBytes(ConsumerSecret + "&" + TokenSecret); | |
return Convert.ToBase64String(hmacsha1.ComputeHash(Encoding.UTF8.GetBytes(baseString))); | |
} | |
private String GenerateHeader(SortedDictionary<String, String> oauthParams, String signature) | |
{ | |
String header = "OAuth "; | |
foreach (KeyValuePair<String, String> kvp in oauthParams) | |
{ | |
header += String.Format("{0}=\"{1}\", ", kvp.Key, kvp.Value); | |
} | |
return header + String.Format("oauth_signature=\"{0}\"", signature); | |
} | |
private Dictionary<String, String> ParseParams(String paramString) | |
{ | |
Dictionary<String, String> paramDict = new Dictionary<String, String>(); | |
if (!String.IsNullOrEmpty(paramString)) | |
{ | |
foreach (String pair in paramString.Split('&')) | |
{ | |
String[] kv = pair.Split('='); | |
if (kv.Length == 2) | |
{ | |
paramDict.Add(kv[0], kv[1]); | |
} | |
} | |
} | |
return paramDict; | |
} | |
private string GenerateTimeStamp() | |
{ | |
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); | |
return Convert.ToInt64(ts.TotalSeconds).ToString(); | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment