Azure AD B2C Customizing loading screen for Custom Policy - azure-ad-b2c

I'm creating a custom policy and I'm trying to customize the behavior when the policy is loading between different pages. Currently, the behavior is that the screen darkens and some text is displayed that overlaps with the rest of the UI. If possible, I'd like to display some completely different HTML content during loading. So far, I've been unable to affect the loading content in the same way that I've been able to affect the rest of the UI.
I have been able to see that a couple divs do appear during loading with IDs "simplemodal-overlap" and "simplemodal-container", and I've attempted to modify these divs using JQuery in the HTML file I've provided to Azure for the custom policy, but nothing I've done seems to have affected those divs in any way.
Has someone customized the loading UI for a custom policy before and can they give me advice on how I can affect its behavior?

Actually, the div with id: simplemodal-overlap is added/removed from HTML page by B2C dynamically:
So you can't capture it directly via JS code. If you just want to change its CSS display, you can just overwrite it on your custom page, on my side, I just use the code below to change its color to grey:
If you want to do more things on it by JS, you can add an event listener to monitor if a dom node with id simplemodal-overlap has been added into your html body. See code below:
<script>
$('body').on('DOMNodeInserted', function(e) {
if($(e.target).attr('id') == 'simplemodal-overlay'){
$(e.target).css({"background":"green","font-size":"100px"});
$(e.target).html("LOADING !!!!!")
}
});
</script>
Result:

Related

Using tabs.executeScript in iframe

I'm trying to implement an extension that can auto fill all fields in an application website. Currently it works great in main frame, but doesn't work if the fields are in a iframe.
I'm allowing users to either use content script to auto inject JS or click a button to inject JS manually.
The problem I have is my JS is not injecting into iframe even I set allFrames to true, but content script work.
"content_scripts" : [
{
"matches" : ["https://*/my_url/*"],
"js" : ["/auto_fill.js"],
"all_frames": true
}
]
This content scripts work fine, JS is being injected. However,
my_button.addEventListener('click', () => {
chrome.tabs.executeScript(null, {
file : "/auto_fill.js",
allFrames : true
})
});
This executeScript doesn't work, nothing happen.
The iframe I'm trying to work with is kinda a dynamic iframe (where I have to click few buttons to load and navigate to the application site I want)
Do I have to find out the iframe id or tab id in order for this to work, please provide some hints.
Please let me know if I'm not making myself clear.
Thank you so much for your time.
As the comments revealed, the extension is using the activeTab permission without host URL patterns (just as the documentation suggests), but this permission only grants access to the tab's main URL. When an iframe points to a different URL origin, it won't be granted by activeTab, which is an intentional restriction enforced since Chrome 45, see https://crbug.com/826433.

Kentico 11 Portal Page Template - how to set Page AsyncMode?

I have a custom webpart that is inside a Portal Page template. It needs to call an async web api method on a button click.
I know for an ASPX based template we would see the Page property like:
<%# Page Title="" Language="C#" ...... Async="true" %>
But I'm not sure if this is accessible using portal template.
If it's not possible and I have to create an ASPX template - is it possible for it to reference a portal based masterPage or would I have to pull that out into an aspx page too?
The reason I need this property set is support this code:
protected void btnProcessPayment_Click(object sender, EventArgs e)
{
Page.RegisterAsyncTask(new PageAsyncTask(ExecuteValidation));
}
private async Task ExecuteValidation()
{
I have found this to be a reliable implementation in web forms.
Although I am not sure that you can set a whole page as Async, there are other options here.
You could use Kentico's AsyncControl - this control is used throughout the admin interface for asynchronous processing
You could use Kentico's AsyncWorker - if for some reason you cannot
use the AsyncControl this can be a valid alternative
Async does not really stick well with whole webforms life cycle for controlls and callbacks can break the cycle, for example if a page is loaded. Running worker thread or AJAX calls are usually better option. Even AsyncControl is attaching to a thread at some point and leveraging it to do the job and changing its rendering based on that.
It could work as long as there are no other complex controls on the page. MVC will really help here, but that is beyond Kentico 11 and portal at this point.

Using the Existing Redirection to an External URL

How do you use redirection on Acumatica mobile xml or msdl to redirect to an external link?
All I could find is If an action on an Acumatica ERP form provides redirection to an external URL, you can map the action to use it in the mobile app. To do this, you need no additional attributes in the action object. However, the redirect attribute of the tag must be set to True, as shown in the following example.
Thanks
There may be other ways, but from the new T410 course for MSDL in 2018R2, you need to do a couple of steps. (Got this at Acumatica Summit 2018 Web Services course - Lesson 6 in the training guide which should be available soon if not already.)
First, define a new toolbar button on the form for your external link
(This example is for the SO303000 screen)
public PXAction<AR.ARInvoice> TestURL;
[PXButton(CommitChanges=true)]
[PXUIField(DisplayName = "TestURL")]
protected void testURL(){
throw new PXRedirectToUrlException(
"http://www.acumatica.com",
"Redirect:http://www.acumatica.com"
)
}
After publishing your project, go back to the Customization Project in the Mobile Application section to map the button. Add this to the commands section of the page as shown in the following example.
add container "InvoiceSummary" {
add field …
add recordAction "TestURL" {
behavior = Void
redirect = True
}
}
Not sure if this answered your question as you pretty much had the MSDL code listed, so maybe it is a matter of where you placed your code within the mobile definition? In the training class, we placed it inside the container where we wanted the link which then appears on the menu on the mobile app when viewing that container.

Optionally inject Content Script

Content Script can be injected programatically or permanently by declaring in Extension manifest file. Programatic injection require host permission, which is generally grant by browser or page action.
In my use case, I want to inject gmail, outlook.com and yahoo mail web site without user action. I can do by declaring all of them manifest, but by doing so require all data access to those account. Some use may want to grant only outlook.com, but not gmail. Programatic injection does not work because I need to know when to inject. Using tabs permission is also require another permission.
Is there any good way to optionally inject web site?
You cannot run code on a site without the appropriate permissions. Fortunately, you can add the host permissions to optional_permissions in the manifest file to declare them optional and still allow the extension to use them.
In response to a user gesture, you can use chrome.permission.request to request additional permissions. This API can only be used in extension pages (background page, popup page, options page, ...). As of Chrome 36.0.1957.0, the required user gesture also carries over from content scripts, so if you want to, you could add a click event listener from a content script and use chrome.runtime.sendMessage to send the request to the background page, which in turn calls chrome.permissions.request.
Optional code execution in tabs
After obtaining the host permissions (optional or mandatory), you have to somehow inject the content script (or CSS style) in the matching pages. There are a few options, in order of my preference:
Use the chrome.declarativeContent.RequestContentScript action to insert a content script in the page. Read the documentation if you want to learn how to use this API.
Use the webNavigation API (e.g. chrome.webNavigation.onCommitted) to detect when the user has navigated to the page, then use chrome.tabs.executeScript to insert the content script in the tab (or chrome.tabs.insertCSS to insert styles).
Use the tabs API (chrome.tabs.onUpdated) to detect that a page might have changed, and insert a content script in the page using chrome.tabs.executeScript.
I strongly recommend option 1, because it was specifically designed for this use case. Note: This API was added in Chrome 38, but only worked with optional permissions since Chrome 39. Despite the "WARNING: This action is still experimental and is not supported on stable builds of Chrome." in the documentation, the API is actually supported on stable. Initially the idea was to wait for a review before publishing the API on stable, but that review never came and so now this API has been working fine for almost two years.
The second and third options are similar. The difference between the two is that using the webNavigation API adds an additional permission warning ("Read your browsing history"). For this warning, you get an API that can efficiently filter the navigations, so the number of chrome.tabs.executeScript calls can be minimized.
If you don't want to put this extra permission warning in your permission dialog, then you could blindly try to inject on every tab. If your extension has the permission, then the injection will succeed. Otherwise, it fails. This doesn't sound very efficient, and it is not... ...on the bright side, this method does not require any additional permissions.
By using either of the latter two methods, your content script must be designed in such a way that it can handle multiple insertions (e.g. with a guard). Inserting in frames is also supported (allFrames:true), but only if your extension is allowed to access the tab's URL (or the frame's URL if frameId is set).
I advise against using declarativeContent APIs because they're deprecated and buggy with CSS, as described by the last comment on https://bugs.chromium.org/p/chromium/issues/detail?id=708115.
Use the new content script registration APIs instead. Here's what you need, in two parts:
Programmatic script injection
There's a new contentScripts.register() API which can programmatically register content scripts and they'll be loaded exactly like content_scripts defined in the manifest:
browser.contentScripts.register({
matches: ['https://your-dynamic-domain.example.com/*'],
js: [{file: 'content.js'}]
});
This API is only available in Firefox but there's a Chrome polyfill you can use. If you're using Manifest v3, there's the native chrome.scripting.registerContentScript which does the same thing but slightly differently.
Acquiring new permissions
By using chrome.permissions.request you can add new domains on which you can inject content scripts. An example would be:
// In a content script or options page
document.querySelector('button').addEventListener('click', () => {
chrome.permissions.request({
origins: ['https://your-dynamic-domain.example.com/*']
}, granted => {
if (granted) {
/* Use contentScripts.register */
}
});
});
And you'll have to add optional_permissions in your manifest.json to allow new origins to be requested:
{
"optional_permissions": [
"*://*/*"
]
}
In Manifest v3 this property was renamed to optional_host_permissions.
I also wrote some tools to further simplify this for you and for the end user, such as
webext-domain-permission-toggle and webext-dynamic-content-scripts. They will automatically register your scripts in the next browser launches and allow the user the remove the new permissions and scripts.
Since the existing answer is now a few years old, optional injection is now much easier and is described here. It says that to inject a new file conditionally, you can use the following code:
// The lines I have commented are in the documentation, but the uncommented
// lines are the important part
//chrome.runtime.onMessage.addListener((message, callback) => {
// if (message == “runContentScript”){
chrome.tabs.executeScript({
file: 'contentScript.js'
});
// }
//});
You will need the Active Tab Permission to do this.

Opening and writing to a new window from a Google Chrome extension sandbox page

(Cross posted here)
Hi,
I have a sandboxed page (specified in my manifest) which is loaded into an iframe in my extension's background page. From within my sandboxed page, I'd like to open a new window and write to it, i.e.:
var win = window.open(); win.document.write('<p&gtHello!</p>');
This works from my extension's background page and from regular web pages, but when invoked from either content scripts or my sandboxed page, the window opens, but I cannot access the win object (it's defined, but empty---console.log outputs "Window {}").
I assume this is due to same-origin policies (with every window being given a uinque-origin within the sandboxed environment). However, since the window opens an about:blank page, I'm confused why this would matter.
Is this a feature? Is there a parameter I can add to my manifest to avoid this? And does anyone know of work-arounds that don't involve using postMessage back to my background page? My ideal solution is to have my sandboxed script open a new window and interact with it directly, not with message passing.
I can provide a full example if necessary, but I'm hoping someone might just know off the top of their head. I'm running Chrome 24.0.1312.57 on Mac and 24.0.1312.68 on Ubuntu if that helps.
Thanks,
Hank
Content scripts, by definition, are part of external regular web pages you load so I'm not really sure how your script could work on a "regular web page" but not the content script. Do you mean the code works when you embed it in your own pages, but not in other pages via the content script?
Regardless, if the script is working properly from your background page, you could always try messaging. (more here: http://developer.chrome.com/extensions/messaging.html)
Script for your sandbox/contentscript:
//send message to background page
chrome.extension.sendMessage({todo: "newWindow"});
In background page:
//create a listener
chrome.extension.onMessage.addListener(
function(request, sender) {
if (request.todo === "newWindow") {
//do your stuff here
var win = window.open(); win.document.write('<p&gtHello!</p>');
}
});
Per the cross-post here, the issue is indeed that the opened window is given a unique origin. This was intentional as the members of the standards working group (SWG) felt that it would be more secure to not make an exception for about:blank pages where they inherit the sandbox's origin.
However, to get around this issue, at least for my purposes, I can use the following method. First, forget sandboxing. This workaround uses an iframe embedded in a background page with the src url set to data:text/html,.... This gives a unique origin to the iframe so it's no longer in extension space. That means eval can be used and chrome apis cannot be accessed. Unlike in a sandbox, windows opened from the iframe share that same origin as the iframe, allowing created windows to be accessed. For example:
In a background html page:
<html>
<head>
...
<script src="background.js"></script>
...
</head>
<body>
...
<iframe id="myframe"></iframe>
...
</body>
</html>
In background.js:
...
document.getElementById('myframe').setAttribute('src', 'data:text/html,'+
encodeURI('<html><head>'+
'<script src='+chrome.extension.getURL('jquery.js')+'></script>'+
'<script src='+chrome.extension.getURL('myscript.js')+'></script>'+
...
'</head><body></body></html>'
));
...
In myscript.js
jQuery(document).ready(function(){
...
// To receive messages from background.js.
window.addEventListener('message', function(e){ ... } );
// To send messages to background.js.
parent.postMessage({...}, '*');
// To open AND ACCESS a window.
var win = window.open();
win.document.write('Hello'); // Fails in sandbox, works here.
// Eval code, if you want. Can't do this from an extension
// page loaded normally unless you allow eval in your manifest.
// Here, it's okay!
eval( 'var x = window.open(); x.document.write("Hi!")' );
// No chrome apis.
chrome.log( chrome.extension ); // -> undefined
chrome.log( chrome.windows ); // -> undefined
// No direct access to background page (e.g., parent).
chrome.log( parent ); // -> Window with no properties.
...
});

Resources