Skip to content

Instantly share code, notes, and snippets.

@tstachl
Created August 19, 2016 23:13
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tstachl/df0d28dc7811b1ea052b27ab6f98b651 to your computer and use it in GitHub Desktop.
Save tstachl/df0d28dc7811b1ea052b27ab6f98b651 to your computer and use it in GitHub Desktop.
Desk.com API Client for C#
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