Is there a way to get a list of the exposed functions from a Flash object? For example, you could get a list of all methods in an object by executing:
for (var i in object) {
if (typeof object[i] == "function") {
console.log(i);
}
}
The only issue is that this won't expose any methods registered through the ExternalInterfaces API. I can try and see if the function exists (object['method']) and it tells me it is a function, but I would have to guess every existing method in this manner.
NOTE: Obviously, I don't have access to the actionscript.
Just hit this question, a tad to late it seems, but I'll post an answer anyways ;)
Using IE10 (windows 7) it worked perfectly fine for me to list all my methods like so:
var obj = document.getElementById('flashObj');
for(var prop in obj){
var fx = obj[prop];
if(obj.hasOwnProperty(prop) && (typeof fx == 'function') && /eval\(instance/.test(fx)){
console.log(prop)
}
}
Note that this did not work in Chrome or Firefox and only with the exact regexp since IE10 does not report "native code" as the other browsers do.
The problem is even worse: the information is neither available in ActionScript. You register a new function as ExternalInterface.addCallback('foo', foo) and you can not list already registered callbacks.
Just a guess but see if it works. All the ExternalInterface functions should be defined in the global namespace. Try embedding the SWF in an HTML page and get all the Javascript functions defined for the page after the page has loaded. List of global user defined functions in JavaScript?
The list of functions should be those defined in the SWF file.
I guess the only way to go is to parse the SWF file bytecode and try to gather the calls to ExternalInterface.addCallback method.
http://www.google.com/search?q=parse+avm2
My instinct is no, ExternalInterface is essentially a black box, or black letter box, you poke things through and sometimes things come back, but you can't open the door to see what's inside.
Without documentation as to what's been exposed in the SWF, the only other suggestion is decompiling the swf to have a look at the source.
Related
I am trying to load sounds through the SoundJS sound registration, and getting the following error:
createjs.js:15 Uncaught Error: Type not recognized.
I figure that the soundjs library is having issues either locating my files or having trouble with the file extensions, but I am using .ogg, which is inline with all the examples I've seen.
Here is my code:
createjs.Sound.alternateExtensions = ["mp3", "ogg"];
createjs.Sound.on("fileload", function(event) {
console.log(event);
}, this);
for (var i = 0; i < soundManifest.length; i++) {
soundManifest[i].loaded = false;
console.log("loading " + soundManifest[i].src);
createjs.Sound.registerSound(soundManifest[i].src, soundManifest[i].id)
}
soundManifest is an array of objects with a source item giving the path to the .ogg files, and an id. I've double and triple checked the path names, so pretty sure that's not it. Any ideas? I am developing on Chrome.
Thanks for posting a github link. It was helpful. Fortunately, I have a super simple answer for you.
Rename the "Object" class you made in Main.js, and you should be good to go.
-- The long answer --
I tossed a breakpoint the error that is thrown, and it showed that when SoundJS tries to create a LoadItem, it fails. This is because it should be treating the LoadItem it receives as an Object, but the line below is failing:
} else if (value instanceof Object && value.src) {
// This code should be executed
}
At first I thought there was a bug in SoundJS that we had somehow missed in the last 2 years, but closer inspection showed that object prototypes in your application are messed up. If you open any browser window, and hit the console, this will return true:
({}) instanceof Object
// true
However while running your app, it returns false.
The issue became clear when I removed all your other classes other than CreateJS and main, and then tried this:
new Object();
// Throws an error that includes info about "Victor"
In main.js, you are defining an "Object" class, which extends a CreateJS Shape. It is global because there is no method closure around the code, so it overwrites the global Object class/prototype.
The reason I included this explanation, is because I couldn't figure out what was going on until I had my steps to show that prototypes were broken in the app mostly written out before the reason dawned on me. I thought it might be of some interest :)
I've been all over here and can't find an answer. I have a .swf sitting in an HTML page and I am trying to call a function inside of it from javascript. I can talk out from flash to the javascript but I can't get it to talk back in. I know I am targeting the object properly because I use console.log() on it and confirms what it is targeting.
I'm triggering the test from flash, calling a javascript function from inside the .swf, and having that function call the internal Flash function.
Flash Code:
//adds callback
ExternalInterface.addCallback("sendToFlash", flashTalkedTo);
//function called by the callback
public function flashTalkedTo():void{
//runs another function in javascript to log a string
ExternalInterface.call("callMe")
}
//calls javascript that tries to talk to Flash
ExternalInterface.call("catchFromFlash")
Javascript Code:
//function called by Flash that initiates
function catchFromFlash(){
talkToFlash()
}
//function that tries to talk to flash
function talkToFlash(){
document.getElementById('Noodleverse').sendToFlash()
}
//function called by Flash in the end to confirm call made
function callMe(){
console.log("Call Me")
}
Any help works, thanks!
Flash, and plugins in general, are a little bit fiddly. They don't behave quite like normal elements, and their functions don't behave quite like normal functions. For example, you can't save the element into a value and call a function from that. You also need to be careful because in some browsers the object is used and in others the embed is used.
The best way to call a function is to use swfobject (https://code.google.com/p/swfobject/) to abstract everything. Personally though, I use this (based on experience, maybe somebody can offer improvements):
HTML:
<object id="myplugin" ...>
...
<embed name="myplugin" ... />
</object>
JavaScript:
var o1=document.myplugin;
if(o1&&!!o1.myFlashFunction){
return document.myplugin.myFlashFunction(); // DO NOT USE o1 here. It will fail.
}
var o2=window.myplugin;
if(o2&&!!o2.myFlashFunction){
return window.myplugin.myFlashFunction(); // DO NOT USE o2 here
}
The first case (document) is for most new browsers. For example, Chrome will find the embed object. The second (window) is for IE and finds the object (IE, at least old IE, ignores embed). I'm not 100% sure the second is needed, because IE might also work with document, so call that voodoo code. Also window.myplugin will give an array of all matching elements in Chrome, FireFox, etc. (but we expect those to already be taken care of)
Is this a possible solution for a pure javascript sandbox ?
My willing is to execute an untrusted string of code without giving access to DOM, window, this, and so on but allowing the user to acces Math, JSON and other functionalities.
I've tested it on Chrome.
UPDATE:
I want to give the possibility to save on server user-defined code and make it available to other users. I'm looking for a way to deny access to the document ni order to make it safe.
function safe(code,args)
{
if (!args)
args=[];
return (function(){
for (i in window)
eval("var "+i+";");
return function(){return eval(code);}.apply(0,args);
})();
}
ff=function()
{
return 3.14;
}
console.log(safe("this;"));//Number
console.log(safe("window;"));//undefined
console.log(safe("console;"));//undefined
console.log(safe("Math;"));//MathConstructor
console.log(safe("JSON;"));//JSON
console.log(safe("Element;"));//undefined
console.log(safe("document;"));//undefined
console.log(safe("Math.cos(arguments[0]);",[3.14]));//-0.9999987317275395
console.log(safe("arguments[0]();",[ff]));//3.14
I've proposed it on an old post : https://stackoverflow.com/a/11513690/76081
Thanks!
It's unsafe. The following construction will get the global window object from inside your sandbox:
(function(){return this;})()
At which point, you can extract anything you want from it, including goodies like document.
Hat tip to T.J. Crowder for his answer on https://stackoverflow.com/a/2673780/149341 in which he described this exploit.
my first time on here.
My problem is with AS3, Javascript and possibly the browsers Firefox and IE.
I have done so much searching for an answer so i will print my code:
i am using this line to call the flash application and in all browsers its combatible and actually traces in firebug to hold an OBJECT->FLASH_ID so thats not the problem.
var obj = document.getElementById('test');
then i use addcallback:
obj.sendStatus(loggedIn);
now whats weird is that i trace all individual elments in chrome and
-obj = flash object
-sendStatus = flash->function
-loggedIn = either false or true;
everything works great but when i am on firefox or ie
it traces differently
-obj = flash object
-sendStatus = undefined
-loggedIn = either true or false;
now what am i missing??????????
i tried embedding rather than object insertion
i made sure that the id's were all unique
i checked to make sure i had the right flash object selected with getElementById
im so confused.. and it feels like something simple.
I know about some browser - dependent timing problems, making the interface of the flash object available...
A timer could help, try this:
var obj = document.getElementById('test');
setTimeout(function(){obj.sendStatus(loggedIn);}, 500);
500 is a bit to long, but just to be sure. If it works you can try to lower it to 200 - 300.
make sure you declared allowScriptAccess = sameDomain both in embed tag and object tag
in case you don't use swfObject
Maybe the way you get a reference to the swf is wrong, try this
function thisMovie(movieName) {
if (navigator.appName.indexOf("Microsoft") != -1) {
return window[movieName];
} else {
return document[movieName];
}
}
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/external/ExternalInterface.html
The problem is that using ExternalInterface requires both parties (browser and flash) to be ready.
You can have the flash poll a method in the page which just returns true so that you know its ready to receive calls from flash.
On the flip side if the page is cached, it can sometimes happen that the page wants to send to flash before flash is ready, so I use a callback to the page telling it flash is ready, so its like a handshake, once both parties are ready, then we can start sending data back and forth.
This has been my approach since Firefox 3.
I am trying to use javascript to run AS3 functions. When I attempt to compile I'm getting an "Access of undefined property" error message.
I've read a few things online about this but I'm still not understanding it. I want to have the flash file always listening for javascript.
Here is my AS3 code:
ExternalInterface.addCallback("song4", PauseMusicExt);
And my Javascript & HTML:
function returnVar3(song3) { return this[song3]; }
<input type="submit" name="playButton" id="playButton" value="Submit" onClick="returnVar('song3')"/>
Edit: Here is the pauseMusic function:
function pauseMusicExt():void
{
songPosition = channel.position;
channelSilence.stop();
channel.stop();
channel2.stop();
btnPlay.mouseEnabled = true;
}
I'm not sure about the extend of your app but you've got your addCallback function parameters mixed up..
See the doc, the first parameter is the name you want to expose the function as to javascript, the second is the actual internal AS3 function you want to trigger.
So the declaration should likely be something like:
ExternalInterface.addCallback("song4", pauseMusic);
(assuming that your function in the same scope as where you call addCallback)
That statement will create a "song4" method that you can call on your flash dom object
var fl = document.getElementById('myflashobject');
fl.song4()
After there's the issue that pauseMusic want a parameter (looks like you've made it a mouse event handler). You probably want to have a clean method that doesn't require a parameter like an internal as3 event param. Rewrite pauseMusic so it doesn't require it (you might need to create another method to handle the mouse event internally - like onPause(evt:MouseEvent), which then calls pauseMusic.
Edit: I don't know if a lot of people thought about doing that, but you can also totally use external interface to call firebug's console.log function to send messages to Firebug from flash (it's really helpful for debugging ExternalInterface issues, or any other flash problems - see the ExternalInterface.call function)
Hope u want to pause the audio player.
AS code :
ExternalInterface.addCallback("sndToAS",rcvdFmJS);
function rcvdFmJS(val){
if (val == "pause"){
audioPause();
}
}
JS code :
document.getElementById("movie").sndToAS("pause");