Created
March 25, 2014 11:22
Using ColdFusion With Pusher - A Notification Service Powered By HTML5 WebSockets
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!--- Param the form value. ---> | |
<cfparam name="form.message" type="string" default="" /> | |
<!--- | |
Check to see if the message is available (if the user | |
submitted the form). | |
---> | |
<cfif len( form.message )> | |
<!--- | |
Pusher information used to tie this push notification | |
to a given application and to a given client (listening | |
for a given channel). | |
---> | |
<cfset pusherAppID = "1306" /> | |
<cfset pusherKey = "61b7e858d47e67683bd8" /> | |
<cfset pusherSecret = "****************" /> | |
<cfset pusherChannel = "helloWorld" /> | |
<!--- | |
Event we are triggering (this is what the client will | |
"bind" to on the given channel). | |
---> | |
<cfset pusherEvent = "hellowWorldEvent" /> | |
<!--- | |
Data we are actually "pushing". All data must be sent as | |
JSON (although it doesn't have to be simple string values). | |
---> | |
<cfset pusherMessage = serializeJSON( form.message ) /> | |
<!--- Authentication information. ---> | |
<cfset authVersion = "1.0" /> | |
<cfset authMD5Body = lcase( hash( pusherMessage, "md5" ) ) /> | |
<cfset authTimeStamp = fix( getTickCount() / 1000 ) /> | |
<!--- Build the post resource (the RESTfule resource). ---> | |
<cfset pusherResource = "/apps/#pusherAppID#/channels/#pusherChannel#/events" /> | |
<!--- ------------------------------------------------- ---> | |
<!--- ------------------------------------------------- ---> | |
<!--- | |
The following is the digital signing of the HTTP request. | |
Frankly, this stuff is pretty far above my understanding | |
of cryptology. I have adapted code from the PusherApp | |
ColdFusion component written by Bradley Lambert: | |
http://github.com/blambert/pusher-cfc | |
To be 100% honest with you, I find this step to be very | |
frustrating. Do we really need so much security around this? | |
---> | |
<!--- | |
Create the list of query string values (alpha-sorted with no | |
URL encoding). | |
---> | |
<cfsavecontent variable="queryStringData"> | |
<cfoutput> | |
auth_key=#pusherKey# | |
auth_timestamp=#authTimeStamp# | |
auth_version=#authVersion# | |
body_md5=#authMD5Body# | |
name=#pusherEvent# | |
</cfoutput> | |
</cfsavecontent> | |
<!--- | |
Create the raw signature data. This is the HTTP | |
method, the resource, and the alpha-ordered query | |
string (non-URL-encoded values). | |
---> | |
<cfset signatureData = ( | |
("POST" & chr( 10 )) & | |
(pusherResource & chr( 10 )) & | |
reReplace( | |
trim( queryStringData ), | |
"\s+", | |
"&", | |
"all" | |
) | |
) /> | |
<!--- | |
Create our secret key generator. This can create a secret | |
key from a given byte array. Initialize it with the byte | |
array version of our PushApp secret key and the algorithm | |
we want to use to generate the secret key. | |
---> | |
<cfset secretKeySpec = createObject( | |
"java", | |
"javax.crypto.spec.SecretKeySpec" | |
).init( | |
toBinary( toBase64( pusherSecret ) ), | |
"HmacSHA256" | |
) | |
/> | |
<!--- | |
Create our MAC (Message Authentication Code) generator | |
to encrypt the message data using the PusherApp shared | |
secret key. | |
---> | |
<cfset mac = createObject( "java", "javax.crypto.Mac" ) | |
.getInstance( "HmacSHA256" ) | |
/> | |
<!--- Initialize the MAC instance using our secret key. ---> | |
<cfset mac.init( secretKeySpec ) /> | |
<!--- | |
Complete the mac operation, encrypting the given secret | |
key (that we created above). | |
---> | |
<cfset encryptedBytes = mac.doFinal( signatureData.getBytes() ) /> | |
<!--- | |
Now that we have the encrypted data, we have to convert | |
that data to a HEX-encoded string. We will use the big | |
integer for this. | |
---> | |
<cfset bigInt = createObject( "java", "java.math.BigInteger" ) | |
.init( 1, encryptedBytes ) | |
/> | |
<!--- Convert the encrypted bytes to the HEX string. ---> | |
<cfset secureSignature = bigInt.toString(16) /> | |
<!--- | |
Apparently, we need to make sure the signature is at least | |
32 characters long. As such, let's just left-pad with spaces | |
and then replace with zeroes. | |
---> | |
<cfset secureSignature = replace( | |
lJustify( secureSignature, 32 ), | |
" ", | |
"0", | |
"all" | |
) /> | |
<!--- ----------------------------------------------------- ---> | |
<!--- ----------------------------------------------------- ---> | |
<!--- | |
Now that we have all the values we want to post, including | |
our encrypted signature, we can post to the PusherApp REST | |
web service using CFHTTP. | |
---> | |
<cfhttp | |
result="post" | |
method="post" | |
url="http://api.pusherapp.com#pusherResource#"> | |
<!--- | |
Alert the post resource that the value is coming through | |
as JSON data. | |
---> | |
<cfhttpparam | |
type="header" | |
name="content-type" | |
value="application/json" | |
/> | |
<!--- Set the authorization parameters. ---> | |
<cfhttpparam | |
type="url" | |
name="auth_version" | |
value="#authVersion#" | |
/> | |
<cfhttpparam | |
type="url" | |
name="auth_key" | |
value="#pusherKey#" | |
/> | |
<cfhttpparam | |
type="url" | |
name="auth_timestamp" | |
value="#authTimeStamp#" | |
/> | |
<cfhttpparam | |
type="url" | |
name="body_md5" | |
value="#authMD5Body#" | |
/> | |
<!--- Sent the name of the pusher event. ---> | |
<cfhttpparam | |
type="url" | |
name="name" | |
value="#pusherEvent#" | |
/> | |
<!--- Send the actual message (JSON data). ---> | |
<cfhttpparam | |
type="body" | |
value="#pusherMessage#" | |
/> | |
<!--- Digitally sign the HTTP request. ---> | |
<cfhttpparam | |
type="url" | |
name="auth_signature" | |
value="#secureSignature#" | |
/> | |
</cfhttp> | |
</cfif> | |
<!--- ----------------------------------------------------- ---> | |
<!--- ----------------------------------------------------- ---> | |
<cfoutput> | |
<!DOCTYPE HTML> | |
<html> | |
<head> | |
<title>PusherApp Hello World - ColdFusion Pusher</title> | |
</head> | |
<body> | |
<h1> | |
PusherApp Hello World - ColdFusion Pusher | |
</h1> | |
<form action="#cgi.script_name#" method="post"> | |
<p> | |
Enter your message to push: | |
</p> | |
<p> | |
<input type="text" name="message" size="40" /> | |
<input type="submit" value="Push It, Push It Real Good!" /> | |
</p> | |
</form> | |
</body> | |
</html> | |
</cfoutput> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE HTML> | |
<html> | |
<head> | |
<title>PushApp Hello World With ColdFusion</title> | |
<script type="text/javascript" src="jquery-1.4.2.min.js"></script> | |
<script type="text/javascript" src="http://js.pusherapp.com/1.4/pusher.min.js"></script> | |
<script type="text/javascript"> | |
// This is for compatability with browsers that don't yet | |
// support Web Sockets, but DO support Flash. | |
// | |
// NOTE: This SWF can be downloaded from the PusherApp | |
// website. It is a Flash proxy to the standard Web | |
// Sockets interface. | |
WebSocket.__swfLocation = "./WebSocketMain.swf"; | |
// When the DOM is ready, init the scripts. Technically, we | |
// can bind the PusherApp before DOM ready, but we can't | |
// respond to it, so no need to bind early. | |
$(function(){ | |
// Get a reference to the message list. | |
var messages = $( "#messages" ); | |
// Create a Pusher server object with your app's key and | |
// the channel you want to listen on. Channels are unique | |
// to your application. | |
var server = new Pusher( | |
"61b7e858d47e67683bd8", | |
"helloWorld" | |
); | |
// Now that we have the pusher connection for a given | |
// channel, we want to listen for certain events to come | |
// over that channel. | |
server.bind( | |
"hellowWorldEvent", | |
function( data ) { | |
// The data that comes through is the evaluated | |
// JSON data that was pushed to the client. In | |
// our case, it's just a simple string. | |
messages.prepend( | |
"<li>" + data + "</li>" | |
); | |
} | |
); | |
}); | |
</script> | |
</head> | |
<body> | |
<h1> | |
PusherApp Hello World With ColdFusion | |
</h1> | |
<p> | |
This page will listen for PusherApp via HTML5 Socket connectsion | |
(or, if not supported, a Flash SWF fallback). Messages will be posted | |
below as they arrive. | |
</p> | |
<ol id="messages"> | |
<!-- To be populated via PUSH notification. --> | |
</ol> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment