I try to develop my new app with Ionic2. In this context, the user should be authenticated with a pre shared token which will be sent to the api (http request). As a response he get an access token with which he can use further api functions.
The problem is that when I send an HTTP request, I get as an error:
{"_body":{"isTrusted":true},"status":200,"statusText":"Ok","headers":{},"type":3,"url":null}
In my desktop version everything works fine, but on Android I get this error. I still googled this error and I guess that the http request comes in conflict with other observables (Form observable).
I would be very pleased if someone could help me to avoid this "error".
As a small hint: {"isTrusted":true} is the value of the event value of the method handleSubmit. Thank you :-)
Solution:
This error was thrown because the api was not reachable (in my case due to a certificate error). When you have the same error:
Check if type="3", then it is possible that your http target is also not reachable.
My template:
<ion-content padding class="token-auth">
<form [ngFormModel]="authForm" (submit)="handleSubmit($event)">
<ion-item>
<ion-label floating>Device-ID</ion-label>
<ion-input (keyup)="onKeyUp($event)" [ngFormControl]="token" type="text"></ion-input>
</ion-item>
<div *ngIf="error !== null"
class="error-box">
{{error.message}}
</div>
<button block type="submit" [disabled]="!authForm.valid">
Register device
</button>
</form>
</ion-content>
Page source:
handleSubmit(event) : void {
this.tokenService.sendAccessTokenRequest(this.authForm.value.token, (err, code) => {
this.error = {
code : code,
message : err
};
}, (accessToken, refreshToken, validTill) => {
this.error = null;
});
}
TokenService:
/**
*
* #param token
* #param errCallback : (message : string, code : number) => any
* #param callback : (accessToken : string, refreshToken : string, validTill : string) => any
*/
public sendAccessTokenRequest(token : string, errCallback, callback) {
if (typeof token === 'undefined') {
throw 'Token value must be set. ';
}
if (typeof errCallback === 'undefined') {
errCallback = (code, message) => null;
}
if (typeof callback === 'undefined') {
callback = (accessToken, refreshToken, validTill) => null;
}
console.log(`Should send token: ${token}`);
this.sendPost(`/auth/login`, `application=XXX&device_token=${token}`)
.subscribe(res => {
console.log("Device verified: "+JSON.stringify(res));
let {
access_token,
refresh_token,
valid_till
} = res.data.token;
this._saveTokenData(access_token, refresh_token, new Date(valid_till));
callback(access_token, refresh_token, valid_till);
},
err => {
// error is here!
if (err && err._body) {
console.log("ERROR: "+JSON.stringify(err));
try {
let bodyData = JSON.parse(err._body);
let responseData = bodyData["data"];
let token:MessageResponse = responseData.token;
if (token && typeof token.code !== 'undefined' && typeof token.userMessage !== 'undefined') {
errCallback(token.userMessage, token.code);
} else {
errCallback(bodyData);
}
} catch (e) {
errCallback(e);
}
}
},
() => console.log("access token request successful")
);
}
// just an excerpt from other url
sendPost(link : string, params : string, header : Object = {}) {
console.log("SEND POST");
link = this._enforceSlashAtStringStart(link);
return this.http.post(`${this.base_url}${link}`, params, {
headers : this._mergeHeader(this.getHeader(), header)
}).map(res => { console.log("Start mapping! "); return res.json(); });
}
// EDIT: added function _saveTokenData
private _saveTokenData(accessToken : string, refreshToken : string, validTill : Date) {
if (!accessToken || !refreshToken || !validTill) {
throw new Error('access token data can not be null or undefined! ');
}
console.log("TOKEN SAVED!");
this._accessToken = accessToken;
this._refreshToken = refreshToken;
this._validTill = validTill;
// this._storage = new Storage(LocalStorage);
this._storage.set(TOKEN_STORAGE_KEY, JSON.stringify({
access_token : accessToken,
refresh_token : refreshToken,
valid_till : validTill.toString()
}));
}
And last but not least the logs:
14 256534 log Should send token: XXXXXXXXXXXXXX
15 256548 log SEND POST
16 256750 log ERROR: {"_body":{"isTrusted":true},"status":200,"statusText":"Ok","headers":{},"type":3,"url":null}
Remove the webkit plugin from ios project and it will start working.
Related
Take a look at the code below. This is server-side. I call the Google ReCaptcha API with bad secret key and bad user token response, as you can see. You know what? It works! More precisely: Google ReCaptcha API doesn't answer with exception (i.e.: my catch isn't reached). Why? This is not the expected behavior, right?
/**
* Verifies a Recaptcha filled by the user in his Android app.
* 1. Success: returns the JSON response
* 2. Failure: throws the error
**/
exports.verifyRecaptcha = functions.https.onCall((data, context) => {
const user_response_token = data.userResponseToken;
if(user_response_token === null || user_response_token === '') {
throw new functions.https.HttpsError('invalid-argument', 'The function must be called with an adequat user response token.');
}
const remote_url = 'https://recaptcha.google.com/recaptcha/api/siteverify';
const secret = '<MY_REAL_SECRET_KEY>'; // Original value: 'https://www.google.com/recaptcha/api/siteverify'; # Moises' value: https://recaptcha.google.com/recaptcha/api/siteverify
var options = {
method: 'POST',
uri: remote_url,
body: {secret: 'Foo', response: 'Bar'},
// body: {secret: secret, response: user_response_token},
json: true
};
return rp(options)
.then(parsedBody => {
return {code: 'Success', message: 'You are actually a human (this msg is for test purposes).'};
})
.catch(error => {
throw new functions.https.HttpsError('unknown', error);
});
});
And below is the Android app code:
final SafetyNetApi.RecaptchaTokenResponse response = task.getResult();
assert response != null;
final String userResponseToken = response.getTokenResult();
if (!userResponseToken.isEmpty()) {
final HashMap<String, String> the_data = new HashMap<>();
the_data.put("userResponseToken", userResponseToken);
FirebaseFunctions.getInstance()
.getHttpsCallable("verifyRecaptcha")
.call(the_data)
.continueWith(new Continuation<HttpsCallableResult, Void>() {
#Override
public Void then(#NonNull final Task<HttpsCallableResult> task) {
if(context.isDestroyed() || context.isFinishing()) {
return null;
}
if(!task.isSuccessful()) {
Exception e = task.getException();
if (e instanceof FirebaseFunctionsException) {
FirebaseFunctionsException ffe = (FirebaseFunctionsException) e;
System.out.println(ffe.getMessage());
}
return null;
}
callback.onAsking();
return null;
}
});
} else {
callback.onFailureUserResponseTokenIsEmpty();
}
The docs suggest that errors such as invalid-input-secret/invalid-input-response will appear in the error-codes field of the response.
This information doesn't necessarily need to be translated into an HTTP error code (which would cause your catch block to execute); in this instance, Google apparently wanted to support multiple simultaneous error messages, and the HTTP response code pertains more to the conduct of the protocol at the HTTP level.
While we're looking at the docs, I should point out that you probably want to refer to the success field before presuming that your user is a human.
I have written an API call in nodejs where a user can delete his account:
router.delete('/deleteAccount', checkAccessToken, (req, res, next) => {
User.find({ username: req.tokenData.username })
.exec()
.then(user => {
if (user.length < 1) {
return res.status(404).json({
message: 'Username does not exist'
});
}
User.deleteOne({ username: req.tokenData.username }, function (err, res) {
if (err) throw err;
});
UserSprint.deleteMany({ username: req.tokenData.username }, function (err, res) {
if (err) throw err;
});
return res.status(200).json({
message: "Successfully deleted"
});
});
});
This call works perfectly fine when tested with Postman and locally, but after deploying the API to my Heroku Instance the call returns 415 Unsupported Media Type
My call in Android:
#DELETE("user/deleteAccount")
fun deleteAccount(#Header(value = "authorization") authorization: String): Observable<Response<String>>
This is how I build my request
val request = original.newBuilder()
.header("Content-Type", "application/json;charset=utf8")
.header("Accept", "application/json;charset=utf-8")
.method(original.method, original.body)
.build()
The charset defined in Content-Type is not right. Here's the list of all valid charset values.
For UTF-8, change the header to: application/json;charset=utf-8.
I ran into a bug whenever I run my React Native app on an Android device (physical and emulator). Yet, no problem at all on iOS. These functions are supposed to scan the database table for user handles and return an object if the handle already exists.
This is what the error looks like:
TypeError: Cannot read property 'handle' of null
at exports.handler (/var/task/index.js:7:36)
I'm using React Native, AWS Lambda, and EXPO.
This code lives within dbfunctions.js on the front end.
export async function scanHandles(){
return new Promise((resolve, reject) => {
let { auth } = store.getState()
let reqBody = {
userId: auth.user.username,
handle: auth.handle_update,
}
let path = '/u/scan-handle'
let myInit = {
headers: { 'Content-Type': 'application/json' },
body: reqBody,
}
console.log('myInit', myInit)
console.log('handle', auth.handle_update)
API.get(apiName, path, myInit)
.then((resp) => {
// if false, then handle does not exist
// if true, then handle already exists
resolve(resp)
})
.catch((error) => {
console.warn('Scan Handle', error)
reject(error)
})
})
}
Console logging auth.handle_update does print out the expected string. myInit also prints out the expected object.
On the back end, I'm using this for my scan:
const AWS = require("aws-sdk");
const docClient = new AWS.DynamoDB.DocumentClient({ region: "us-west-1" });
exports.handler = (event, context, callback) => {
let e = JSON.parse(event.body);
var params = {
TableName: event.stageVariables.user,
FilterExpression: "handle = :handle",
ExpressionAttributeValues: { ":handle": e.handle }
};
docClient.scan(params, function(err, data) {
if (err) {
console.log("ERROR:", err);
let response = {
statusCode: err.statusCode,
headers: {},
body: JSON.stringify(err)
};
callback(response);
}
if (data.Count >= 1) {
// if user name exists
// call back handle exists response
let handleExistsResponse = {
statusCode: 200,
body: JSON.stringify({ Success: true })
};
callback(null, handleExistsResponse);
} else {
let response = {
statusCode: 200,
body: JSON.stringify({ Success: false })
};
callback(null, response);
}
});
};
Any idea as to why this would work on iOS and not Android?
EDIT:
Upon further testing, let e = JSON.parse(event.body) is returning null. So I console logged event and got a big ol object. Within this object, I found body and it's still null. So the body object isn't being passed it properly. Still confused about it working on iOS and not Android.
Did it!
Okay so API.get doesn't like body's being passed in. Instead, it wants a query parameter. So the lambda params looks like:
var params = {
TableName: event.stageVariables.user,
FilterExpression: "handle = :handle",
ExpressionAttributeValues: {
":handle": event["queryStringParameters"]["handle"]
}
};
And the front end function is:
export async function scanHandles(){
return new Promise((resolve, reject) => {
let { auth } = store.getState()
let handle = auth.handle_update
let path = `/u/scan-handle?handle=${handle}`
let myInit = {
headers: { 'Content-Type': 'application/json' },
}
API.get(apiName, path, myInit)
.then((resp) => {
// if false, then handle does not exist
// if true, then handle already exists
resolve(resp)
})
.catch((error) => {
console.warn('Scan Handle', error)
reject(error)
})
})
}
Works on both iOS and Android. Wonder why it wasn't working before?
My environment is Android and i use Xamarin for do my project.
I have a problem with my connection to server, for that i use Json my error is :
`Newtonsoft.Json.JsonReaderException: Error reading JObject from JsonReader. Current JsonReader item is not an object: String. Path '', line 1, position 2. at Newtonsoft.Json.Linq.JObject.Load`
so my code app side is :
public async Task Login (string user_email, string user_password)
{
var content = new Dictionary<string, string> { {
"user_email",
user_email
},
{
"user_password",
user_password
}
};
String str = await ProcessPOST ("/api/login", content);
JObject data = JObject.Parse (str);
if (data ["success"] != null)
return (string)data ["success"];
throw new Exception ((string)data ["error"]);
}
and server side is :
So login
public function login() {
if ($this->method == "POST") {
if ($this->_data("user_email") && $this->_data("user_password")) {
$u_dao = new UserDAO();
$users = $u_dao->executeSelect("WHERE user_email = :user_email", array("user_email" => $this->_data("user_email")));
if (!isset($users[0]))
return $this->_response(array("error" => "User not found"), 403);
$user = $users[0];
if ($user && crypt($this->_data("user_password"), $user->user_password) == $user->user_password) {
$token = bin2hex(openssl_random_pseudo_bytes(16));
$user->user_token = $token;
$u_dao->update($user);
return $this->_response(array("success" => $token));
}
return $this->_response(array("error" => "Bad login"), 403);
}
return $this->_response(array("error" => "Missing data"), 500);
}
return $this->_response(array("error" => "Wrong method"), 405);
}
and code of _response
protected function _response($data, $status = 200) {
header("HTTP/1.1 " . $status . " " . $this->_requestStatus($status));
return json_encode($data);
}
and now of _requestStatus
private function _requestStatus($code) {
$status = array(
200 => 'OK',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
500 => 'Internal Server Error',
);
return ($status[$code]) ? $status[$code] : $status[500];
}
and when i try to connect my web service is online , but i forget to said when i have error like "Missing Data" i haven't error of JObject but when i have success i have error.
so i show to all two str one of error:
"{\"error\":\"Missing data\"}"
and one of succes:
"''{\"success\":\"db035db78a9f1e64d71c83bcbb45ffa5\"}"
i want to said thanks to all people which help me . And i'm sorry for my bad english but i'm french .
i hope to be clear but if u have question u can ask them.
I don't see any necessary use for Json.net here. I would simplify and just check if the response contains "success" or "error".
How to retrieve device id/ token at device registration? I am using Phonegap Pushwoosh example and it works fine. But I could not figure out how to retrieve the token at device registration initPushwoosh.
I am not a professional programmer. Any help will be appreciated.
I have an index.html that initialize
<body onload="init();">
In main.js
function init() {
document.addEventListener("deviceready", deviceInfo, true);
document.addEventListener("deviceready", initPushwoosh, true);
}
In PushNotification.js
function initPushwoosh()
{
var pushNotification = window.plugins.pushNotification;
// CHANGE projectid & appid
pushNotification.registerDevice({ projectid: "xxxxxxx", appid : "xxxxxxxx" },
function(status) {
var pushToken = status;
console.warn('push token: ' + pushToken);
},
function(status) {
console.warn(JSON.stringify(['failed to register ', status]));
});
document.addEventListener('push-notification', function(event) {
var title = event.notification.title;
var userData = event.notification.userdata;
if(typeof(userData) != "undefined") {
console.warn('user data: ' + JSON.stringify(userData));
}
navigator.notification.alert(title);
});
}
The first section is the .registerDevice and the token is probably pushToken, but I just cannot figure out how to retrieve it from this function!
The best is to send it to a MySQL database lets call it smartphonedb.tokentable
I modified the initPushwoosh() to send me the token to MySQL using Ajax (see below) I am receiving nothing on MySQL. Am I sending the right Token param (pushToken)?
function initPushwoosh()
{
var pushNotification = window.plugins.pushNotification;
// CHANGE projectid & appid
pushNotification.registerDevice({ projectid: "xxxxxx", appid : "xxxxxxx" },
function(status) {
var pushToken = status;
console.warn('push token: ' + pushToken);
// start my ajax to insert token to mysql
var param ={Token: pushToken};
$.ajax({
url: 'http://luxurylebanon.com/offeratlive/apitoken.php', data: param, dataType: 'json', success: function(result)
{
if(result.success == false)
{
alert(failed)
}
else {
alert(success)
}
}
});
// end ajax
},
function(status) {
console.warn(JSON.stringify(['failed to register ', status]));
});
document.addEventListener('push-notification', function(event) {
var title = event.notification.title;
var userData = event.notification.userdata;
if(typeof(userData) != "undefined") {
console.warn('user data: ' + JSON.stringify(userData));
}
navigator.notification.alert(title);
});
}
The PHP apitoken.php
<?php
$username="xxxxxxx";
$password="xxxxxxxxxxxx";
$database="offeratdb";
$server="offeratdb.db.xxxxxxxxx.com";
$connect = mysql_connect($server,$username,$password)or die('Could not connect: ' . mysql_error());
#mysql_select_db($database) or die('Could not select database ('.$database.') because of : '.mysql_error());
$vtoken= $_POST['Token'];
// Performing SQL query
$query = "INSERT INTO `tokentable` (`thetoken`) VALUES ('$vtoken')";
$result = mysql_query($query)or die('Query failed: ' . mysql_error());
echo $vtoken;
// We will free the resultset...
mysql_free_result($result);
// Now we close the connection...
mysql_close($connect);
?>
any help will be appreciated
After looking through your code I think it contains some mistakes.
So, lets try to fix them:
First of all. Do you have jquery js script included before PushNotification.js? If not, "$.ajax" will not be executed.
The other thing. The ajax default type is GET, and you use POST in your php code.
And you don't use json at all. So your code should be transformed into something like this
$.ajax({
type: "POST",
async: true,
url: url,
data: params,
success: function (result) {
// todo
},
error: function (result) {
// todo
}
});
And the last thing. The param var should be initialized like this:
var param = "Token="+pushToken;
Hope this would be helpful.
I was having the same problem, I updated the Pushwoosh.jar and it worked for me. :)