Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Angry Birds Refresh - ExternalInterface Login Failure #16942

Open
ultra0000 opened this issue Jun 30, 2024 · 4 comments
Open

Angry Birds Refresh - ExternalInterface Login Failure #16942

ultra0000 opened this issue Jun 30, 2024 · 4 comments
Labels
avm2 AVM2 (ActionScript 3.0) issues bug Something isn't working

Comments

@ultra0000
Copy link

Describe the bug

The authentication data fails to get sent through ExternalInterface, with the following error:

ERROR core/src/external.rs:310 Unhandled error in External Interface callback sendDiscordData: TypeError: Error #2007: Parameter closure must be non-null.

Expected behavior

The game should receive the data properly after authenticating with Discord.

Content Location

https://refresh.teamflashcord.com/

Affected platform

Browser's extension

Operating system

Windows 11

Browser

Microsoft Edge 126.0.2592.81

Additional information

Relevant JavaScript code:

var discordResult;
var gotResult = false;

function HandleDiscordResult(result) {
    discordResult = JSON.parse(result);
    gotResult = true;
}

function discordLogIn() {
    var urlToOpen = "/discordauth/login/";
    var popup = createPopupWindow(urlToOpen, "", 450, 600);
	
    var pollTimer = window.setInterval(function() {
        if (popup.closed !== false) {
            window.clearInterval(pollTimer);
            if (discordResult !== null && gotResult) {
                document.getElementById("AngryBirdsRefresh").sendDiscordData(discordResult);
                discordResult = null;
            }
            else {
                if (gotResult) {
                    document.getElementById("AngryBirdsRefresh").sendDiscordData({"error": "Result is null"});
                }
                else {
                    document.getElementById("AngryBirdsRefresh").sendDiscordData({"error": "Didn't Log In"});
                }
            }
        }
    }, 200);
}

Relevant ActionScript 3 code:

	  private static function serverCallDiscord() : void
	  {
		 if (AngryBirdsBase.singleton.mCanvas.loaderInfo.parameters.launcherType != "AIRBIRD")
		 {
			// we're not on airbird, proceed as normal
			ExternalInterfaceHandler.performCall("discordLogIn");
			ExternalInterfaceHandler.addCallback("sendDiscordData",onDiscordGotData);
		 }
		 ...
	  }

	  private static function onDiscordGotData(response:Object) : void
	  {
		 ExternalInterfaceHandler.removeCallback("sendDiscordData",onDiscordGotData);
		 if (response.error == "Didn't Log In")
		 {
			AngryBirdsBase.singleton.popupManager.openPopup(new ErrorPopup(ErrorPopup.DIDNT_LOG_IN,"Server Error: User didn't log in."));
		 }
		 else if (response.error == "Banned")
		 {
			AngryBirdsBase.singleton.popupManager.openPopup(new ErrorPopup(ErrorPopup.BANNED,"User has been banned.", response.banReason, response.banTime));
		 }
		 else if (response.error == "Success")
		 {
			sFacebookUserId = response.userId;
			sAccessToken = response.accessToken;
			sExpiresInSeconds = response.expiresInSeconds;
			serverCallLogIn();
		 }
		 else
		 {
			AngryBirdsBase.singleton.popupManager.openPopup(new ErrorPopup(ErrorPopup.ERROR_GENERAL,"Unknown Server Error"));
		 }
	  }

(AIRBird is our Adobe AIR launcher, which uses a different way of authenticating)

@ultra0000 ultra0000 added the bug Something isn't working label Jun 30, 2024
@ultra0000
Copy link
Author

Relevant code from ExternalInterfaceHandler:

      public static function addCallback(externalMethod:String, callback:Function) : void
      {
         try
         {
            if(!externalMethods[externalMethod])
            {
               externalMethods[externalMethod] = new ExternalInterfaceMethod(externalMethod);
            }
            (externalMethods[externalMethod] as ExternalInterfaceMethod).addCallback(callback);
         }
         catch(e:Error)
         {
         }
      }
      
      public static function removeCallback(externalMethod:String, callback:Function) : void
      {
         var method:ExternalInterfaceMethod = externalMethods[externalMethod] as ExternalInterfaceMethod;
         if(method)
         {
            method.removeCallback(callback);
            if(method.callbackCount == 0)
            {
               method.dispose();
               delete externalMethods[externalMethod];
            }
         }
      }
      
      public static function performCall(call:String, ... params) : *
      {
         var logStr:String = "ExternalInterface call: " + call + "(" + params.join(", ") + ");";
         if(logStr.length > 300)
         {
            logStr = logStr.substr(0,300) + "[...]";
         }
         Log.log(logStr);
         if(ExternalInterface.available && EXTERNAL_INTERFACES_ENABLED)
         {
            try
            {
               params.unshift(call);
               return ExternalInterface.call.apply(null,params);
            }
            catch(e:Error)
            {
               Log.log("ExternalInterface call failed!\nCall was:" + call + "\nError data:" + e.toString());
            }
         }
         ...
      }

@ultra0000
Copy link
Author

ExternalInterfaceMethod:

package com.rovio.externalInterface
{
   import com.rovio.factory.Log;
   import flash.external.ExternalInterface;
   
   public class ExternalInterfaceMethod
   {
       
      
      public var externalMethodName:String = "";
      
      private var callbacks:Array = null;
      
      public function ExternalInterfaceMethod(methodName:String)
      {
         super();
         this.externalMethodName = methodName;
         if(ExternalInterface.available)
         {
            ExternalInterface.addCallback(this.externalMethodName,this.methodListener);
         }
      }
      
      public function methodListener(... args) : *
      {
         var logStr:* = null;
         var i:Number = NaN;
         var f:Function = null;
         logStr = "call through externalInterface! " + this.externalMethodName + "(";
         for(i = 0; i < args.length; i++)
         {
            logStr += args[i] + ",";
         }
         logStr += ")";
         Log.log(logStr);
         var returnValue:* = null;
         if(this.callbacks != null)
         {
            for each(f in this.callbacks)
            {
               returnValue = f.apply(null,args);
            }
         }
         return returnValue;
      }
      
      public function addCallback(callback:Function) : void
      {
         if(this.callbacks == null)
         {
            this.callbacks = new Array();
         }
         if(this.callbacks.indexOf(callback) == -1)
         {
            this.callbacks.push(callback);
         }
      }
      
      public function removeCallback(callback:Function) : void
      {
         if(this.callbacks && this.callbacks.indexOf(callback) != -1)
         {
            this.callbacks.splice(this.callbacks.indexOf(callback),1);
         }
      }
      
      public function get callbackCount() : int
      {
         if(!this.callbacks)
         {
            return 0;
         }
         return this.callbacks.length;
      }
      
      public function dispose() : void
      {
         if (ExternalInterface.available)
         {
            ExternalInterface.addCallback(this.externalMethodName,null);
         }
      }
   }
}

@sleepycatcoding
Copy link
Member

According to ExternalInterface.addCallback docs, using null closure argument on an existing callback should remove it (I haven't tested this, so it might be wrong). We currently throw on null or undefined

let method = args.get_object(activation, 1, "closure")?;

@sleepycatcoding sleepycatcoding added the avm2 AVM2 (ActionScript 3.0) issues label Jun 30, 2024
@Fancy2209
Copy link
Contributor

According to ExternalInterface.addCallback docs, using null closure argument on an existing callback should remove it (I haven't tested this, so it might be wrong). We currently throw on null or undefined

let method = args.get_object(activation, 1, "closure")?;

This game works on Flash and AIR, so the docs must be wrong.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
avm2 AVM2 (ActionScript 3.0) issues bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants