I followed the tutorial below.
https://developers.google.com/eclipse/docs/running_and_debugging_2_0
which basically added a GAE backend to my existing app. I then try out the example below, run it on the local development server and I get the exception below which occurs after
Note result = endpoint.insertNote(note).execute();
is called.
com.google.api.client.googleapis.json.GoogleJsonResponseException: 404 Not Found
My code is below.
package com.cloudnotes;
import java.io.IOException;
import java.util.Date;
import android.os.AsyncTask;
import android.content.Context;
import com.cloudnotes.noteendpoint.Noteendpoint;
import com.cloudnotes.noteendpoint.model.Note;
import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.json.jackson.JacksonFactory;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new EndpointsTask().execute(getApplicationContext());
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
public class EndpointsTask extends AsyncTask<Context, Integer, Long> {
protected Long doInBackground(Context... contexts) {
Noteendpoint.Builder endpointBuilder = new Noteendpoint.Builder(
AndroidHttp.newCompatibleTransport(),
new JacksonFactory(),
new HttpRequestInitializer() {
public void initialize(HttpRequest httpRequest) { }
});
Noteendpoint endpoint = CloudEndpointUtils.updateBuilder(
endpointBuilder).build();
try {
Note note = new Note().setDescription("Note Description");
String noteID = new Date().toString();
note.setId(noteID);
note.setEmailAddress("E-Mail Address");
Note result = endpoint.insertNote(note).execute();
} catch (IOException e) {
e.printStackTrace();
}
return (long) 0;
}
}
}
Another possible cause for this problem is not setting the correct applicationId in appengine-web.xml:
<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<application>APPLICATION_ID_HERE</application>
...
</appengine-web-app>
Another possible reason for 404 if you call the method with a null parameter and the method does not accept null parameters.
I had a similar issue with a method with 4 String parameters and I sent null for one of them and all I got was a stupid 404.
Another possible reason for 404 on the development(local) server is that you have a parameter with some strange characters (like a url for example) that the development(local) server does not handle correctly event if it works fine on the app engine live servers. Possible solution: instead of multiple params use a simple java object.
I had the same problem and this is how I fixed it.
A little background
I had two versions of the API deployed to App Engine which I believe it should be OK. The admin console didn't show any problem and I was getting the 200 OK code after deploying version 2 of the API in log file.
/_ah/spi/BackendService.getApiConfigs 200 118ms 8kb
but no matter what I tried I was always getting the 404 Not Found error.
I am not sure what the problem was but I think Web Server at App Engine was redirecting all the requests to the version 1. It could be because both versions had the following settings in their web.xml.
<servlet-mapping>
<servlet-name>SystemServiceServlet</servlet-name>
<url-pattern>/_ah/spi/*</url-pattern>
</servlet-mapping>
Solution
I removed version 1 and redeployed version 2. Then everything just worked fine.
This comes down to the app engine default version being different from the one you've deployed. Go here:
https://appengine.google.com/deployment?app_id=s~your-project-id
and change your default version
this happen because your deploy back-end is not fully deployed. just re-deploy your back-end and make sure you got the message deploy succeed. you can check the detail deploy process on the top page header. also, you can test by visiting the url to check:
https://developers.google.com/apis-explorer/?base=https://[YOUR_PROJECT_ID].appspot.com/_ah/api#p/
Try to update your plugin and dependency libraries to the latest version. See https://stackoverflow.com/a/37639701/857346.
In build gradle do:
minifyEnabled false
Related
I need to implement SSL Certificate Pinning in my react native application.
I know very little about SSL/TLS let alone pinning.
I am also not a native mobile developer, though I know Java and learned Objective-C on this project enough to get around.
I started searching for how to execute this task.
Doesn't React Native already implement this?
No, My initial search lead me to this proposal which has received no activity since August 2nd 2016.
From it I learned that react-native uses OkHttp which does support Pinning, but I wouldn't be able to pull it off from Javascript, which is not really a requirement but a plus.
Implement it in Javascript.
While react seems like it uses the nodejs runtime, it is more like a browser than node, meaning it does not support all native modules, specifically the https module, for which I had implemented certificate pinning following this article. Thus could not carry it into react native.
I tried using rn-nodeify but the modules didn't work. This has been true since RN 0.33 to RN 0.35 which I'm currently on.
Implement using phonegap plugin
I thought of using a phongape-plugin however since I have a dependency on libraries that require react 0.32+ I can't use react-native-cordova-plugin
Just do it natively
While I'm not a native app developer I can always take a crack at it, only a matter of time.
Android has certificate pinning
I learned that android supports SSL Pinning however was unsuccessful as it seems that this approach does not work Prior to Android 7. As well as only working for android.
The bottom line
I have exhausted several directions and will continue to pursue more native implementation, maybe figure out how to configure OkHttp and RNNetworking then maybe bridging back to react-native.
But is there already any implementations or guide for IOS and android?
After exhausting the current spectrum of available options from Javascript I decided to simply implement certificate pinning natively it all seems so simple now that I'm done.
Skip to headers titled Android Solution and IOS Solution if you don't want to read through the process of reaching the solution.
Android
Following Kudo's recommendation I thought out to implement pinning using okhttp3.
client = new OkHttpClient.Builder()
.certificatePinner(new CertificatePinner.Builder()
.add("publicobject.com", "sha1/DmxUShsZuNiqPQsX2Oi9uv2sCnw=")
.add("publicobject.com", "sha1/SXxoaOSEzPC6BgGmxAt/EAcsajw=")
.add("publicobject.com", "sha1/blhOM3W9V/bVQhsWAcLYwPU6n24=")
.add("publicobject.com", "sha1/T5x9IXmcrQ7YuQxXnxoCmeeQ84c=")
.build())
.build();
I first started by learning how to create a native android bridge with react nativecreating a toast module. I then extended it with a method for sending a simple request
#ReactMethod
public void showURL(String url, int duration) {
try {
Request request = new Request.Builder()
.url(url)
.build();
Response response = client.newCall(request).execute();
Toast.makeText(getReactApplicationContext(), response.body().string(), duration).show();
} catch (IOException e) {
Toast.makeText(getReactApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
Succeeding in sending a request I then turned to sending a request pinned.
I used these packages in my file
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.CertificatePinner;
import java.io.IOException;
import java.util.Map;
import java.util.HashMap;
Kudo's approach wasn't clear on where I would get the public keys or how to generate them. luckily okhttp3 docs in addition to providing a clear demonstration of how to use the CertificatePinner stated that to get the public keys all I would need to do is send a request with an incorrect pin, and the correct pins will appear in the error message.
After taking a moment to realise that OkHttpClent.Builder() can be chained and I can include the CertificatePinner before the build, unlike the misleading example in Kudo's proposal (probably and older version) I came up with this method.
#ReactMethod
public void getKeyChainForHost(String hostname, Callback errorCallbackContainingCorrectKeys,
Callback successCallback) {
try {
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add(hostname, "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAA=")
.build();
OkHttpClient client = (new OkHttpClient.Builder()).certificatePinner(certificatePinner).build();
Request request = new Request.Builder()
.url("https://" + hostname)
.build();
Response response =client.newCall(request).execute();
successCallback.invoke(response.body().string());
} catch (Exception e) {
errorCallbackContainingCorrectKeys.invoke(e.getMessage());
}
}
Then replacing the public keychains I got in the error yielded back the page's body, indicating I had made a successful request, I change one letter of the key to make sure it was working and I knew I was on track.
I finally had this method in my ToastModule.java file
#ReactMethod
public void getKeyChainForHost(String hostname, Callback errorCallbackContainingCorrectKeys,
Callback successCallback) {
try {
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add(hostname, "sha256/+Jg+cke8HLJNzDJB4qc1Aus14rNb6o+N3IrsZgZKXNQ=")
.add(hostname, "sha256/aR6DUqN8qK4HQGhBpcDLVnkRAvOHH1behpQUU1Xl7fE=")
.add(hostname, "sha256/HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=")
.build();
OkHttpClient client = (new OkHttpClient.Builder()).certificatePinner(certificatePinner).build();
Request request = new Request.Builder()
.url("https://" + hostname)
.build();
Response response =client.newCall(request).execute();
successCallback.invoke(response.body().string());
} catch (Exception e) {
errorCallbackContainingCorrectKeys.invoke(e.getMessage());
}
}
Android Solution Extending React Native's OkHttpClient
Having figured out how to send pinned http request was good, now I can use the method I created, but ideally I thought it would be best to extend the existing client, so as to immediately gain the benefit of implementing.
This solution is valid as of RN0.35 and I don't know how it will fair in the future.
While looking into ways of extending the OkHttpClient for RN I came across this article explaining how to add TLS 1.2 support through replacing the SSLSocketFactory.
reading it I learned react uses an OkHttpClientProvider for creating the OkHttpClient instance used by the XMLHttpRequest Object and therefore if we replace that instance we would apply pinning to all the app.
I added a file called OkHttpCertPin.java to my android/app/src/main/java/com/dreidev folder
package com.dreidev;
import android.util.Log;
import com.facebook.react.modules.network.OkHttpClientProvider;
import com.facebook.react.modules.network.ReactCookieJarContainer;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.CertificatePinner;
public class OkHttpCertPin {
private static String hostname = "*.efghermes.com";
private static final String TAG = "OkHttpCertPin";
public static OkHttpClient extend(OkHttpClient currentClient){
try {
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add(hostname, "sha256/+Jg+cke8HLJNzDJB4qc1Aus14rNb6o+N3IrsZgZKXNQ=")
.add(hostname, "sha256/aR6DUqN8qK4HQGhBpcDLVnkRAvOHH1behpQUU1Xl7fE=")
.add(hostname, "sha256/HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=")
.build();
Log.d(TAG, "extending client");
return currentClient.newBuilder().certificatePinner(certificatePinner).build();
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
return currentClient;
}
}
This package has a method extend which takes an existing OkHttpClient and rebuilds it adding the certificatePinner and returns the newly built instance.
I then modified my MainActivity.java file following this answer's advice by adding the following methods
.
.
.
import com.facebook.react.ReactActivity;
import android.os.Bundle;
import com.dreidev.OkHttpCertPin;
import com.facebook.react.modules.network.OkHttpClientProvider;
import okhttp3.OkHttpClient;
public class MainActivity extends ReactActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
rebuildOkHtttp();
}
private void rebuildOkHtttp() {
OkHttpClient currentClient = OkHttpClientProvider.getOkHttpClient();
OkHttpClient replacementClient = OkHttpCertPin.extend(currentClient);
OkHttpClientProvider.replaceOkHttpClient(replacementClient);
}
.
.
.
This solution was carried out in favor of completely reimplementing the OkHttpClientProvider createClient method, as inspecting the provider I realized that the master version had implemented TLS 1.2 support but was not yet an available option for me to use, and so rebuilding was found to be the best means of extending the client. I'm wondering how this approach will fair as I upgrade but for now it works well.
Update It seems that starting 0.43 this trick no longer works. For timebound reasons I will freeze my project at 0.42 for now, until the reason for why rebuilding stopped working is clear.
Solution IOS
For IOS I had thought I would need to follow a similar method, again starting with Kudo's proposal as my lead.
Inspecting the RCTNetwork module I learned that NSURLConnection was used, so instead of trying to create a completely new module with AFNetworking as suggested in the proposal I discovered TrustKit
following its Getting Started Guide I simply added
pod 'TrustKit'
to my podfile and ran pod install
the GettingStartedGuide explained how I can configure this pod from my pList.file but preferring to use code than configuration files I added the following lines to my AppDelegate.m file
.
.
.
#import <TrustKit/TrustKit.h>
.
.
.
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Initialize TrustKit
NSDictionary *trustKitConfig =
#{
// Auto-swizzle NSURLSession delegates to add pinning validation
kTSKSwizzleNetworkDelegates: #YES,
kTSKPinnedDomains: #{
// Pin invalid SPKI hashes to *.yahoo.com to demonstrate pinning failures
#"efghermes.com" : #{
kTSKEnforcePinning:#YES,
kTSKIncludeSubdomains:#YES,
kTSKPublicKeyAlgorithms : #[kTSKAlgorithmRsa2048],
// Wrong SPKI hashes to demonstrate pinning failure
kTSKPublicKeyHashes : #[
#"+Jg+cke8HLJNzDJB4qc1Aus14rNb6o+N3IrsZgZKXNQ=",
#"aR6DUqN8qK4HQGhBpcDLVnkRAvOHH1behpQUU1Xl7fE=",
#"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY="
],
// Send reports for pinning failures
// Email info#datatheorem.com if you need a free dashboard to see your App's reports
kTSKReportUris: #[#"https://overmind.datatheorem.com/trustkit/report"]
},
}
};
[TrustKit initializeWithConfiguration:trustKitConfig];
.
.
.
I got the public key hashes from my android implementation and it just worked (the version of TrustKit I received in my pods is 1.3.2)
I was glad IOS turned out to be a breath
As a side note TrustKit warned that it's Auto-swizzle won't work if the NSURLSession and Connection are already swizzled. that said it seems to be working well so far.
Conclusion
This answer presents the solution for both Android and IOS, given I was able to implement this in native code.
One possible improvement may be to implement a common platform module where setting public keys and configuring the Network providers of both android and IOS can be managed in javascript.
Kudo's proposal mentioned simply adding the public keys to the js bundle may however expose a vulnerability, where somehow the bundle file can be replaced.
I don't know how that attack vector can function, but certainly the extra step of signing the bundle.js as proposed may protect the js bundle.
Another approach may be to simply encode the js bundle into a 64 bit string and include it in the native code directly as mentioned in this issue's conversation. This approach has the benefit of obfuscating as well hardwiring the js bundle into the app, making it inaccessible for attackers or so I think.
If you read this far I hope I enlightened you on your quest for fixing your bug and wish you enjoy a sunny day.
You can use this lib https://github.com/nlt2390/react-native-pinning-ssl
It verifies SSL connection using SHA1 keys, not certificates.
I am just about to release an app and I saw this stackoverflow question about things you should do before releasing an app. It tells me to use ACRA so I followed the instructions on this page.
So know I have a class called MyApplication like so :
import android.app.Application;
import org.acra.*;
import org.acra.annotation.*;
#ReportsCrashes(formKey = "", // will not be used
mailTo = "c#gmail.com",
mode = ReportingInteractionMode.TOAST,
customReportContent = { ReportField.APP_VERSION_CODE, ReportField.APP_VERSION_NAME, ReportField.ANDROID_VERSION, ReportField.PHONE_MODEL, ReportField.CUSTOM_DATA, ReportField.STACK_TRACE, ReportField.LOGCAT },
resToastText = R.string.crash_report_text)
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
// The following line triggers the initialization of ACRA
ACRA.init(this);
}
}
Now apparently when my application crashes I think the user is supposed to be able to send the report somehow, so I put a null pointer in my app but it just crashes and nothing happens. Am I supposed to do anything else?
I guess you might not have registered your application on BugSense
Where you want to send the crash reporst that depands on you only. When you are using Google Docs (deprecated now), you have to use your formKey you got from your google docs document.
If you want to store the reports on your own server, you can leave the formKey field blank. The only thing you have to do is to enter a valid url to your server (formUri = ....).
The other strings are for the type of dialog, which should or shouldn't appear.
Instead of using your own server, you can use BugSense. See this thread on stackoverflow.
As the use of Google Docs is deprecated for ACRA. I recommend you to use **BugSense** as your Back-End service:
1. Go to their site and sign in: http://www.bugsense.com/
2. Create a new project to monitor in BugSense site, as a result you will receive an API Key for this application.
3. Finally add this line to you Application class in you project:
#ReportsCrashes(formUri = "http://www.bugsense.com/api/acra?api_key=YOUR_API_KEY", formKey="")
Check out BugSense Docmentation
I'm attempting to follow the example tutorial at https://developers.google.com/eclipse/docs/endpoints-addentities and I'm stuck figuring out how to get the GameEndpoint.Builder class to generate within Eclipse.
After following this and generating the cloud endpoints as described, I have a GameEndpoint class created, but there is no GameEndpoint.Builder class. So obviously I have this error
GameEndpoint.Builder cannot be resolved to a type
I'm stumped at this point. How do I generate the GameEndpoint.Builder class within Eclipse, or what would prevent it?
Code
public class NewGameTask extends AsyncTask<Context, Integer, Long> {
protected Long doInBackground(Context... contexts) {
GameEndpoint.Builder endpointBuilder = new GameEndpoint.Builder(
AndroidHttp.newCompatibleTransport(), new JacksonFactory(),
new HttpRequestInitializer() {
public void initialize(HttpRequest httpRequest) {
}
});
GameEndpoint endpoint = CloudEndpointUtils.updateBuilder(
endpointBuilder).build();
try {
Game game = new Game();
game.setStart(Calendar.getInstance());
Game result = endpoint.insertGame(game);
} catch (IOException e) {
e.printStackTrace();
}
return (long) 0;
}
}
I figured out my issue after watching this video from Google I/O 2013 which is using Android Studio, but it was the same thing as Eclipse mostly.
My mistake in following https://developers.google.com/eclipse/docs/endpoints-addentities was that you need to put your entity class into the MyApp-AppEngine project and NOT your MyApp project.
That was the source of confusion. In case it helps those in the future, here is a short breakdown of what I did.
Put the Entity class you want to add to App Engine into your MyApp-AppEngine project.
Right click your class and go to Google > Generate Cloud Endpoint Client Library
Right click your MyApp-AppEngine project and go to Google > Generate Cloud Enpoint Client Library
New references will be made in your MyApp project which you reference in your project for usage.
Note This answer is based on Android Studio, but am sure it's pretty much the same as Eclipse.
I also had this issue but later found the cause.Turns out I was importing the Endpoint class I generated instead of the endpoint Api package. Let me be clear.When you add the endpoint module to your project, you get the MyBean and MyEndpoint classes in the endpoint package. If you take a look at the guide to connecting your client to your backend, the EndpointsAsyncTask class uses:
private static MyApi myApiService = null;
Note how it uses MyApi instead of MyBean Now I was wondering where it got that from but I just have to take a look at my backend libraries:
The library marked 1 is the library first added to your project when you follow the guide previously mentioned. When I added a new class Student and autogenerated the cloud endpoint class, the second library was also added.
Long, boring story short; It is this library you should be importing and not the class.
import com.package-name.backend.studentApi.StudentApi;
and then using:
private static StudentApi myApiService = null;
...
StudentApi.Builder builder = new StudentApi.Builder(...)
instead of:
import com.package-name.backend.StudentEndpoint;
...
private static StudentEndpoint myApiService = null;
StudentEndpoint.Builder builder = new StudentEndpoint.Builder(...)
I got the same problem in Android Studio. I generated my Endpoint class from my entity java bean but when creating the AsyncTask, now way to get the Builder.
Actually (if I take a Game java bean like you) the Builder is not depending on the GameEndPoint but on the generated GameApi class.
In other words, I had to add these two imports in the AsyncTask class:
import com.examplepackage.backend.gameApi.GameApi;
import com.examplepackage.backend.gameApi.model.Game;
while the Game java bean that you wrote and the generated GameEndpoint are under package com.examplepackage.backend
I have the following project structure.
My StockInfo.java is perfectly fine.
StockInfo.java (No error)
package org.yccheok.jstock.engine;
import android.os.Parcel;
import android.os.Parcelable;
public class StockInfo implements Parcelable {
...
...
StockInfo.aidl (No error)
package org.yccheok.jstock.engine;
parcelable StockInfo;
StockInfoObserver.aidl (Error!)
package org.yccheok.jstock.engine;
interface StockInfoObserver {
void update(StockInfo stockInfo);
}
AutoCompleteApi.aidl (Error!)
package org.yccheok.jstock.engine;
interface AutoCompleteApi {
void handle(String string);
void attachStockInfoObserver(StockInfoObserver stockInfoObserver);
}
However, Eclipse complains in StockInfoObserver.aidl (It does complain AutoCompleteApi.aidl too, as it cannot process StockInfoObserver.aidl),
parameter stockInfo (1) unknown type StockInfo
I tried for an hour, but still not able to find out, why in aidl, StockInfo is not being recognized although I had
Provided StockInfo.aidl
Provided StockInfo.java
Any idea?
Here are the complete errors.
Note, AutoCompleteApi.aidl is very much dependent on StockInfoObserver.aidl. That's why you will see the error.
I share the entire project for your reference purpose : https://www.dropbox.com/s/0k5pe75jolv5mtq/jstock-android.zip
According to Android documentation You must include an import statement for each additional type not listed above, even if they are defined in the same package as your interface
Try to add this line to StockInfoObserver.aidl
import org.yccheok.jstock.engine.StockInfo;
i want to connect odbc connection to my android application. my database is oracle 10g. Here in my code my table name is world. After compiling my program and close the emulator open table in oracle database the values could not be stored
The same coding i compiled normal javac compiler in cmp prompt the values should be stored, if i compiling in android application in eclipse ide the values could not be stored.Pls give one solution or any changes in my code
Thanks in advance
package com.odbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import android.app.Activity;
import android.os.Bundle;
import android.R.id;
public class OdbcActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try
{
String country="india";
String city="delhi";
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection con=DriverManager.getConnection("jdbc:odbc:world","system","love");
PreparedStatement ps=con.prepareStatement("insert into world(country,city) values(?,?)");
ps.setString(1,country);
ps.setString(2,city);
ps.executeUpdate();
}
catch(Exception e)
{
System.out.println("Exception:"+e);
}
}
}
Android apps connecting directly to a DMBS isn't an architecture I'd recommend. Instead, I suggest setting an application on the server (using Java, Rails, whatever) that reads the database and exposes a simple HTTP web service for the Android app to get at the data. Not only is that a more sound architecture, I'm not even sure you can run JDBC drivers in an Android device. Using my architecture, you isolate the device from the structure and type of your database.