How to call external rest service from angularjs? - http

I am trying to call an external REST service from angular using $http service.
The thing is that I am stuck on the $http.get method, because everytime I call the rest service i get an error with status = 0 and no information in the data parameter of the error callback.So far I've tried calling a local service runnig on port 5000 : $http.get('http://localhost:5000/ping') and this is supposed to return a json object with a property and a value. Another approach was calling http://api.flickr.com/services/rest/?method=flickr.test.echo&name=test in the hope of getting an answer. For both of them I get the same error: that I mentioned earlier.The call is made from an angular controller that has injected the http service.Thanks.

Have you tried:
$http({method: 'GET', url: 'someURL'}).
success(function(data, status, headers, config) {
//set view model or do something.
}).
error(function(data, status, headers, config) {
});

Make sure that you have passed the parameters correctly if there are any.
The general syntax should be like the following :
$http.get('../link/yourApplication/searchBySomeNumber?someNum='+$scope.someNum+'&asOfDate='+asOfDate+'&status=undefined')
.success(function(data, status, headers, config) {
//your code
console.log('Data return successful');
})
.error(function(data, status, headers, config) {
$scope.status = status;
alert('Info Error');
console.log('Group Info Error');
});

As $http returns a Promise, you can use the .then() method to log your results when the promise is resolved, or log an error in case anything goes wrong:
$http.get('http://localhost:5000/ping')
.then(function(returnedJson) {
console.log(returnedJson.data);
})
.catch(console.error) // or $log.error if you are using $log from Angular
Please note that the clean JSON response is obtained by logging the .data property of the returnedJson object. As it is a Promise, it contains other information that are not relevant to consume the web service.
Also note that the web service you want to consume should also be in the same domain as your Angular app, otherwise you may incur into a Cross Domain error, unless the service allows usage from external websites by exposing a Cross Domain Policy.
(Find more info here: Can someone post a well formed crossdomain.xml sample?)
If that's the case, this post should be helpful:
jQuery AJAX cross domain
Hope this helps.

Related

intercept firebase-functions response (middleware)

For my Google Assistant/Dialogflow project, I am trying to intercept every response my firebase-functions endpoint is sending back to Dialogflow. I can easily intercept the request, but the response gets built within several functions (one function for every Intent), and I don't want to include an interceptor in every function.
Is it possible to have a middleware or is there a callback provided when a response is send out, sort of a global interceptor for every response?
I have found the following in the Docs: https://firebase.google.com/docs/functions/http-events#use_middleware_modules_with
However, I am unsure where this goes. Note that I am not using a custom express setup, but I am using the native implementation on firebase directly.
serialize() method is called on conversation right before the response is sent back, so what you can do is to extend the conversation object(based on the library you are using) and overwrite the serialize method to do whatever you need to do. don't forget to call the original serialize method and return the value in your new method.
Since you are using Dialog Flow with Firebase for your fulfilment, I am expecting you are also using actions-on-google package.
serialize() is a function which is called to generate the response. You can override this function and intercept the request and response. Try this code and thank me later. 😉
app.middleware((conv) => {
const serializeCopy = conv.serialize;
conv.serialize = () => {
const response = serializeCopy.call(conv);
console.log(conv.request, response);
return response;
};
});
Cloud Functions does not expose any sort of middleware or interceptors for HTTP requests or responses. You will have to build something yourself, probably with an Express app that you build yourself. You can host an Express app on Cloud Functions.
I wanted something similar to intercept all conversations back and forth for logging purposes. I ended up writing a function that I use to send a conversation. For eg:
const intercept = (conv, sentence) => {
//My Interceptor code
conv.ask(sentence)
}
Now anytime I want to send a response, I would use:
intercept(conv, "Speak this")

The anti-forgery cookie token and form field token do not match when using WebApi

I have a single-page app (user loads a bunch of HTML/JS and then makes AJAX requests without another call to MVC - only via WebAPI). In WebAPI I have the following:
public sealed class WebApiValidateAntiForgeryTokenAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(
System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (actionContext == null)
{
throw new ArgumentNullException(nameof(actionContext));
}
if (actionContext.Request.Method.Method == "POST")
{
string requestUri = actionContext.Request.RequestUri.AbsoluteUri.ToLower();
if (uriExclusions.All(s => !requestUri.Contains(s, StringComparison.OrdinalIgnoreCase))) // place some exclusions here if needed
{
HttpRequestHeaders headers = actionContext.Request.Headers;
CookieState tokenCookie = headers
.GetCookies()
.Select(c => c[AntiForgeryConfig.CookieName]) // __RequestVerificationToken
.FirstOrDefault();
string tokenHeader = string.Empty;
if (headers.Contains("X-XSRF-Token"))
{
tokenHeader = headers.GetValues("X-XSRF-Token").FirstOrDefault();
}
AntiForgery.Validate(!string.IsNullOrEmpty(tokenCookie?.Value) ? tokenCookie.Value : null, tokenHeader);
}
}
base.OnActionExecuting(actionContext); // this is where it throws
}
}
Registered in Global.asax:
private static void RegisterWebApiFilters(HttpFilterCollection filters)
{
filters.Add(new WebApiValidateAntiForgeryTokenAttribute());
filters.Add(new AddCustomHeaderFilter());
}
Occasionally, I see the The anti-forgery cookie token and form field token do not match error in my logs. When this is happening, both tokenCookie.value and tokenHeader are not null.
Clientside, all of my AJAX requests use the following:
beforeSend: function (request) {
request.setRequestHeader("X-XSRF-Token", $('input[name="__RequestVerificationToken"]').attr("value"););
},
With Razor generating the token once on my SPA page:
#Html.AntiForgeryToken()
I have my machine key set in Web.config.
What could be causing this?
Update
I just checked logs and I'm seeing this sometimes as well:
The provided anti-forgery token was meant for user "", but the current user is "someuser#domain.com". a few seconds ago
This occurs when a user refreshes their instance of the SPA while logged in. The SPA then drops them into the landing page instead of the inner page for some reason (User.Identity.IsAuthenticated is true) - then they can't log in because of this error. Refreshing pulls them back inside. Not sure what this means, but I figured more info can't hurt.
Appendix
https://security.stackexchange.com/questions/167064/is-csrf-protection-useless-with-ajax/167076#167076
My answer will recommend to not try to use CSRF protections based on tokens in AJAX calls, but rather to rely on the native CORS features of the web browser.
Basically, any AJAX call from the browser to the back-end server will check for the domain origin (aka the domain where the script was loaded from). If the domains match (JS hosting domain == target AJAX server domain) the AJAX calls performs fine, otherwise returns null.
If an attacker tries to host a malicious AJAX query on his own server it will fail if your back-end server has no CORS policy allowing him to do so (which is the case by default).
So, natively, CSRF protections are useless in AJAX calls, and you can lower your technical debt by simply not trying to handle that.
More info on CORS - Mozilla Foundation
Code example - use your console inspector!
<html>
<script>
function reqListener () {
console.log(this.responseText);
}
var oReq = new XMLHttpRequest();
oReq.addEventListener("load", reqListener);
oReq.open("GET", "http://www.reuters.com/");
oReq.send();
</script>
</html>
Run it and look at the Security error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at http://www.reuters.com/. (Reason: CORS header
‘Access-Control-Allow-Origin’ missing).
Mozilla is pretty clear regarding the Cross-site XMLHttpRequest implementation:
Modern browsers support cross-site requests by implementing the Web
Applications (WebApps) Working Group's Access Control for Cross-Site
Requests standard.
As long as the server is configured to allow requests from your web
application's origin, XMLHttpRequest will work. Otherwise, an
INVALID_ACCESS_ERR exception is thrown.
I try to give an answer the same, also if in the comments we exchange, yours it seems a not related scenario with mine..
A such type of issue can be due to the XMLHttpRequest.setRequestHeader() behaviour, because this function "combines" the values of an header that has been already assigned in the context of an http request, as stated by MDN and Whatwg:
If this method is called several times with the same header, the
values are merged into one single request header.
So, if we have a SPA for example that executes all ajax POSTs setting a given http header, in your case:
beforeSend: function (request) {
request.setRequestHeader("X-XSRF-Token", $('input[name="__RequestVerificationToken"]').attr("value"););
}
the first ajax POST request sets a clear header ("X-XSRF-Token") and so, server side, you should have a "valid" header value to compare to.
But, in absence of a page refresh, or a new GET request, all subsequent ajax POSTs, as well as stated in the MDN and Whatwg documentation, will make a dirty assignment of the same header ("X-XSRF-Token"), because they combine the new values with the olds.
To avoid this issue, you could try to reset "X-XSRF-Token" value (but there isn't much documentation on that and it seems a not reliable solution...)
beforeSend: function (request) {
request.setRequestHeader("X-XSRF-Token", null); //depends on user agents..
//OR.. request.setRequestHeader("X-XSRF-Token", ''); //other user agents..
//OR.. request.setRequestHeader("X-XSRF-Token"); //other user agents..
request.setRequestHeader("X-XSRF-Token", $('input[name="__RequestVerificationToken"]').attr("value"););
}
Other solutions can rely on some client-side state handing mechanism that you have to implement on your own, because it is not possible to get values or state access of the http request headers (only response headers can be accessed).
Update - revision of the following text:
So, if we have a SPA for example that executes all ajax POSTs recycling the XMLHttpRequest object for each calling and setting a given http header, in your case:
...

Router.current().route.getName() is returning an error server side

Router.current().route.getName() is returning an error when I use it in a method call (server side method). I thought they say Iron-Router is supposed to work both client and server side. The error I get is
Error invoking Method 'mySeverSideMethod': Internal server error [500]
Please help.
You are half way right, the router works on both client and server. However the server-side implementation is meant for server side routes (eg. REST endpoints). There is no "state" sharing between client/server with iron:router (when invoked inside methods), so Router.current().route.getName() is going to throw you this error, because Router.current() is undefined.
Yes, iron:router can create server side routes, but that api is client only
From the docs:
Router.route('/download/:file', function () {
// NodeJS request object
var request = this.request;
// NodeJS response object
var response = this.response;
this.response.end('file download content\n');
}, {where: 'server'});
You have access to the NodeJS request object so you should be able to find what you need there, e.g. this.request.route, this.request.path.
When calling a Method, you're not going through a 'route' as defined by Iron-Router: it's a route defined by the Meteor framework. It does not care what route the client is on.
So, if you need to know from what page the client is calling the endpoint, you should pass it as a parameter to the Method.
Meteor.methods({
"myEndPoint": function(route) {
// use route here.
return //something
}
})

Durandal and ASP.Net - Interrupting the routing

I am using Durandal in an asp.net application which is all working well. What I would like to achieve is to put something into the routing of it so if required I can stop the current route and redirect.
The reason for this is I want to permission base some routes where the permissions are stored in a database. So during the routing I want to check the route, use web api accordingly to check if they have access to that route and redirect if so OR use a method on the viewmodel to check this and redirect accordingly. I do use the activate function on the viewmodel, I wondered if the route can be redirected here perhaps?
Has anyone done this before?
EDIT:
Following the great answer below the following is the code I eventually used on a test route to get this working. The web api function HasAccessToRoute part returns a bool:
define(['durandal/http', 'plugins/router', 'knockout', 'durandal/app'], function (http, router, ko, app) {
function viewModel() {
var self = this;
self.canActivate = function () {
return http.ajaxRequest("get", "/api/route/hasaccesstoroute?route=test")
.done(function (result) {
if (!result) {
app.showMessage("Test area cannot be accessed");
}
});
};
}
var model = new viewModel();
return model;
});
Yes, it is possible. Take a look at canActivate here. You can return a promise in your canActivate handler and fetch your authorization profiles asynchronously. Once you have the authorization profile, you can then resolve your canActivate with either true or false, accordingly. This is what we do.
Also, the routes in Durandal are client-side, not server-side. Or are you doing server-side rendering with, say, Razor? If not, then the only time you would be going out to the server, essentially, is to obtain data, usually through a RESTful Web API (although you can do this with action-based routes as well).
This is an important point since canActivate is a client-side handler.

Performing redirects in ServiceStack

I'm attempting to build a service in ServiceStack whose sole responsibility will be to interpret requests, and send a redirect response. Something like this:
[Route("/redirect/", "POST")
public class Redirect : IReturnVoid
{
public string Something { get; set; }
}
public class RedirectService : Service
{
public object Post(Redirect req)
{
// make some decisions about stuff
return new HttpResult(){ StatusCode = HttpStatusCode.Redirect, Headers = {{HttpHeaders.Location, "place"}}};
}
}
I did initial testing using fiddler, setting a content-type of application/json and creating an appropriate request body.This did exactly as expected: the service request gave a 302 response and redirected to the expected location.
I've also tested this by using a basic Html form post, with an action of http://myserviceuri/redirect/, which also works as expected and redirects appropriately.
However, i've hit an issue when attempting to use the SS c# client to call the same service. If I call the following code in an aspx code behind or an mvc controller
var client = new JsonServiceClient("uri);
client.post(new Redirect{Something = "something});
I get a 500 and the error message:
The remote certificate is invalid according to the validation procedure.
Which makes sense as it's a development server, with a self-cert. But I get the feeling that, as I can call the service successfully by other means, that this is a red herring.
Should I be using a different type of c# client to make the request, or setting any more custom headers, or something else? Am I fundamentally not understanding what i'm trying to do?
Please let me know if more info is needed. Thanks.
What's happening here is that the JsonServiceClient is happily following the redirect, doing more than what you've expected it to do.
I'll reference a related question and answer for posterity ( - hopefully you've resolved this issue a long time ago...).
POST to ServiceStack Service and retrieve Location Header
Essentially you'd use .net's WebRequest or the ServiceStack extensions mentioned in the answer to see the redirect and act as you see fit.

Resources