Angular: redirecting /#%21/ to /#!/ - javascript

In emails that we send to users, we include links to Angular app like the following:
http://example.com/#!/mypage
We've noticed that some email clients or browsers, for one reason or another, upon click direct the user to this instead:
http://example.com/#%21/mypage
Angular then throws the following error:
Uncaught Error: [$location:ihshprfx] Invalid url "http://example.com/#%21/mypage", missing hash prefix "#!".
http://errors.angularjs.org/1.3.0-beta.10/$location/ihshprfx
We are using $locationProvider.hashPrefix('!');. I'm trying to find a way to detect instances where $location is /#%21/ rather than /#!/ and then redirect properly, but I can't find a way to detect and/or get Angular to do this. What is the proper way to do this?

Ended up finding a better answer here:
Adding a hash prefix at the config phase if it's missing
Using $locationChangeStart didn't work because angular threw the error during initialization, so $locationChangeStart was never tripped.
Instead, I went with the following approach:
<head>
<!-- Change #%21 to #! on first load -->
<script type="text/javascript">
var loc = window.location.href;
if (loc.indexOf('#%21') > -1 && loc.indexOf('#!') === -1 ) {
window.location.href = loc.replace("#%21", "#!");
}
</script>
<!-- More stuff ... -->
</head>
<body>...
This (a) allows me to rewrite the URL before we ever hit Angular, and (b) makes sure we only rewrite it the first time the app is loaded, rather than any time there's a location change--just in case at some point in the future we deliberately write a change that includes a #%21.

Might not be the most elegant way to go about solving your problem, but you could catch the $locationChangeStart event and then conditionally redirect the user with the $location service based on what the nature of the URL is.
For example:
$rootScope.$on('$locationChangeStart', function(event, newUrl, oldUrl) {
// ...
});

Related

How to pass variable to index.html in angular securely

i have script tags for my payment gateway in my index.html
<script type="text/javascript" src="https://app.sandbox.midtrans.com/snap/snap.js"
data-client-key="my-data-client-key">
</script>
my data-client-key is showing up in head tags, is it okay or should it be secured? if it need to be secured, how can i secure it?
i have read this post How to pass variable data to index.html in angular? but still i wonder is my key should be hidden or not.
and of course i have others key too, like analytics, can i hide it?
EDIT
i added this to my main.ts
if (environment.production) {
enableProdMode();
// HACK: Don't log to console in production environment.
// TODO: This can be done in better way using logger service and logger factory.
if (window) {
window.console.log = window.console.warn = window.console.info = function () {
// Don't log anything.
};
}
document.write('<script type="text/javascript" src="https://app.sandbox.midtrans.com/snap/snap.js" data-client-key="'+environment.midtransKey+'" ></script>');
} else {
document.write('<script type="text/javascript" src="https://app.sandbox.midtrans.com/snap/snap.js" data-client-key="'+environment.midtransKey+'" ></script>');
}
the script tag for midtrans not showing up, and i got core.js:6014 ERROR ReferenceError: snap is not defined
Once the Key is to be used in the frontend, there is no way of hiding it. Eventually, it should be in the header tag or somewhere on the page for the required processing to be done
From their documentation, this is a client Key, so there isn't much to worry about. Also Mid Trans accepts merchant Url and other callback URLs, by which they restrict payment and redirection. Assuming these are not as they say, the only thing someone can do is to execute a payment transaction on your behalf into your account.
For Google analytics, there is also not much you can do, but with this, the data you collect can be polluted if someone gets your key, So I will suggest you create a filter on your analytics page and restricting only hits that match your domain. Check out this post on how to do that.
You have two choose
Insert this script tag from angular
import { environment } from './environments/environment';
const script = document.createElement('script');
script.src = "https://app.sandbox.midtrans.com/snap/snap.js";
if (environment.production) {
script.setAttribute("data-client-key","my-data-client-key")
} else if (environment.staging) {
script.setAttribute("data-client-key","my-data-client-key")
}
document.head.appendChild(script);
Edit variable from angular by custom key
var html = document.documentElement.innerHTML
document.documentElement.innerHTML = html.replace("my-data-client-key", environment.variable)
there is no problem to show client key because the provider will restrict to use client key per domain etc....
in your case the documentation mention to put client key in html
https://snap-docs.midtrans.com/#frontend-integration

Set $location in AngularJS / Electron app

Is it possible to change the URL for $location in AngularJS within an Electon app but without implicitly loading that URL? The problem is that Electron is loading index.html (and other resources) locally, which is intended. But then of course it also sets $location to the local file system.
Background: The reason why I need $location to point to the server is that there is some existing legacy code (which I must not change) and this code uses e.g. $location.search. So after the Electron app has started I'd need to set the location correctly, so that this legacy code can work.
UPDATE 17.07.2020
Here is the requested example code:
I'm trying to set the location with window.location = "https://example.com?param1=test" so that the AngularJS function $location.search() returns param1=test. The problem is, as mentioned above, that when setting window.location, Electron loads the index.html from that server and replaces the content of the BrowserWindow. But I want to load those resources (index.html, *.js, *.css locally) I also tried:
window.location.href = ...
window.location.assign (...)
window.location.replace (...)
but all of these are reloading the page as well.
I think you'll want to add an event listener for will-navigate. Docs can be found here. The important piece:
[The will-event event will be] emitted when a user or the page wants to start navigation. It can happen when the window.location object is changed or a user clicks a link in the page.
I'd imagine your main.js file will look something like this, it's bare-bones but I hope you get the idea.
const {
app
} = require("electron");
let window;
function createWindow(){
window = new BrowserWindow(){...};
// etc....
}
app.on("ready", createWindow);
// For all BrowserWindows you make, the inner bindings will be applied to each;
// more information for "web-contents-created" is here: https://www.electronjs.org/docs/api/app#event-web-contents-created
app.on("web-contents-created", (event, contents) => {
contents.on("will-redirect", (event, navigationUrl) => {
// prevent the window from changing path via "window.location = '....'"
event.preventDefault();
return;
});
});
FYI: This event listener is mainly used for security reasons, but I don't see why you can't use it in your case.

Load scripts through all components in Angular 2

I have been using Angular 2 with AdminLTE which needs to run some scripts to load properly. So I have added them in in my .anglular-cli.json:
"scripts": [
"../node_modules/jquery/dist/jquery.min.js",
"../node_modules/bootstrap/dist/js/bootstrap.min.js",
"../node_modules/admin-lte/dist/js/adminlte.min.js",
"../node_modules/moment/min/moment.min.js"
],
Unfortunately, this does not work all time. The page loads fine the first time but when I route to another page, scripts are not reloaded for the component template.
I could not find any information about this which is very surprising for me since I thought it would be a general problem! I might be totally lost with this!
A simple solution I found was just to add a window.location.href = '...' to whatever link you are opening after login. Heres my function for the when the login button is clicked.
this.authService.authenticateMember(member).subscribe(data => {
if (data.success) {
...
window.location.href = '/'
...
} else {
...
}
}
So if you are using authentication then you can put that above code at the end of your login success response and it will refresh the page aswell as take the user to wherever they are going after a successful login.
This is not the best solution but it is the simplest one i can think of that dosent require too many changes. Hope it helps :)
You can remove and recreate your script elements in DOM every time you need, like this:
document.getElementById("myScript").remove();
var testScript = document.createElement("script");
testScript.setAttribute("id", "myScript");
testScript.setAttribute("src", "assets/js/script.js");
document.body.appendChild(myScript);
I posted a question in GitHub where I explain how to do it.

getting access token from Facebook - alloy titanium

I have built an app using titanium alloy
index.js
// Use the Alloy.Globals.Facebook namespace to make Facebook module API calls
var facebookModule = Alloy.Globals.Facebook;
//set facebook app id
facebookModule.appid = Ti.App.Properties.getString("ti.facebook.appid");
//set permissions i.e what data I want
facebookModule.permissions = ['user_friends','user_photos'];
// Do not force a facebook html popover but use the native dialog if possible
facebookModule.forceDialogAuth = false;
//invoke method onto button from module
$.fbButton.style = facebookModule.BUTTON_STYLE_WIDE;
$.index.open();
In my index.js controller I have this segment of code, it executes and I am presented with a log in screen.
I then fall into 2 problems:
1) "FB Session: Should only be used from a single thread"
2) I am unable to get the access token.
Not sure how to resolve both as the inbuilt login function has it's own event handler.
Cheers
Like you said, the inbuilt login function does have it's own handler.. so you should listen for event changes, something like this:
facebookModule.addEventListener('login', function(e) {
if (e.success) {
Ti.App.Properties.setString('face_token', facebookModule.getAccessToken());
// DO SOMETHING WITH THE TOKEN - open new window, auth the user...
}
});
If you try to get the access token BEFORE the login event is fired, you'll end up bad.
Now about the single thread thing.. I did run into this a while back.. I'm not sure exactly what I did to solve it, but I think it might be related to opening multiple windows or event allowing more than one call to the facebook API. Try to check if you are closing your windows and if the login function is being called more than once.
Let me know if that works for you. Good luck.

Get the navigating url in webview WinRt

I am injecting this JS to get the navigating url (destination) at run time. I am getting JS exceptions. What is wrong?
static String NAVIGATING_FUNCTION = "window.onbeforeunload = function(){ window.external.notify(' + location.href + ''); };";
webView.InvokeScript("eval", new String[] { NAVIGATING_FUNCTION });
Also please tell me how to cancel the navigation and return back to the previous page using this JS?
If I understand correctly, since I haven't used the WebView (yet), you want to report the current location before leaving and then cancel it?
You could try this:
window.onbeforeunload = function(){ window.external.notify(location.href); return false; };
I am not sure why you had quotes in there; location.href would be in that web view, and it would be passed as a string.
Also, take a look at the responses to this thread. One of them says:
Did you get your problem solved? In the Release Preview, you need to
add some code that looks like this:
List<Uri> allowedUris = new List<Uri>();
allowedUris.Add(e.Uri);
allowedUris.Add(new Uri("http://www.bing.com"));
Browser.AllowedScriptNotifyUris = allowedUris;
Another thing, this thread: Can I get the current HTML or Uri for the Metro WebView control?, talks about the LoadCompleted event handler.
See if that helps.

Categories

Resources