Is there a way to add detailed remote crash reporting to a Flex Air application? - apache-flex

I will be releasing my Air/Flex application soon, but I am pretty sure there are a couple of bugs that may pop up on the various platforms that Air is available for. So I was wondering if there is a way to implement a mechanism, that would send an error report, logging where the error happened, to a remote server each time an app crashes? This way I might catch errors that otherwise would go unnoticed.

Global error handling is now supported in Flash 10 and AIR2. More info on that here: http://help.adobe.com/en_US/air/reference/html/flash/events/UncaughtErrorEvent.html
Using that kind of functionality to catch uncaught exceptions; you can submit the trace to some web service set up specifically to grab them. Using Google App Engine is excellent for this purpose since it already has a logging feature which grabs all kinds of meta data from the client calling the application. Also, if your logs become huge for some reason - at least you wont have to worry about storing them. Google does that for you :)
I've set up such a service as outlined below (granted it has some flaws, in particular anyone can call it and add "traces", but you could add some shared secret and post over HTTPS to have some tiny measure of security).
App Engine Logging Service
#!/usr/bin/env python
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
class MainHandler(webapp.RequestHandler):
def post(self):
import logging
if self.request.get('trace'):
logging.error(self.request.get('trace')) #Adds a row to GAE:s own logs :)
self.response.out.write('trace logged')
else:
set_status(501)
def get(self):
""" Kill this function when done testing """
test_form = """
<form action="/" method="POST">
<textarea name="trace"></textarea>
<input type="submit">
</form>"""
self.response.out.write(test_form)
def main():
application = webapp.WSGIApplication([('/', MainHandler)],
debug=False)
util.run_wsgi_app(application)
if __name__ == '__main__':
main()
I wrote a little AIR-app containing this little test function which simply POST:ed the app engine service with the parameter "trace" specified.
Posting to the logging service (ActionScript)
private function postToLogger(event:MouseEvent):void
{
var service:HTTPService = new HTTPService();
var parameters:Object = {'trace': "omg something went wrong"};
service.url = "https://YOURSUPERSIMPLELOGGINGSERVICE.APPSPOT.COM";
service.method = HTTPRequestMessage.POST_METHOD;
service.resultFormat = HTTPService.RESULT_FORMAT_E4X;
service.addEventListener("result", onSuccess);
service.addEventListener("fault", onError);
service.send(parameters);
}
And finally, this is how it looks in the logs, lots of metadata, and of the trace you caught in your AIR app.

Related

Why Isn't app.initailzation() working in my Teams Add-in OAuth flow?

I am trying to get simple auth in my Teams app working with Adobe ID (a third party Oauth provider that I use on my site).
I am following the sample here. Everything is working to authorize with the Adobe ID, but when it gets to my end authentication page like this, I get an exception thrown with the message "SDK initialization timed out." when I call await app.initialize();. The sample shown does not have the await term before app.initialize(). Is that incorrect? If I remove the await, my code later on to notify authentication of success, fails with the exception "The library has not yet been initialized".
authentication.notifySuccess("Yippee");
What do I need to do to allow app.initialize() to work?
How can the sample work if there is no await before it?
Here is the TypeScript code for my OAuth End page that is loaded after the Adobe Authentication succeeds.
import $ from "jquery";
import {app, authentication} from "#microsoft/teams-js";
startup();
async function startup(){
try{
$("#status").text("Initializing");
await app.initialize();
$("#status").text("Initialized");
console.log("notifying of success");
authentication.notifySuccess("Yippee");
}
catch(error){
handleError(error, "initializing");
}
}
function handleError(error:Error, context: string){
console.error(`💥 Error ${context}: ${error.message}`);
$("#status").text(error.message);
}
What version of the js library are you using?
There have been some changes to how app.initialize is handled depending on the version of the SDK you are using- see details here
https://learn.microsoft.com/en-us/microsoftteams/platform/tabs/how-to/using-teams-client-library?tabs=typescript%2Cmanifest-teams-toolkit#callbacks-converted-to-promises
You should be able to see this in package.json for typescript, although I think there may be other areas where you may need to update this.
Try this with the version referenced in the sample- 2.0.0 does that resolve the issue?
re: await- that just tells the application to wait until a response is returned (a success or failure) before moving on to the next line. In your case, you need the await as your next line is dependent on the value of status, but your function is async, so it won't block the execution of other async functions. You want to use await where you have other requests that must have a response on that call- like getauthtoken.

How to skip extra 'sign in with' page in Flask App Builder / Airflow

I have started using Apache Airflow (Built upon FAB) and enabled authentication through OAuth (as shown in FAB Security). I have ONLY one OAUTH_PROVIDER (azure).
FYI, Airflow version 2.1.4
When I launch my airflow home page, it used to open the direct login page of my OAUTH_PROVIDER.
NOW, the real problem started when I upgraded my airflow to 2.2.4 AND configured the same OAUTH (Azure) provider.
When I launch my airflow home page, a page coming like this
After clicking the button "Sign In with azure", the user login page comes.
Compared to the older airflow, the latest version got an extra page.
Why is matter to me?
We are rendering airflow in a web app and this extra "sign in with" page does not look good.
Please provide some info on SKIPPING that extra interaction.
After upgrading Airflow, Flask Appbuilder version was probably also bumped and that caused change in behavior. Basically:
Flask Appbuilder < 3.4.0 made it possible to have automatic sign-in when just one oauth provider was configured
Flask Appbuilder >= 3.4.0 changed the behavior and made it impossible to achieve this. This is the PR (with justification) that removed this functionality: https://github.com/dpgaspar/Flask-AppBuilder/pull/1707
If you want previous behavior to be used in your deployment, this is what most likely would work (although I didn't test it):
Prepare custom view class, let's call it CustomAuth0AuthView - it would bring back old behavior on login method. (I used v4.1.3 as reference code and modified it slightly).
webserver_config.py:
from flask_appbuilder.security.views import AuthOAuthView
class CustomAuthOAuthView(AuthOAuthView):
#expose("/login/")
#expose("/login/<provider>")
#expose("/login/<provider>/<register>")
def login(self, provider: Optional[str] = None) -> WerkzeugResponse:
log.debug("Provider: {0}".format(provider))
if g.user is not None and g.user.is_authenticated:
log.debug("Already authenticated {0}".format(g.user))
return redirect(self.appbuilder.get_url_for_index)
if provider is None:
if len(self.appbuilder.sm.oauth_providers) > 1:
return self.render_template(
self.login_template,
providers=self.appbuilder.sm.oauth_providers,
title=self.title,
appbuilder=self.appbuilder,
)
else:
provider = self.appbuilder.sm.oauth_providers[0]["name"]
log.debug("Going to call authorize for: {0}".format(provider))
state = jwt.encode(
request.args.to_dict(flat=False),
self.appbuilder.app.config["SECRET_KEY"],
algorithm="HS256",
)
try:
if provider == "twitter":
return self.appbuilder.sm.oauth_remotes[provider].authorize_redirect(
redirect_uri=url_for(
".oauth_authorized",
provider=provider,
_external=True,
state=state,
)
)
else:
return self.appbuilder.sm.oauth_remotes[provider].authorize_redirect(
redirect_uri=url_for(
".oauth_authorized", provider=provider, _external=True
),
state=state.decode("ascii") if isinstance(state, bytes) else state,
)
except Exception as e:
log.error("Error on OAuth authorize: {0}".format(e))
flash(as_unicode(self.invalid_login_message), "warning")
return redirect(self.appbuilder.get_url_for_index)
Prepare custom security manager. Let's call it CustomSecurityManager. It would use your custom view to handle login.
webserver_config.py:
from airflow.www.security import AirflowSecurityManager
class CustomSecurityManager(AirflowSecurityManager):
authoidview = CustomAuthOAuthView
Configure Airflow to use your CustomSecurityManager
webserver_config.py:
SECURITY_MANAGER_CLASS = CustomSecurityManager
More on this:
https://flask-appbuilder.readthedocs.io/en/latest/security.html#your-custom-security
https://developer.squareup.com/blog/secure-apache-airflow-using-customer-security-manager/

How to troubleshoot oAuth authentication in asp.net core Blazor App

I am trying to set up Strava authentication (which is plain oAuth2) in Asp.Net Core Blazor App.
I am rather new to Blazor & Web dev (more of a backend background), and I don't seem to find out how to troubleshoot the reason why the Authentication does not work.
When I click the oAuth login button on the Login page in the (default) Blazor Server App, I get redirected to the correct oAuth login screen (of Strava in my case), but after I successfully enter the credentials for that App, the login page shows an error Error loading external login information.
While I would obviously appreciate any help or tips that could point out what is wrong in my code, I'm mostly searching for a way to get better error information and troubleshooting capabilities here. Setting a breakpoint in the EventHandler delegates does not show much.
This is the Startup.cs extract where I have configured the authentication setup :
services.AddAuthentication().AddOAuth("Strava",
oAuthOptions =>
{
oAuthOptions.ClientId = "myappid";
oAuthOptions.ClientSecret = "myclientsecret";
oAuthOptions.Scope.Clear();
oAuthOptions.Scope.Add("read");
oAuthOptions.CallbackPath = "/profile";
oAuthOptions.AuthorizationEndpoint = "https://www.strava.com/oauth/authorize";
oAuthOptions.TokenEndpoint = "https://www.strava.com/api/v3/oauth/token";
oAuthOptions.SignInScheme = IdentityConstants.ExternalScheme;
oAuthOptions.Events = new OAuthEvents()
{
OnRemoteFailure = loginFailureHandler =>
{
Console.WriteLine("Remote Error");
Console.WriteLine(loginFailureHandler.Failure.Message);
return Task.FromResult(0);
},
OnAccessDenied = handler =>
{
Console.WriteLine(handler.Response.StatusCode);
return Task.FromResult(0);
}
};
});
An update that made things work for me, so maybe it can help other people.
I performed the following actions, in order to gain more control on the entire authentication process.
I scaffolded two pages, in which I then could debug & step through (and obviously also update and change things). More information was found in this post:
Account.Login, which enables the customization of the actual login page dotnet aspnet-codegenerator identity -dc CotacolApp.Data.ApplicationDbContext --files "Account.Login"
Account.ExternalLogin, which enables the customization of the actual strava page dotnet aspnet-codegenerator identity -dc CotacolApp.Data.ApplicationDbContext --files "Account.ExternalLogin"
I then found out that the var info = await _signInManager.GetExternalLoginInfoAsync(); always resulted in a null value. And that was because I had to set the IdentityScheme to external. ```
And after that, I had to run some custom logic to do the claim mapping. Most of those details were written down in this stackoverflow post by #Morgeh.
Hope this can help people in the future.

Qt WebView - intercept loading of JS/CSS Libraries to load local ones

I've been looking for a while through documentation to find a way to accomplish this and haven't been successful yet. The basic idea is, that I have a piece of html that I load through Qt's webview. The same content can be exported to a single html file.
This file uses Libraries such as Bootstrap and jQuery. Currently I load them through CDN which works when online just fine. However, my application also needs to run offline. So I'm looking for a way to intercept loading of the Libraries in Qt and serve a locally saved file instead. I've tried installing a https QWebEngineUrlSchemeHandler, but that never seems to trigger the requestStarted method on it.
(PyQT example follows)
QWebEngineProfile.defaultProfile().installUrlSchemeHandler(b'https', self)
If I use a different text for the scheme and embed that into the page it works, so my assumption is that it doesn't work as Qt has a default handler for it already registered. But that different scheme would fail in the file export.
Anyway, back to the core question; Is there a way to intercept loading of libraries, or to change the url scheme specifically within Qt only?
Got Further with QWebEngineUrlRequestInterceptor, now redirecting https requests to my own uri, which has a uri handler. However, the request never gets through to it, because: Redirect location 'conapp://webresource/bootstrap.min.css' has a disallowed scheme for cross-origin requests.
How do I whitelist my own conapp uri scheme?
Edit: For completeness sake, it turns out back when I originally stated the question, it was impossible to accomplish with PySide 5.11 due to bugs in it. The bug I reported back then is nowadays flagged as fixed (5.12.1 I believe) so it should now be possible to accomplish this again using Qt methods, however for my own project I'll stick to jinja for now which has become a solution for many other problems.
The following example shows how I've done it. It uses the QWebEngineUrlRequestInterceptor to redirect content to a local server.
As an example, I intercept the stacks.css for stackoverflow and make an obvious change.
import requests
import sys
import threading
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage, QWebEngineProfile
from PyQt5.QtWebEngineCore import QWebEngineUrlRequestInterceptor, QWebEngineUrlRequestInfo
from http.server import HTTPServer, SimpleHTTPRequestHandler
from socketserver import ThreadingMixIn
# Set these to the address you want your local patch server to run
HOST = '127.0.0.1'
PORT = 1235
class WebEngineUrlRequestInterceptor(QWebEngineUrlRequestInterceptor):
def patch_css(self, url):
print('patching', url)
r = requests.get(url)
new_css = r.text + '#mainbar {background-color: cyan;}' # Example of some css change
with open('local_stacks.css', 'w') as outfile:
outfile.write(new_css)
def interceptRequest(self, info: QWebEngineUrlRequestInfo):
url = info.requestUrl().url()
if url == "https://cdn.sstatic.net/Shared/stacks.css?v=596945d5421b":
self.patch_css(url)
print('Using local file for', url)
info.redirect(QtCore.QUrl('http:{}:{}/local_stacks.css'.format(HOST, PORT)))
class ThreadingHTTPServer(ThreadingMixIn, HTTPServer):
"""Threaded HTTPServer"""
app = QtWidgets.QApplication(sys.argv)
# Start up thread to server patched content
server = ThreadingHTTPServer((HOST, PORT), SimpleHTTPRequestHandler)
server_thread = threading.Thread(target=server.serve_forever)
server_thread.daemon = True
server_thread.start()
# Install an interceptor to redirect to patched content
interceptor = WebEngineUrlRequestInterceptor()
profile = QWebEngineProfile.defaultProfile()
profile.setRequestInterceptor(interceptor)
w = QWebEngineView()
w.load(QtCore.QUrl('https://stackoverflow.com'))
w.show()
app.exec_()
So, the solution I went with in the end was, first, introduce jinja templates. Then, using those the template would have variables and blocks set based on export or internal use and from there I did not need the interceptor anymore.

How do I log asynchronous thin+sinatra+rack requests?

I'm writing my first Sinatra-based web app as a frontend to another TCP-based service, using EventMachine and async_sinatra to process incoming HTTP requests asynchronously. When I'm testing my app, all requests to synchronous routes are logged to stdout in common log format, but asynchronous requests are not.
I've read through bits of the source code to async_sinatra, Sinatra, Thin, and Rack, and it looks like logging of synchronous requests is done through CommonLogger#call. However, I can't find anywhere in the asynchronous code in async_sinatra or Thin that seems to pass asynchronous requests through the logging middleware (I'm looking at Sinatra::Helpers#body in async_sinatra and at Thin::Connection.post_process which is written into env['.async_callback'] in Thin's connection.rb:68 and request.rb:132).
I'm experienced with C but relatively new to Ruby, so if I've used some terminology or notation incorrectly, please correct me. Thanks in advance.
Edit: this also affects error handling. If an exception is raised in an asynchronous request, the request is never finished and the error is never logged.
I eventually found that using rack-async with async_sinatra was causing problems with 404 pages, exception handling, and logging:
!! Unexpected error while processing request: undefined method `bytesize' for nil:NilClass
Instead I used the following wrapper around aroute for logging:
module Sinatra::Async
alias :oldaroute :aroute
def aroute verb, path, opts = {}, &block
# Based on aroute from async_sinatra
run_method = :"RunA#{verb} #{path} #{opts.hash}"
define_method run_method, &block
log_method = :"LogA#{verb} #{path} #{opts.hash}"
define_method(log_method) { |*a|
puts "#{request.ip} - #{status} #{verb} #{path}"
}
oldaroute verb, path, opts do |*a|
oldcb = request.env['async.callback']
request.env['async.callback'] = proc { |*args|
async_runner(log_method, *a)
oldcb[*args]
}
async_runner(run_method, *a)
end
end
end
This is for the same versions of async_sinatra, Thin, and Rack that I was using when I asked this question last year; newer versions may allow the use of common Rack middleware for logging.
I am running on sinatra-synchrony and therefore I have a slightly different core than you.
But basically I solved the same problem.
Here is an abstract of the solution:
I am not using Rack::CommonLogger, I use my own Logger
You need to buffer log output in an async aware storage
The buffered log output must be flushed at the end of the request
In my sinatra-synchrony application I am running the following middleware for logging:
# in app.rb I register Logger::Middleware as the first middleware
use Logger::Middleware
# in logger.rb
module Logger
attr_accessor :messages
def log(message)
stack << message
end
def stack
# This is the important async awareness
# It stores messages for each fiber separately
messages[Fiber.current.object_id] ||= []
end
def flush
STDERR.puts stack.join("\n") unless stack.empty?
messages.delete Fiber.current.object_id
end
extend self
class Middleware
def initialize(app)
#app = app
end
def call(env)
# before the request
Logger.log "#{env['REQUEST_METHOD']} #{env['REQUEST_URI']}"
result = #app.call(env)
# after the request
Logger.flush
result
end
end
end
Logger.messages = {} # initialize the message storage
Everywhere in the application I am able to use Logger.log("message") for logging.

Resources