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
Related
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.
In Asp.Net core, a cookie is created when you configure your app to app.UseSession().
By default the cookie is called ".AspNetCore.Session". Its value identifies the session to be used. Currently, I'm saving my session data on a sql server. I need to know the decrypted value of ".AspNetCore.Session" so that I can lookup the session in the database.
Is there a way to decrypt this value? I know ASP.NET must do it behind the scenes somehow.
The session source has everything, but you should need to know it, ISessionStore and IDistributedSessionStore gives you a sessionkey to use.
Rather than make an assumption about the cookie format, what is stopping you from using the store APIs?
I had to extract the private Pad function from Microsoft.AspNetCore.Session, but I was able to get what I needed:
public class DiscussionController : Controller
{
private readonly IDataProtector _dataProtector;
public DiscussionController(IDataProtectionProvider dataProtectionProvider)
{
var protectorPurpose = "whatever purpose you want";
_dataProtector = dataProtectionProvider.CreateProtector(protectorPurpose);
}
public IActionResult Index()
{
HttpContext.Request.Cookies.TryGetValue(".AspNetCore.Session", out string cookieValue);
var protectedData = Convert.FromBase64String(Pad(cookieValue));
var unprotectedData = _dataProtector.Unprotect(protectedData);
var humanReadableData = System.Text.Encoding.UTF8.GetString(unprotectedData);
return Ok();
}
private string Pad(string text)
{
var padding = 3 - ((text.Length + 3) % 4);
if (padding == 0)
{
return text;
}
return text + new string('=', padding);
}
}
The Pad function was taken from: https://github.com/aspnet/AspNetCore/blob/87629bbad906e9507026692904b6bcb5021cdd33/src/Middleware/Session/src/CookieProtection.cs#L61-L69
I want to check whether a facebook user liked my facebook page or not. I got so many solutions using javascript but I want to implement this requirement in ASP.Net.
I copied the code from the below link:
http://duanedawnrae.com/Blog/post/2012/02/29/Determine-if-a-Facebook-user-Likes-your-page-with-ASPNET.aspx
I got the below ASP.Net code which works for the same.
ASP.Net code:
public class WebService : System.Web.Services.WebService
{
[WebMethod()]
public string GetFacebookLikeStatus(string fbpageid, string fbappid, string fbtoken, string fburl)
{
string strReturn = null;
// Placeholder for the Facbook "like" API call
string strURL = null;
strURL = "https://graph.facebook.com/me/likes?access_token=" + fbtoken;
// Placeholder for the Facebook GET response
WebRequest objGETURL = null;
objGETURL = WebRequest.Create(strURL);
// Declare response stream
Stream objStream = null;
// Declare The Facebook response
string strLine = null;
// Declare a count on the search term
int intStr = 0;
try
{
// Create an instance of the StreamReader
StreamReader objReader = new StreamReader(objStream);
// Get the response from the Facebook API as a JSON string.
// If access_token is not correct for the logged
// on user Facebook returns (400) bad request error
objStream = objGETURL.GetResponse().GetResponseStream();
// If all is well
try
{
// Execute the StreamReader
strLine = objReader.ReadToEnd().ToString();
// Check if Facebook page Id exists or not
intStr = strLine.IndexOf(fbpageid); // if valid return a value
if (intStr > 0)
{
strReturn = "1";
// if not valid return a value
}
else
{
strReturn = "0";
}
objStream.Dispose();
}
catch (Exception ex)
{
// For testing comment out for production
strReturn = ex.ToString();
// Uncomment below for production
//strReturn = "Some friendly error message"
}
}
catch (Exception ex)
{
// For testing comment out for production
strReturn = ex.ToString();
// Uncomment below for production
//strReturn = "Some friendly error message"
}
return strReturn;
}
}
The above code contains a webservice which contains a single function. The function contains four input parameters and returns a single output string.
But when I run this webservice I got the error, “Value cannot be null. Parameter name: stream”. This error is coming because the “objStream” variable is set to null. Please fix the issue so that I can get my correct output as I dont know how to implement my requirement.
Like Gating is not allowed on Facebook, and neither is incentivizing users to like your Page. Users must like something only because they really want to, you can´t reward them in any way.
That being said, you would need the user_likes permission to use /me/likes, and you would need to get it approved by Facebook. Which will not happen just for checking if the user liked your Page.
Btw, that article is from 2012. A lot of stuff changed since then.
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.
Apologies if this is somewhere, but I'm struggling to find the details I need for wp7.
I have created the application on Facebook as required, and am retrieving an access token. The following code posts to Facebook but I cannot get a response, nor can I work out how to monitor the response?
public bool fbUpload(string accessToken, Picture pic)
{
try
{
Stream s = null;
s = PicturesLoader.LoadFileFromStorage(pic.Url);
//Sets the byte array to the correct number of bytes
byte[] imageData = new byte[s.Length];
s.Read(imageData, 0, System.Convert.ToInt32(s.Length));
FacebookApp app = new FacebookApp();
IDictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("access_token", accessToken);
parameters.Add("message", "TEST - WP7 application [upload pic and comment on wall...]");
var mediaObject = new FacebookMediaObject { FileName = pic.Name, ContentType = "image/jpeg" };
mediaObject.SetValue(imageData);
parameters["source"] = mediaObject;
FacebookAsyncResult postResult;
FacebookAsyncCallback fbCB = new FacebookAsyncCallback();
app.PostAsync(parameters, fbCB);
return true;
}
catch (InvalidCastException ex)
{
return false;
}
}
The other question I have, is how do you allow users to allow access based upon their own Facebook account. I want to store a user's account details so they only have to set up the account details once, and then they can use my phone app with having to sign in?
You can handle the post result something like this:
FacebookAsyncCallback callBack = new FacebookAsyncCallback(postResult);
fbApp.PostAsync(parameters, args, callBack);
private void postResult(FacebookAsyncResult asyncResult)
{
// Do something with asyncResult here;
}
Regarding the second question, you must ask for permissions to access this data.
You usually do that in the FacebookOAuthClient.GetLoginUrl(<appId>, null, <permissions>) method call.
Once that's done, you can store the files you have permissions to locally in your app.