I want to intercept POST requests from a custom page, which is impossible from the callback client interface (unlike to GET one, you have no access to the POST request body). So, I have implemented a service worker based solution, which wrapping POST request into a GET one with the same data, that I can handle in shouldInterceptRequest().
So, once the service worker is registered and active:
function subscribeToSWMessages()
{
navigator.serviceWorker.onmessage = function (event)
{
if (event.data.command == 'activeSW')
{
// !! Only from now we can post requests !!
}
};
}
Only after that it's safe to post request from the page. So, how to properly inject my JS code, to be sure no requests are posted until the message is received? Can the page be totally custom, or I should ask its developer to do something on their side?
Related
I have an issue with react-native-firebase (or firebase) in which my app does not receive a trigger after the auth token refreshes. It's pretty much the same issue as [1], but they never posted a solution.
So, what happens is that both on an Android phone and on the Android emulator (no idea about iOS), signing up, logging in and logging out works perfectly, meaning the listeners correctly see when I do a logout() etc. But the listeners never fire when the token refreshes.
My first question is: Am I correct to assume that the onIdTokenChanged-listener should automatically fire after 60 minutes without having to do anything else, e.g. call any firebase function, such that the app just sits there doing nothing for 60 minutes and then receiving the event and replacing the token?
My main component which contains the listeners looks like this:
class ReduxAppWrapper extends Component {
componentDidMount() {
firebase.auth().onAuthStateChanged((user) => {
console.log('COMP DID MOUNT: AUTH STATE CHANGED! ' + JSON.stringify(user));
});
firebase.auth().onIdTokenChanged((user) => {
console.log('COMP DID MOUNT: TOKEN CHANGED! ' + JSON.stringify(user));
});
firebase.auth().onUserChanged((user) => {
console.log('COMP DID MOUNT: USER CHANGED! ' + JSON.stringify(user));
});
};
render() {
return (
<ReduxProvider store={store}>
<MenuProvider>
<PaperProvider>
<AppContainer />
</PaperProvider>
</MenuProvider>
</ReduxProvider>);
}
}
Normally inside the listener I have a function that dispatches a redux-action such that the authentication information is broadcast across my components. Inside those components I use the jwt token for http-requests to my backend.
Now the backend of course uses firebase to validate that token (and this is where the problem occurs after the 60 minutes since it retrieves an outdated jwt), but I think I am right to assume that the problem lies within the app since the refresh does not happen.
I'd be really glad if someone could point me to where to look, I also tried to find out in the firebase console whether a token refresh event was sent, but I could not find anything about that.
So basically:
1) Am I right to assume that the firebase.auth().onIdTokenChanged() function should be called without me doing anything else? Or is it not enough to define the listener once in the main component (also regarding the fact that other screens will be rendered on top of that due to the stack-nvigation).
2) If the code is fine, do you have any hints for where to look?
Thanks so much!
[1] https://github.com/invertase/react-native-firebase/issues/531
For anyone with the same issue, I ended up asking firebase asking for the token everytime I needed it. I still think this should not be necessary but I did not want to spend any more time analyzing why the refresh did not work automatically. So what I am doing in the app is
firebase.auth().currentUser.getIdToken().then((token) => {
fetch(url, {
method: 'GET',
headers: { Authorization: token }
})
}
¯\_(ツ)_/¯
Apparently, with getIdToken, Firebase only makes a call to its server to get a new token if the current token has expired; it does not create unnecessary requests if it does not have to.
Quite a crucial detail which can be confusing if you are not aware of it and makes you (rightfully) assume that onIdTokenChanged is a listener which you would need to use to automatically update the token ...
https://firebase.google.com/docs/reference/js/firebase.User.html#getidtoken
Returns the current token if it has not expired. Otherwise, this will refresh the token and return a new one.
I understand the flow to use OAuth2 is:
after the short-lived access token expires (server returning 401), the client has to request a new one using the refresh token.
To implement it in an iOS (with AFNetworking) or Android (with Volley) app, I imagine the network manager has to be able to detect returned 401 error and then send request to the auth server.
The problem is with the concurrent usage of the network. Consider the scenario where the access has expired, the app sends 2 requests: req1 and after 100ms, req2. Drawn on a timeline, this looks like:
req1 --> 401 --> (refresh req) --> OK, new access and fresh tokens --> retry req1
req2 --> 401 --> (refresh req) --> 403, wrong refresh token
The final result is req2 will fail and the app logs user out because of the 403 error.
So my questions are
is this implementation heading towards a right direction? Or it's wrong to refresh after receiving 401? Should I instead refresh the token when the user starts the app (at the cost of slowing down app launch)
How can I solve the concurrency issue?
Since you have an existing token manager, I would add some extra logic into it (in Java):
class TokenManager {
private String accessToken;
private CompletableFuture<String> accessTokenRefreshComletableFuture;
public CompletableFuture<String> getAccessToken() {
if (this.accessToken is expired) {
// If refreshed accessToken is being requested
CompletableFuture<String> runningRequestFuture = this.accessTokenRefreshComletableFuture;
if (runningRequestFuture == null) {
// For thread safety, this assignment should be synchronized (or made atomic)
// with the previous reading
this.accessTokenRefreshComletableFuture = new CompletableFuture<>();
// Request a fresh access token.
// When you get a new access token, set the this.accessTokenRefreshComletableFuture
// complete and remove its reference from the manager class.
}
return runningRequestFuture;
}
// Synchronous result
return CompletableFuture.completedFuture(this.accessToken);
}
}
The manager doesn't return an access token, but a CompletableFuture (Promise in JavaScript - asynchronous result). If the access token needs to be refreshed, check first whether the /token endpoint request is already running. If it is, return it's CompletableFuture.
This way, you would always have either a valid access token or a single CompletableFuture waiting for a new access token.
I am working on voice calling app which is built in java and I need to know the call status when it is picked , rejected or complated.My server end is in java.
I set status callback url while placing a call as mention in the twilio docs. My question which url is to added in that code and do i need to add the funtion for that end point url also.
And what should be the code in that funtion like what are the parameters as I need to print the call status
com.twilio.type.Client clientEndpoint = new com.twilio.type.Client("client:" + to);
PhoneNumber from = new PhoneNumber(CALLER_ID);
// Make the call
Call call = Call.creator(clientEndpoint, from, uri).setMethod(HttpMethod.POST)
.setStatusCallbackMethod(HttpMethod.POST)
.setStatusCallback(URI.create("https://57fb8b2c.ngrok.io/events"))
.setStatusCallbackEvent(
Arrays.asList(Call.Event.ANSWERED.toString(), Call.Event.COMPLETED.toString(),
Call.Event.INITIATED.toString(), Call.Event.RINGING.toString()))
.create(client);
// Print the call SID (a 32 digit hex like CA123..)
System.out.println(call.getSid() + "//" + call.getStatus());
return call.getSid();
Twilio developer evangelist here.
I'm not particularly good at Java, but I can help with what happens when you set a statusCallback URL.
For each of the events you set as the statusCallbackEvent you will receive an HTTP request to your statusCallback URL when the call enters that state.
You will need to implement an endpoint (in your case, at the path /events as that's the URL you are setting) that can receive these incoming HTTP requests.
When Twilio makes the status callback request it includes all the regular webhook parameters, such as CallSid so you can tie the request to the known call sid.
The request will also include some other parameters, most importantly in your case the CallStatus parameter. The value will be one of queued, initiated, ringing, in-progress, busy, failed, or no-answer. There's more on what they mean here.
I hope that helps a bit.
I am using mockwebserver to mock request and response for my android app. I am testing a login feature which goes through a series of 4 service calls.
Get access token
Re-direct
Get user info (different base url)
Get some other stuff (original base url)
I am trying to mock the response of the redirected call. Here is my code:
#Test
public void testSuccessfulLogin() throws Exception {
// Post
server.enqueue(new MockResponse()
.setResponseCode(HTTP_OK)
.setBody(getStringFromFile(getInstrumentation().getContext(), "access_token.json")));
// Redirect
server.enqueue(new MockResponse().setResponseCode(HTTP_MOVED_TEMP));
// GET user info
server.enqueue(new MockResponse().setResponseCode(HTTP_OK).setBody(getStringFromFile(getInstrumentation().getContext(), "userinfo.json")));
// GET some other stuff
server.enqueue(new MockResponse().setResponseCode(HTTP_OK)
.setBody(getStringFromFile(getInstrumentation().getContext(), "sts.json")));
// Init call
loginWithoutWaiting(Data.serviceLoginUsername, Data.serviceLoginPassword);
// Debug (need to loop 4 times to get all 4 call paths)
RecordedRequest request = server.takeRequest();
request.getPath();
}
My test fails at the Redirect code. I cannot login. I have found some hints here but I do not fully understand what is going on, thus can't make it work at the moment.
It turned out to be quite easy. In the call that makes redirect, create a new mocked response with response code 302 and header with location url. The next call will use that location url.
case "/userinfo":
return new MockResponse().setResponseCode(HTTP_MOVED_TEMP).setHeader("Location", "/api-test.com/users");
case "/api-test.com/users":
return new MockResponse().setBody("{}")).setResponseCode(HTTP_OK);
I am new to sencha touch and i want to consume soap web service in sencha touch.I have written code for this cause, but the problem is that I am getting just plain HTML content as response not the soap object. And I dont know how to call a specific method from web service to sencha touch.
Here's my code :-
Ext.Ajax.request({
method: 'get',
url: 'http://192.168.1.15:80/himanshu/helloworldwebservice.asmx',
success: function (response, request) {
alert('Working!')
alert(response.responseText)
console.log('Response:-'+response.responseText)
},
failure: function (response, request) {
alert('Not working!')
console.log('Response Status:- '+response.status)
}
});
EDIT:- Ok i got the idea to call a specific method from web service from here.Like i have HelloWorld() method which only returns a single string and my url is http://192.168.1.15:80/himanshu/helloworldwebservice.asmx.
I can call HelloWorld() method by setting my url like this :- http://192.168.1.15:80/himanshu/helloworldwebservice.asmx/HelloWorld
But its not working for me.Every time i run the program 'Not Working' alert generates and 500 is the response stats i gets.Please make me understand that how can i call methods from webservice.Thanx in advance.
You will not be able to consume your SOAP webservice in this way, since performing a GET request on the asmx url will just return you the HTML content for the page listing your webservice methods.
Consuming SOAP webservices relies on POST requests and need that you send a correct XML SOAP request. I may suggest you to use something like http://archive.plugins.jquery.com/project/jqSOAPClient to execute your SOAP calls and retrieve your data and then pass them back to your Ext code.
Hope this helps
Nacef
Your code is absolutely fine. I think you are sending HTML data from the server side. Do check the response in Chrome/Safari Developer Tools. Also, use console.log() function instead of alert() function for a better view.
Also, open this url: "http://192.168.1.15:80/himanshu/helloworldwebservice.asmx" in browser and "View source" of the page - you will see what exactly you are sending.
You can make use of : SOAP Data Proxy
http://www.sencha.com/blog/taking-a-look-at-the-new-sencha-soap-data-proxy