Skip to content

Instantly share code, notes, and snippets.

@chrisntr
Created May 22, 2011 20:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chrisntr/985841 to your computer and use it in GitHub Desktop.
Save chrisntr/985841 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.RegularExpressions;
namespace RavelryNet
{
public class RavelryClient
{
public class TrustAllCertificatePolicy : System.Net.ICertificatePolicy
{
public TrustAllCertificatePolicy()
{ }
public bool CheckValidationResult(ServicePoint sp,
X509Certificate cert, WebRequest req, int problem)
{
return true;
}
}
private readonly string _accessKey, _apiServer, _secretKey;
private string _authToken, _signingKey;
private WebClient _webClient;
public bool Authenticated { get { return _authToken != null; } }
public RavelryClient(string accessKey, string secretKey)
{
System.Net.ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();
_accessKey = accessKey;
_secretKey = secretKey;
_apiServer = "api.ravelry.com";
}
public RavelryClient(string accessKey, string secretKey, string apiServer)
{
System.Net.ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();
_accessKey = accessKey;
_secretKey = secretKey;
_apiServer = apiServer;
}
public string Get(string uri, Dictionary<String, String> parameters)
{
return Request("Get", uri, parameters, null);
}
private string Request(string method, string url, Dictionary<String, String> parameters, Dictionary<String, String> options)
{
var protocol = (options != null && options.ContainsKey("ssl")) ? "https" : "http";
var timestamp = DateTime.UtcNow.ToString("yyyy-MM-dd\\THH:mm:ss.000Z");
var defaults = new Dictionary<String, String> {{"timestamp", timestamp}, {"access_key", _accessKey}};
if(Authenticated)
defaults.Add("auth_token", _authToken);
parameters = (parameters != null) ? defaults.Union(parameters).ToDictionary(i => i.Key, i => i.Value) : defaults;
var sortedParameters = parameters.OrderBy(x => x.Key.ToString());
var queryString = String.Join("&", sortedParameters.Select(x => String.Format("{0}={1}", x.Key, UrlEncodeUpperCase(x.Value))).ToArray());
Console.WriteLine("Query String = {0}", queryString);
var signature = Sign(String.Format("http://{0}{1}?{2}", _apiServer, url, queryString));
var signedQueryString = String.Format("{0}&signature={1}", queryString,
UrlEncodeUpperCase(signature));
_webClient = new WebClient();
var uri = new Uri(String.Format("{0}://{1}{2}?{3}", protocol, _apiServer, url, signedQueryString));
var completeUrl = String.Format("{0}://{1}{2}?{3}", protocol, _apiServer, url, signedQueryString);
var response = _webClient.DownloadString(completeUrl);
return response.ToString();
// response = if method == :get
// http = Net::HTTP.new(url.host, url.port)
// http.use_ssl = protocol == "https"
// http.request(Net::HTTP::Get.new(url.request_uri))
// else
// raise ApiError, "#{method} method not supported"
// end
// if response.code == "200"
// JSON.parse(response.body)
// else
// raise ApiError, "#{response.code} #{response.message} : #{response.body}"
// end
}
public void Authenticate(string username, string password)
{
var credentials = EncryptAes(String.Format("{0}:{1}", username, password));
var parameters = new Dictionary<String, String> {{"credentials", credentials}};
var options = new Dictionary<String, String> {{"ssl", "true"}};
var result = Request("Get", "/authenticate.json", parameters, options);
var json = System.Json.JsonObject.Parse(result);
_authToken = json["auth_token"].ToString();
_signingKey = json["signing_key"].ToString();
var what = result.ToString();
//@auth_token = result["auth_token"]
//@signing_key = result["signing_key"]
}
private string EncryptAes(string s)
{
var iv = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
var key = Sha256Hash(_secretKey);
String result;
var rijn = new RijndaelManaged
{
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7
};
using (var msEncrypt = new MemoryStream())
{
using (var encryptor = rijn.CreateEncryptor(key, iv))
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
using (var swEncrypt = new StreamWriter(csEncrypt))
swEncrypt.Write(s);
result = Convert.ToBase64String(msEncrypt.ToArray());
}
rijn.Clear();
return result;
}
public static byte[] Sha256Hash(string data)
{
var sha = new SHA256Managed();
return sha.ComputeHash(Encoding.UTF8.GetBytes(data));
}
private string Sign(string data)
{
var key = this.Authenticated ? _signingKey : _secretKey;
var encoding = new UTF8Encoding();
var hmacsha256 = new HMACSHA256(encoding.GetBytes(key));
var signature = hmacsha256.ComputeHash(encoding.GetBytes(data));
return Convert.ToBase64String(signature);
}
static string UrlEncodeUpperCase(string value)
{
value = HttpUtility.UrlEncode(value);
return Regex.Replace(value, "(%[0-9a-f][0-9a-f])", c => c.Value.ToUpper());
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment