I have to really ask this question as I donot know Python.
Following are a few lines taken from this place. I would appreciate if someone guides me in translating the following to C#
#Step 1: Get a session key
servercontent = myhttp.request(baseurl + '/services/auth/login', 'POST',
headers={}, body=urllib.urlencode({'username':username, 'password':password}))[1]
sessionkey = minidom.parseString(servercontent).getElementsByTagName('sessionKey')[0].childNodes[0].nodeValue
print "====>sessionkey: %s <====" % sessionkey
I can't translate it to C#, but I can explain what this code does:
Login to baseurl + '/services/auth/login' using the username and password provided.
Read the contents of that URL.
Parse the content for the first <sessionkey> tag, and read the value of its first child node.
Here's a quick-n-dirty translation:
using System.Linq.Xml;
using System.Net;
using System.Collections.Generic;
using System.Web;
// ...
var client = new WebClient();
var parameters = new Dictionary<string, string>
{
{ "username", username },
{ "password", password }
};
var result = client.UploadString(String.Format("{0}/services/auth/login", BaseUrl), UrlEncode(parameters));
var doc = XDocument.Load(result); // load response into XML document (LINQ)
var key = doc.Elements("sessionKey").Single().Value // get the one-and-only <sessionKey> element.
Console.WriteLine("====>sessionkey: {0} <====", key);
// ...
// Utility function:
private static string UrlEncode(IDictionary<string, string> parameters)
{
var sb = new StringBuilder();
foreach(var val in parameters)
{
// add each parameter to the query string, url-encoding the value.
sb.AppendFormat("{0}={1}&", val.Key, HttpUtility.UrlEncode(val.Value));
}
sb.Remove(sb.Length - 1, 1); // remove last '&'
return sb.ToString();
}
This code does a check to see that the response only has one sessionKey element, otherwise it'll throw an exception if there's 0, or more than 1. Then it prints it out.
Related
I'm trying to translate some text by sending a GET request to https://translate.googleapis.com/ from a C# application.
The request should be formatted as following:
"/translate_a/single?client=gtx&sl=BG&tl=EN&dt=t&q=Здравей Свят!"
where sl= is the source language, tl= is the target language and q= is the text to be translated.
The response is a JSON array with the translated text and other details.
The problem is that when I try to translate from bulgarian to english the result gets broken like: "Р-РґСЂР ° РІРμР№ РЎРІСЏС,!"
There is no problem when I'm translating from english to bulgarian (no cyrillic in the URL) so my gues is that the problem is in the request.
Also whenever I'm sending the request directly from the browser the result is properly translated text.
How I'm doing it:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Net.Http;
using System.Web;
class Program
{
static void Main(string[] args)
{
string ApiUrl = "https://translate.googleapis.com/translate_a/single?client=gtx&sl={0}&tl={1}&dt=t&q={2}";
string targetLang = "en";
string sourceLang = "bg";
string text = "Здравей Свят!";
text = HttpUtility.UrlPathEncode(text);
string url = string.Format(ApiUrl, sourceLang, targetLang, text);
using (var client = new HttpClient())
{
var result = client.GetStringAsync(url).Result;
var jRes = (JArray)JsonConvert.DeserializeObject(result);
var translatedText = jRes[0][0][0].ToString();
var originalText = jRes[0][0][1].ToString();
var sourceLanguage = jRes[2].ToString();
}
}
}
Any suggestion will be appreciated.
Thanks to this comment I have managed to recieve a properly formatted response.
The thing is that I'm not using two important parameters in the URL:
ie=UTF-8
oe=UTF-8
The URL should look like this:
https://translate.googleapis.com/translate_a/single?client=gtx&sl=BG&tl=EN&dt=t&q=Здравей%20Свят!&ie=UTF-8&oe=UTF-8
I'm trying to hit the Coinspot REST API, but I'm getting an error returned. I'm having no trouble talking to Bittrex and Independent Reserve, but Coinspot is a bit different. This is my code:
protected override RESTClient RESTClient { get; } = new RESTClient(new NewtonsoftSerializationAdapter(), new Uri("https://www.coinspot.com.au/api"));
public class postdata
{
public string nonce { get; set; }
}
public string CalculateMD5Hash(string input)
{
//step 1, calculate MD5 hash from input
MD5 md5 = MD5.Create();
var inputBytes = Encoding.ASCII.GetBytes(input);
var hash = md5.ComputeHash(inputBytes);
// step 2, convert byte array to hex string
var sb = new StringBuilder();
for (int i = 0; i < hash.Length; i++)
{
sb.Append(hash[i].ToString("X2"));
}
return sb.ToString();
}
/// <summary>
/// Private IR Call: GetAccounts
/// </summary>
/// <returns></returns>
private async Task<List<AccountHolding>> Balances()
{
//https://github.com/geekpete/py-coinspot-api/blob/master/coinspot/coinspot.py
//var nonce = new Date().getTime();
//var postdata = postdata || { };
//postdata.nonce = nonce;
//var stringmessage = JSON.stringify(postdata);
//var signedMessage = new hmac("sha512", self.secret);
//signedMessage.update(stringmessage);
// 'sign': sign,
//'key': self.key
var nonce = APIHelpers.GetNonce();
var postdata = new postdata { nonce = nonce };
var json = JsonConvert.SerializeObject(postdata);
System.Diagnostics.Debug.WriteLine(json);
var sign = APIHelpers.GetHMACSHAHash(ApiSecret, json, APIHelpers.HMACSHAType.NineBit);
//Do we do this?
//The JavaScript samples seem to hash with MD5 afterwards for double encryption?
sign = CalculateMD5Hash(sign);
RESTClient.Headers.Clear();
RESTClient.Headers.Add("sign", sign);
RESTClient.Headers.Add("key", ApiKey);
try
{
var retVal = await RESTClient.PostAsync<string, postdata>(postdata, "/my/balances");
System.Diagnostics.Debug.WriteLine(retVal);
}
catch (Exception ex)
{
}
throw new NotImplementedException();
}
The doco is very scant! I'm stuck.
https://www.coinspot.com.au/api
I don't have the error handy right now, but it was a completely non-descript error with information about what went wrong. It was something like "invalid call". But, I know that it is accepted my posted data to some extent, because if I change the name of the property "nonce" to "noncey", I get a meaningful error back that says "no nonce".
Did you ever manage to get this API working. CoinSpot are not very supportive of this. I can only get 3 of the coins API working which isn't much help
I managed to get it working recently and put together a simple SDK in .NET
https://github.com/QuintinHumphreys/CoinspotAPI
tl:dr It's undocumented but you need to use port 443, I found it by digging through their node SDK.
I was having the same issue, getting the very non-descriptive {status: invalid} response, in my case using Elixir not C#. I got it to work by peeking into their node SDK - my details worked using their SDK so I knew it had to be something I wasn't doing properly (although their documentation is pretty shocking). They use port 443 and as soon as I set that it worked.
I tried 2 things, I'm 90% sure it was the port number but half way through my getting it to work I printed the sha512 sign created by their node sdk and compared it to the one I generating using Cryptex I saw that they were generating the same sha512 signature, but my one was in capital letters while the node one was in lowercase - this may or may not end up mattering but I did use String.downcase() on mine in the end.
I have a program that comunicates with an external http server to the request a first, second etc value... (1º,2º,3º,4º,...)
I have an issue in c# with the º character.
Here is some example code:
var testdata=new Dictionary<string,string>{
{"val","º"},
{"val1","\xBA"},
{"val2","\u00BA"},
};
var content = new FormUrlEncodedContent(testdata);
var cont = content.ReadAsStringAsync().GetAwaiter().GetResult();
the result is:
val=%C2%BA&val1=%C2%BA&val2=%C2%BA
I test the communication with the server with curl and firefox console
and the result should be:
val=%BA&val1=%BA&val2=%BA
Somehow the extra %C2 in C# dosent work with the server.
How can I fix or escape the º correctly?
This issue relates with the default encoding used by FormUrlEncodedContent which is UTF-8 and your server expect ISO-8859-1.
Here is a workaround to get over it but you'll need (unfortunately) to add System.Web to your project :
// This is an implementation of FormUrlEncodedContent with `ISO-8859-1`
public class FormIso8859Encoder : ByteArrayContent
{
public FormIso8859Encoder(IEnumerable<KeyValuePair<string, string>> nameValueCollection)
: base(FormDataToByteArray(nameValueCollection))
{
Headers.Add("Content-Type", "application/x-www-form-urlencoded");
}
private static byte[] FormDataToByteArray(IEnumerable<KeyValuePair<string, string>> nameValueCollection)
{
StringBuilder sb = new StringBuilder();
foreach (var nameValue in nameValueCollection)
{
if (sb.Length > 0)
sb.Append('&');
sb.Append(nameValue.Key);
sb.Append('=');
// Here is the major change
sb.Append(HttpUtility.UrlEncode(nameValue.Value, Encoding.GetEncoding("iso-8859-1") ));
}
return Encoding.Default.GetBytes(sb.ToString());
}
}
Then
var testdata=new Dictionary<string,string>{
{"val","º"},
{"val1","\xBA"},
{"val2","\u00BA"},
};
var content = new FormIso8859Encoder(testdata);
var cont = content.ReadAsStringAsync().GetAwaiter().GetResult();
This provide the following output :
val=%BA&val1=%BA&val2=%BA
The correct unicode character for ° is \u00B0. More info can you find here how to work with unicode in C#.
All unicode characters can be found here.
I'm using Facebook as a login provider for my web application (ASP.NET MVC).
My login works similar to another StackOverflow post How to securely authorize a user via Facebook's Javascript SDK. I also share the user's concerns.
The flow for my login is as Follows:
1. The user presses the login button.
2. The user must accept the app.
3. A javascript callback retrieves the response.
var authResponse = response.authResponse;
Object returned:
{
accessToken: "...",
expiresIn: 1234,
signedRequest: "...",
userID: "123456789"
}
I've heard that I can used the signed_request to validate the user's request, but all the examples online are for PHP. How do I do this in .NET?
To compile Rowan's answer into its final code:
public static string DecodeSignedRequest(string signed_request)
{
try
{
if (signed_request.Contains("."))
{
string[] split = signed_request.Split('.');
string signatureRaw = FixBase64String(split[0]);
string dataRaw = FixBase64String(split[1]);
// the decoded signature
byte[] signature = Convert.FromBase64String(signatureRaw);
byte[] dataBuffer = Convert.FromBase64String(dataRaw);
// JSON object
string data = Encoding.UTF8.GetString(dataBuffer);
byte[] appSecretBytes = Encoding.UTF8.GetBytes(app_secret);
System.Security.Cryptography.HMAC hmac = new System.Security.Cryptography.HMACSHA256(appSecretBytes);
byte[] expectedHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(split[1]));
if (expectedHash.SequenceEqual(signature))
{
return data;
}
}
}
catch
{
// error
}
return "";
}
private static string FixBase64String(string str)
{
while (str.Length % 4 != 0)
{
str = str.PadRight(str.Length + 1, '=');
}
return str.Replace("-", "+").Replace("_", "/");
}
Thanks Rowan!
Yes, the signed_request can be used to verify that an incoming login request is genuine. If you're logging in a user with Javascript (via AJAX, for example) you can use the signed_request to ensure that the data isn't false.
According to Parsing the Signed Request, there are 3 major steps, however I'll be a little more specific.
Take the signed_request string and split it into two strings. There is a period character (full stop) which is a delimiter.
The first part of the string (the signature) is a hash of the second part.
The second part contains some information about the user and the request (user ID, timestamp).
The strings are in Base64, but cannot be decoded straight away.
They are Base64-URL-encoded which means that + and / characters have been replaced with URL-friendly - and _ characters. Replace - characters with + and _ characters with /.
The strings may not be fully Base64 padded. Base64 strings should be divisible by 4; pad the strings out as necessary.
Hash the signature using HMAC (SHA256) using your app secret as the key and compare the result to the signature that was provided.
Use the .NET class HMACSHA256.
1. Split and decode
Code
string response = ""; // the signed_request
string[] split = response.Split('.');
string signatureRaw = FixBase64String(split[0]);
string dataRaw = FixBase64String(split[1]);
// the decoded signature
byte[] signature = Convert.FromBase64String(signatureRaw);
byte[] dataBuffer = Convert.FromBase64String(dataRaw);
// JSON object
string data = Encoding.UTF8.GetString(dataBuffer);
FixBase64String()
static string FixBase64String(string str)
{
string result = str;
while (result.Length % 4 != 0)
{
result = result.PadRight(result.Length + 1, '=');
}
result = result.Replace("-", "+").Replace("_", "/");
return result;
}
2. Compare the hashes
byte[] appSecretBytes = Encoding.UTF8.GetBytes("my_app_secret_here");
HMAC hmac = new HMACSHA256(appSecretBytes);
byte[] expectedHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(dataRaw));
bool areEqual = expectedHash.SequenceEqual(signature);
If areEqual is true then you can be sure that the signed request is valid and has not been tampered with (assuming your app secret is secure).
Remember to keep your app secret secure, otherwise malicious users can do bad things.
I'm new to Facebook apps. I'm trying to create an MVC 4 application with Facebook Application as my Project Template.
I'm trying to catch the page id on which the page tab is created and I've got it somehow.
My problem here is when someone visits my app, I want to know the page id through which they are viewing the page tab. I've searched a lot where I got to know that I've to use FacebookSignedRequest for this. But this class is not available to me.
Thanks in advance for any help.
If you are simply trying to parse the signed_request parameter from Facebook, you can do so using the following C# code.
This code also verifies the hash using your own app_secret param, to ensure the signed_request originated from Facebook.
public static string DecodeSignedRequest(string signed_request)
{
try
{
if (signed_request.Contains("."))
{
string[] split = signed_request.Split('.');
string signatureRaw = FixBase64String(split[0]);
string dataRaw = FixBase64String(split[1]);
// the decoded signature
byte[] signature = Convert.FromBase64String(signatureRaw);
byte[] dataBuffer = Convert.FromBase64String(dataRaw);
// JSON object
string data = Encoding.UTF8.GetString(dataBuffer);
byte[] appSecretBytes = Encoding.UTF8.GetBytes(app_secret);
System.Security.Cryptography.HMAC hmac = new System.Security.Cryptography.HMACSHA256(appSecretBytes);
byte[] expectedHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(split[1]));
if (expectedHash.SequenceEqual(signature))
{
return data;
}
}
}
catch
{
// error
}
return "";
}
private static string FixBase64String(string str)
{
while (str.Length % 4 != 0)
{
str = str.PadRight(str.Length + 1, '=');
}
return str.Replace("-", "+").Replace("_", "/");
}
All I had to do was create a Facebook Client object and call the ParseSignedRequest method with the app secret.
var fb = new FacebookClient();
dynamic signedRequest = fb.ParseSignedRequest(appSecret, Request.Form["signed_request"]);
This returns a Json object which we have to parse using JObject.Parse