Using Coldfusion to decode a facebook signed_request - facebook

I'm trying to use ColdFusion 9 to decode the signed_request variable that facebook passes. It is a base64 URL encoded string that needs to be decoded. In order to decode base64 strings one should do:
ToString( BinaryDecode( 'Base64 URL Encoded String' ) )
When I do this I get the error: input and output encodings are not same.
I took this same string to this website and decoded it correctly: http://www.motobit.com/util/base64-decoder-encoder.asp

The issue is that the Facebook signed_request parameter doesn't have any "=" padding at end. It is expecting the receiving end to add the padding before being put through BinaryDecode().
Try
<cfset signed_request = listtoarray(form.signed_request,".")>
<cfset fb_str = replacelist(signed_request[2], "-,_", "+,/")>
<cfset padding = repeatstring("=",4-len(fb_str) mod 4)>
<cfset data = toString(BinaryDecode(fb_str & padding,"base64"))>
<cfoutput>#data#</cfoutput>

I found a solution to this problem. It seems like the built in ColdFusion BinaryDecode function can handle some of these strings. Here's the code:
<cfset fb_str = Replace(Replace(ListGetAt(FORM.signed_request, 2, "."), "-", "+", "ALL"), "_", "/", "ALL")>
<cfset jstr = JavaCast("string", fb_str)>
<cfset decoder = CreateObject("java", "org.apache.commons.codec.binary.Base64")>
<cfset result = decoder.decodeBase64(jstr.getBytes())>
<cfoutput>#ToString(result)#</cfoutput>

A quick search around the net leads me to think that the facebook response is "base64url" which is encoded for passing in a url.
So, try doing a
ToString( BinaryDecode( UrlDecode('Base64 URL Encoded String') ) )
And, if that doesn't work, I found this function
<cffunction name="Base64URLDecode" access="public" output="false" returntype="string" hint="Returns a base64url decoded string.">
<cfargument name="String" type="string" required="true" hint="String to decode.">
<cfreturn Variables.Base64Decode( Replace( Replace( Arguments.String, "-", "+", "all"), "_", "/", "all") & RepeatString("=", Len(Arguments.String) + (4 - Len(Arguments.String) % 4) % 4))>
</cffunction>
from this url: http://pastebin.com/bFb1bBpU

Check out Ben Nadel's post on how he did this:oAuth and CF
His code samples show you exactly what you need to do to solve this issue. It took him a while, but it works!

I know I'm late to the game on this comment but I wrote a tutorial on exactly this here!
It turns out that Facebook don't use a standard base64 encoding and it needs padding out to the right length. Check the link to get a struct containing the data from the signed_request.

Related

xml-rpc with coldfusion - how to pass in parameters?

I'm trying to make an xml-rpc call from a coldfusion server. I found this xml-rpc cfc (Thanks, Brad Wood!) that formats the xml for the cfhttp call but I'm struggling with interpretting how to pass in any parameters besides the call name.
Here's the api documention using perl
This is my coldfusion code
<cfobject component="xmlrpc" name="c">
<cfset arr = arraynew(1)>
<cfset arrayappend(arr,"service.show")>
<cfset arrayappend(arr,myVIP)>
<cfset arrayappend(arr,myIP)>
<cfset arrayappend(arr,myPort)>
<cfset myxml = c.CFML2XMLRPC(arr,"call")>
<cfhttp url="#apiUrl#" method="POST">
<cfhttpparam name="request_body" value="#myxml#" type="XML">
</cfhttp>
The error message that I keep getting is:
Can't use string (myVIP...) as a HASH ref while "strict refs" in
use at /home/...
So what I don't understand is how to translate the notation I see in perl of {parameter1=>'value1',parameter2=>'value2'} to the array that I'm passing into CFML2XMLRPC.
I figured it out and now it seems so obvious... You have to use a struct to hold the parameters and pass that into the array after the method string.
<cfset arr = arraynew(1)>
<cfset arrayappend(arr,"service.show")>
<cfset paramObj = structnew()>
<cfset paramObj['vip'] = myVIP>
<cfset paramObj['ip'] = myIP>
<cfset paramObj['port'] = myPort>
<cfset paramObj['show'] = "status/state">
<cfset arrayappend(arr,paramObj)>
I found the jquery xml-rpc documentation helpful to understanding how the xml should actually be formatted.
Note: the notation of
<cfset paramObj['ip'] = myIP>
vs
<cfset paramObj.ip = myIP>
is important since the latter will result in all uppercase for the parameter name in xmlrpc.cfc. (thanks to comment by Dave Merrill on this post)

BrowserWindow.Launch NOT decode string

In a codedui, this line decodes the link before opening the browser:
myBrowser = BrowserWindow.Launch(New System.Uri("http://blablabla/main.aspx?sn=JFA%3d%3d"))
I want it to remain encoded in the url. In other words, when the browser opens, the %3d are already converted to "=" in the string.
http://mylinkhere/main.aspx?sn=JFA==
I want them to remain as %3d.
Thanks
Try this bro, this is in c# btw.
String URL = HttpUtility.UrlEncode("sn=JFA%3d%3d");
window = BrowserWindow.Launch(new Uri("http://blablabla/main.aspx?" + URL));

How to declare dynamic form field defaults inside a Coldfusion CFC?

I'm looking for a way to declare form default values dynamically in a CFC, I'm calling via AJAX. The current CFC sends orders, which I need to break down into sub-orders.
I had been using this:
<!--- static defaults --->
<cffunction name="Defaults" access="public" returntype="struct" output="false"
hint="Assign default values to instance">
<cfscript>
var formDefaults = {
versenden=""
, speichern=""
...
}
</cfscript>
<cfreturn formDefaults />
</cffunction>
<cffunction name="Commit" access="public" returntype="struct" output="false" hint="database handler">
<!--- add dynamic form fields --->
<cfscript>
var LOCAL = {};
variables.defs = THIS.Defaults();
</cfscript>
<cfloop collection="#VARIABLES.Instance.FormData#" item="formField">
<cfscript>
if ( LEFT(formField, 5) EQ "MENGE"
OR LEFT(formField, 3) EQ "EAN"
OR LEFT(formField, 12) EQ "BESTELL_TEXT"
OR LEFT(formField, 10) EQ "BESTELLTYP"
...
) {
variables.defs[formField]="";
}
</cfscript>
</cfloop>
<cfscript>
structAppend(variables.defs, VARIABLES.Instance.FormData);
LOCAL.Basket = variables.defs;
</cfscript>
...
So I first declare static form fields (single instance only) and then try to dynamically append dynamic form fields to my array, which might be transferred multiple times (MENGE38, MENGE39, MENGE40 etc)
While this works ok, I need to add another counting element to my form-names, so I would have to change MENGE to something like counter.MENGE or MENGE.counter which will then send form values like this:
MENGE.1.38
MENGE.1.40
MENGE.1.41
MENGE.2.37
With the counter denoting the sub-order, this field is used for.
Problem is, this breaks my dynamic form field declaration and I don't understand why. I'm getting the following errors:
Diagnose: Element MENGE.1 is undefined in a CFML structure referenced as part of an expression.
Question:
Can anyone give me a hint on what the problem might be? Do I have to param the form fields on the HTML page as well (shouldn't have to)?
Thanks!
EDIT:
Problem was in my validate function, I also need to declare the modifications I did above. The new function looks like this:
<cffunction name="Validate" access="public" returntype="array" output="false" hint="validate form inputs and return an array of faulty field names.">
<cfscript>
var LOCAL = {};
var double = structNew();
double.form = VARIABLES.Instance.FormData;
double.criteria = VARIABLES.Instance.Validation;
</cfscript>
<!--- add dynamic form fields for validation... I FORGOT TO UPDATE THIS--->
<cfloop collection="#VARIABLES.Instance.FormData#" item="formField">
<cfscript>
if ( LEFT(formField, 5) EQ "MENGE"
OR LEFT(formField, 10) EQ 'BESTELLTYP'
OR LEFT(formField, 3) EQ "EAN"
OR LEFT(formField, 12) EQ "BESTELL_TEXT"
...
) {
VARIABLES.Instance.Validation[formField]="pass";
}
</cfscript>
</cfloop>
<!--- Get error names and type --->
<cfinvoke component="form_validate" method="validate_fields" double="#double#" returnvariable="validation_errors"></cfinvoke>
<cfset LOCAL.ErrorMessages = validation_errors />
<cfreturn LOCAL.ErrorMessages />
Because I did not add the new updated the if-clause in this function, I was getting the error.
To build on Dan Bracuk's answer, use underscores (though you'd need to change the name of "BESTELL_TEXT"). Use this with a combination of listFirst, listGetAt, and listLast to determine field name structure, using underscore as delimiter. Note how I cleaned up your big IF a bit using list function. This code as written probably doesn't do what you need, but wanted to illustrate the concepts without having to understand your business need.
<cfscript>
var orders=structNew();
item=listFirst(formField,'_');
orderNames = "MENGE,EAN,BESTELLTEXT,BESTELLTYPE";
if (listFindNoCase(orderNames,item,'_')){
if (!structKeyExists(orders,item)){
// initialize item
orders[item]=structNew();
}
orderID="";
subOrderId="";
if (listLen(formField,'_') gt 1) {
orderID=listGetAt(formField,2,'_');
}
if (listLen(formField,'_') eq 2) {
orders[item][orderId]=formData[formField];
}
if (listLen(formField,'_') eq 3) {
subOrderId=listLast(formField,'_');
orders[item][orderId][subOrderId]=formData[formField];
}
}
</cfscript>

MSXML2.ServerHTTP in Coldfusion 8 fails to post data

In trying to work around the buggy <cfhttp> SSL implementation, I switched to using COM and MSXML2.ServerHTTP directly. Unfortunately the POST data fails to arrive at the destination page. GET works, but I'd rather not use it, since I have no idea if the request urls are logged and I don't want to pass sensitive data if I can help it. (Am I worrying too much?)
My problem is similar to this one: http://objectmix.com/xml-soap/87408-sending-post-variables-using-msxml2-serverxmlhttp-3-0-a.html
Here's my code:
<cfset querystring = "?CustomerID=#CustomerID#&OrderDelRecipient=#OrderDelRecipient#&OrderCompany=#OrderCompany#&OrderTelephone=#OrderTelephone#&OrderNotes=#OrderNotes#&OrderDelStreet=#OrderDelStreet#&OrderDelCity=#OrderDelCity#&OrderDelState=#OrderDelState#&OrderDelZip=#OrderDelZip#">
<cfobject type="COM" action="Create" name="objSrvHTTP" class="MSXML2.ServerXMLHTTP.3.0">
<cfset urlstring = "http://www.pascaltechnologies.com/saveorder.cfm">
<cfset temp = objSrvHTTP.open("post", urlstring, false)>
<cfset temp = objSrvHTTP.setRequestHeader("Content-Type", "application/x-www-form-
urlencoded")>
<cfset temp = objSrvHTTP.send("#querystring#")>
<cfset FileContent = objSrvHTTP.responsetext>
<cfoutput>
#filecontent#
</cfoutput>
When I check for the Form vars on the called page (saveorder.cfm)
<cfif Not IsDefined("CustomerID") OR NOT IsNumeric(CustomerID)>
ERR 609 - INVALID PARAMETERS PASSED.
<cfabort>
</cfif>
they are empty, so the above code gets triggered.
Is this because I need to copy the response to the form var? e.g. <cfset FORM.CustomerID = objSrvHTTP.CustomerID> (You'd think it wouldn't be necessary since it isn't needed with GET.) Or am I simply not implementing something correctly?

Method post: accents on my app's description, posting on user's wall, result in diamonds and interrogation signs

I'm using a http call to post information about my app in any user's wall. I do it in this way:
_url = "https://graph.facebook.com/" + user_id + "/feed?message=MSG";
_url += "&access_token=" + access_token;
_url += "&picture=" + fb_app_url + "fb_icon.png";
_url += "&name=" + String_ToUrl("MY GAMES");
_url += "&link=" + "http://www.nlkgames.com";
_url += "&description=String_ToUrl("descripción with accent")"
_url += "&method=post";
http.URL_CALL(_url);
This method post right the information in the user's wall, but the accents are shown by a diamond with a question sign inside it. I don't know how to make it works with accents.
String_ToUrl will encode string in this way:
"descripción with accent" = "descripci%E9n+with+accent"
What's my fail? Why the user's facebook's wall doesn't recognize the urlencoded?
Instead of encoding it for URL, what happens if you just post the description as is?
If that doesn't work, try converting the string using HTML entities and then URL Encoding the description.
you could also try to replace those letters with the ASCII representation (somewhat like \u123) - that would be what the Graph API gives you when there is such a Special character (in my case it would be äöü from the german alphabet)
Your String_ToUrl function doesn't encode URL in unicode aware way.
ó (aka 'LATIN SMALL LETTER O WITH ACUTE' (U+00F3)) should became %C3%B3 in URL encoded form, and not %F3 (in your case you indicated that it became %E9 which in fact é character).
descripción -> descripci%C3%B3n
Be sure to use proper (and unicode aware) way to encode your parameters, in JavaScript for example encodeURIComponent should be used...