Hey guys,
This is sort of a two part question. I'm building a flash image viewer to be a portable age-restricted module (violent video games). Basically, it will load any number of images from a CDN and require the user to enter their birthday before viewing it. Simple stuff. The problem is that, per company policy, we can't allow those images to be directly accessible by any means of sniffing (eg, watching your Resources/Net tab in Webkit/Firebug, or watching XHR if we loaded them that way). So, I'd like to get your opinions about the best way to approach this.
At first I thought to have a server-side script that loads the image (eg via PHP) by passing a var that can be decrypted but with a dynamic salt, eg, using a method that is very unlikely to be discovered (for example, having the salt be embedded throughout the string), but that defeats the purpose of the CDN as all requests would be geolocated to the server.
Then I thought that loading the images via sockets would be a good solution, however, I'm having trouble converting the binary image (after removing the response headers) to a Bitmap.
Is there a better way to go about this? I know that realistically it's impossible to completely prevent the content from being linked to (eg someone could screenshot the flash) but my goal is just to take steps on our side to prevent that from happening by native means. Any thoughts would be appreciated. Below is the socket code (irrelevant parts removed), if that helps any.
package com.std.socket {
import flash.system.Security;
import flash.net.Socket;
import flash.events.*;
import flash.errors.*;
import flash.display.Bitmap;
import flash.display.MovieClip;
import flash.display.Loader;
import flash.utils.ByteArray;
public class SocketRequest {
private var root:MovieClip;
private var sock:Socket;
private var data:ByteArray = new ByteArray();
private var request:Object = {
'host': null,
'port': null,
'uri': null,
'callback': null,
'response_parts': [] };
public function SocketRequest(root:MovieClip, host:String, port:int, uri:String, callback:Function):void {
Security.allowDomain('*');
Security.loadPolicyFile('http://foo.bar/crossdomain.xml');
this.request.root = root;
this.request.host = host;
this.request.port = port;
this.request.uri = uri;
this.sock = new Socket();
this.sock.addEventListener(Event.CONNECT, this.evt_socketConnect);
this.sock.addEventListener(Event.CLOSE, this.evt_socketClose);
this.sock.addEventListener(ProgressEvent.SOCKET_DATA, this.evt_socketResponse);
this.sock.connect(this.request.host, this.request.port);
}
private function evt_socketConnect(evt:Event):void {
// Send the request headers
this.sock.writeUTFBytes('GET ' + this.request.uri + " HTTP/1.1\n");
this.sock.writeUTFBytes('Host: ' + this.request.host + ':' + this.request.port + "\n\n");
}
private function evt_socketClose(evt:Event):void {
// Since this is an image, just split on header \r\n and get the last member
var response:Array = this.request.response_parts.join('').split("\r\n");
var body:String = response[response.length - 1];
var loader = new Loader();
var ba:ByteArray = new ByteArray();
var mc:MovieClip = new MovieClip();
this.data.writeMultiByte(body, 'utf-8');
loader.loadBytes(this.data);
mc.addChild(loader);
// Pass the resulting MovieClip back to the caller
if(typeof(this.request.callback) == 'function')
this.request.callback.apply(this.request.root, [mc])
}
private function evt_socketResponse(evt:ProgressEvent):void {
if(!this.sock.bytesAvailable)
return;
this.request.response_parts.push(this.sock.readUTFBytes(this.sock.bytesAvailable));
}
}
}
As I'm writing I'm thinking that in SocketRequest::evt_socketResponse()
, the this.sock.readUTFBytes()
bit should really be:
this.request.response_parts.push(this.sock.readBytes(this.data, this.data.length, evt.bytesLoaded));
and then remove the headers from this.data
, but TBH I'm not super ByteArray-savvy. Does anyone have any thoughts?