Firebase Service Account Credentials Json Read permission denied - android

I downloaded my service account credential json file from Firebase console placed it earlier in the main directory of GAE endpoint project when I run my backed locally it gives Security exception.
java.security.AccessControlException: access denied ("java.io.FilePermission" "\src\main\secret.json" "read")
I tried placing the .json file under the src directory also but no help.

You should place the json file in src/main/resources

I found a couple ways to approach this. First is by getting it from a file over an internet stream. The other is locally.
INTERNET WAY
My first method involved storing the file on my public dropbox folder. I got the shareable link (make sure it ends in .json) and pasted it in the string example "https://dl.dropboxusercontent.com/..EXAMPLE-CREDENTIALS"
/** A simple endpoint method that takes a name and says Hi back */
#ApiMethod(name = "sayHi")
public MyBean sayHi(#Named("name") String name) {
MyBean mModelClassObject = null;
String text = "";
try {
String line = "";
StringBuilder builder = new StringBuilder();
URL url = new URL("https://dl.dropboxusercontent.com/..EXAMPLE-CREDENTIALS");
BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
while ((line = reader.readLine()) != null) {
// ...
builder.append(line);
}
reader.close();
text = builder.toString();
} catch (MalformedURLException e) {
// ...
} catch (IOException e) {
// ...
}
InputStream stream = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8));
FirebaseOptions options = null;
options = new FirebaseOptions.Builder()
.setServiceAccount(stream)
.setDatabaseUrl("https://[PROJECT-ID].firebaseio.com/")
.build();
FirebaseApp.initializeApp(options);
DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
final TaskCompletionSource<MyBean> tcs = new TaskCompletionSource<>();
Task<MyBean> tcsTask = tcs.getTask();
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
MyBean result = dataSnapshot.getValue(MyBean.class);
if(result != null){
tcs.setResult(result);
}
}
#Override
public void onCancelled(DatabaseError databaseError){
//handle error
}
});
try {
mModelClassObject = Tasks.await(tcsTask);
}catch(ExecutionException e){
//handle exception
}catch (InterruptedException e){
//handle exception
}
return mModelClassObject;
}
LOCAL WAY
The other way is taking the version above and skipping something like dropbox
/** A simple endpoint method that takes a name and says Hi back */
#ApiMethod(name = "sayHi")
public MyBean sayHi(#Named("name") String name) {
MyBean mModelClassObject = null;
String text = "JUST PASTE YOUR JSON CONTENTS HERE";
InputStream stream = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8));
FirebaseOptions options = null;
options = new FirebaseOptions.Builder()
.setServiceAccount(stream)
.setDatabaseUrl("https://[PROJECT-ID].firebaseio.com/")
.build();
FirebaseApp.initializeApp(options);
DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
final TaskCompletionSource<MyBean> tcs = new TaskCompletionSource<>();
Task<MyBean> tcsTask = tcs.getTask();
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
MyBean result = dataSnapshot.getValue(MyBean.class);
if(result != null){
tcs.setResult(result);
}
}
#Override
public void onCancelled(DatabaseError databaseError){
//handle error
}
});
try {
mModelClassObject = Tasks.await(tcsTask);
}catch(ExecutionException e){
//handle exception
}catch (InterruptedException e){
//handle exception
}
return mModelClassObject;
}
I don't know if this follows best practice but my project is working now.
I also included firebase's code for getting info. check out this answer to a question i asked recently on reading and writing to firebase.
EDIT
cleaned up version which doesnt throw errors
public class MyEndpoint {
private FirebaseOptions options;
private DatabaseReference ref;
private String serviceAccountJSON = "i took mine out for security reasons";
// create firebase instance if need be
private void connectToFirebase(){
if (options == null) {
options = null;
options = new FirebaseOptions.Builder()
.setServiceAccount(new ByteArrayInputStream(serviceAccountJSON.getBytes(StandardCharsets.UTF_8)))
.setDatabaseUrl("https://[PROJECT-ID].firebaseio.com/")
.build();
FirebaseApp.initializeApp(options);
}
if(ref == null) {
ref = FirebaseDatabase.getInstance().getReference();
}
}
/** A simple endpoint method that takes a name and says Hi back */
#ApiMethod(name = "sayHi")
public MyBean sayHi(#Named("name") String name) {
// always do this first
connectToFirebase();
MyBean mModelClassObject = null;
final TaskCompletionSource<MyBean> tcs = new TaskCompletionSource<>();
Task<MyBean> tcsTask = tcs.getTask();
// get the info
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
MyBean result = dataSnapshot.getValue(MyBean.class);
if(result != null){
tcs.setResult(result);
}
}
#Override
public void onCancelled(DatabaseError databaseError){
//handle error
}
});
// wait for it
try {
mModelClassObject = Tasks.await(tcsTask);
}catch(ExecutionException e){
//handle exception
}catch (InterruptedException e){
//handle exception
}
mModelClassObject.setData(mModelClassObject.getData() + name);
return mModelClassObject;
}
}

Finally, I found the solution, Its written under the APIs and references section of Google App Engine in this link, that we need to add such files in the appengine-web.xml file under the <resource-files> tag, using <include path=""/> property. After doing so its works for me. I placed the .json file containing project credentials in the WEB-INF directory and then entered its relative path in <resource-files> tag.

Related

How to make retrofit api request for each item in list with rxjava?

I'm very new to RxJava and although I have seen multiple questions related to the one I am asking, I can't seem to piece them out altogether.
I have a PostPatrol object containing the following data:
public class PostPatrol {
String checkpoint_name;
String status;
int user;
String detail;
List<String> photos;
public PostPatrol(int cpId, String checkpoint_name, String detail, List<String> photos, String detail) {
this.cpId = cpId;
this.checkpoint_name = checkpoint_name;
this.detail = detail;
this.photos = photos;
this.status = status;
}
//getters and setters
}
What I'm trying to do now is to save a local list of photos into this PostPatrol record, but before that I have to upload the photos one by one with retrofit, get back a url and save that to a list which I then set as the photos for the PostPatrol record.
Once I save all the needed details for a certain PostPatrol record, I then send that again through retrofit.
Currently, I am doing it this way:
I pass the photos to a function to upload the image one by one
The function is like this:
private void uploadImage(List<String> photos, String folder, long requestId) {
final int size = photos.size();
final long reqId = requestId;
for (String path : photos) {
File file = new File(path);
RequestBody requestBody = RequestBody.create(MediaType.parse("image/*"), file);
MultipartBody.Part body = MultipartBody.Part.createFormData("image", file.getName(), requestBody);
RequestBody folderName = RequestBody.create(MediaType.parse("text/plain"), folder);
ApiEndpointInterface apiEndpointInterface = RetrofitManager.getApiInterface();
Call<FileInfo> call4File = apiEndpointInterface.postFile(body, folderName);
call4File.enqueue(new ApiCallback<FileInfo>() {
#Override
protected void do4Failure(Throwable t) {
Log.d(TAG, t.toString());
snackbar = Snackbar.make(viewPendingRequestLayout, R.string.sb_image_upload_error, Snackbar.LENGTH_SHORT);
snackbar.show();
position++;
}
#Override
protected void do4PositiveResponse(Response<FileInfo> response) {
Log.d(TAG, "Uploaded Image");
FileInfo fileDetails = response.body();
listUrls.add(fileDetails.getImage());
position++;
if (position == size) {
postRequest(reqId);
position = 0;
}
}
#Override
protected void do4NegativeResponse(Response<FileInfo> response) {
String bodyMsg = "";
try {
bodyMsg = new String(response.errorBody().bytes());
} catch (IOException e) {
e.printStackTrace();
}
Log.d(TAG, bodyMsg);
snackbar = Snackbar.make(viewPendingRequestLayout, R.string.sb_image_upload_error, Snackbar.LENGTH_SHORT);
snackbar.show();
position++;
}
});
}
}
In do4PositiveResponse I use local variables to keep track whether I have uploaded all the photos before sending them to a function where the list is saved to the PostPatrol record. Sometimes though, I get problems where the photos aren't uploaded at all since it fires too late or too early.
This is my code onpostRequest()
private void postRequest(long requestId) {
if(mapIdPatrol.containsKey(requestId)){
PostPatrol postPatrol = mapIdPatrol.get(requestId);
postPatrol.setPhotos(listUrls);
postPatrolRequest(postPatrol, requestId);
}
listUrls = new ArrayList<>();
}
And finally my code on postPatrolRequest()
private void postPatrolRequest(final PostPatrol postPatrol, final long requestId){
ApiEndpointInterface apiEndpointInterface = RetrofitManager.getApiInterface();
Call<ResponseId> call4Handle = apiEndpointInterface.handleCheckpoint(postPatrol);
call4Handle.enqueue(new ApiCallback<ResponseId>() {
#Override
protected void do4Failure(Throwable t) {
finishUploading();
Log.d(TAG, t.toString());
}
#Override
protected void do4PositiveResponse(Response<ResponseId> response) {
RequestsDataSource.removeRequest(getApplication(),requestId);
finishUploading();
}
#Override
protected void do4NegativeResponse(Response<ResponseId> response) {
finishUploading();
String bodyMsg = "";
try {
bodyMsg = new String(response.errorBody().bytes());
} catch (IOException e) {
e.printStackTrace();
}
Log.d(TAG, bodyMsg);
snackbar = Snackbar.make(viewPendingRequestLayout, getResources().getText(R.string.sb_negative_response), Snackbar.LENGTH_SHORT);
snackbar.show();
}
});
}
I know this is very inefficient and so I would like your help so I can try to find a way around it with the use of RxJava. Thank you.
Is the operation atomic? i.e. if saving some of the photos via Retrofit fails, do you still have to proceed?
Anyway, roughly the solution will be something like that (pseudocode):
Observable<String> urls = Observable.from(listOfPhotoFilePaths)
.flatMapDelayError(path -> { return retrofit.save(readFile(path))})
.toList()
Observable<PostPatrol> pp = urls
.map(list -> { return new PostPatrol(list)})

Replicating CouchDB with Cloudant fails

I have a CouchDB database and I want to replicate it on an Android device using Cloudant
So what I am doing is:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
URI uri = null;
File path = getApplicationContext().getDir(DATASTORE_DIRECTORY, Context.MODE_PRIVATE);
try {
uri = new URI("http://XXX.XXX.XXX.X:XXXX/my_database/");
} catch (URISyntaxException e) {
Log.d("onCreate",e.getMessage());
}
DocumentStore ds = null;
try {
ds = DocumentStore.getInstance(path);
} catch (DocumentStoreNotOpenedException e) {
Log.d("onCreate",e.getMessage());
}
// Create a replicator that replicates changes from the remote
// database to the local DocumentStore.
Replicator replicator = ReplicatorBuilder.pull()
.from(uri)
.to(ds)
.addRequestInterceptors(new BasicAuthInterceptor("myUser:myPass"))
.build();
// Use a CountDownLatch to provide a lightweight way to wait for completion
CountDownLatch latch = new CountDownLatch(1);
Listener listener = new Listener(latch);
replicator.getEventBus().register(listener);
replicator.start();
try {
latch.await();
} catch (InterruptedException e) {
Log.d("onCreate",e.getMessage());
}
replicator.getEventBus().unregister(listener);
if (replicator.getState() != Replicator.State.COMPLETE) {
Log.d("onCreate","Error replicating FROM remote");// error
Log.d("onCreate",(listener.errors).toString());// error
} else {
Log.d("onCreate",(String.format("Replicated %d documents in %d batches",
listener.documentsReplicated, listener.batchesReplicated)));
}
}
I am getting two errors;
onCreate: Error replicating FROM remote onCreate:
onCreate:[java.lang.RuntimeException: Could not determine if the _bulk_get
endpoint is supported]
What I am doing wrong?

Storing a string on mobile device using gluon mobile plugin

I want to save a string from a TextArea to the device and then reload it after reopening the app. I have tried following the examples (link) but cant get it to work. Main problem arises when i try to read the file and use a StringInputConverter.
private void saveAndLoad(TextArea textArea){
File textFile = new File(ROOT_DIR,"text_file");
String text2 = textArea.getText();
String loadedFile = "none";
if (textFile.exists()){
FileClient fileClient = FileClient.create(textFile);
loadedFile = DataProvider.retrieveObject(fileClient.createObjectDataReader(
new StringInputConverter()));
}
try(FileWriter writer = new FileWriter(textFile)){
writer.write(textArea.getText());
} catch (IOException e) {
e.printStackTrace();
}
textArea.setText(text2);
}
Edit: inserted code which i tried to start reading file with and image of the error i am getting
If you check the DataProvider::retrieveObject documentation:
Retrieves an object using the specified ObjectDataReader. A GluonObservableObject is returned, that will contain the object when the read operation completed successfully.
It returns GluonObservableObject<String>, which is an observable wrapper of the string, not the string itself.
You need to get first the observable, and when the operation ends successfully you can retrieve the string:
if (textFile.exists()) {
FileClient fileClient = FileClient.create(textFile);
GluonObservableObject<String> retrieveObject = DataProvider
.retrieveObject(fileClient.createObjectDataReader(new StringInputConverter()));
retrieveObject.stateProperty().addListener((obs, ov, nv) -> {
if (ConnectState.SUCCEEDED.equals(nv)) {
loadedFile = retrieveObject.get();
}
});
}
This is a quick implementation of this functionality:
public class BasicView extends View {
private static final File ROOT_DIR;
static {
ROOT_DIR = Services.get(StorageService.class)
.flatMap(StorageService::getPrivateStorage)
.orElseThrow(() -> new RuntimeException("Error"));
}
private final File textFile;
private final TextField textField;
private String loadedFile = "none";
public BasicView(String name) {
super(name);
textFile = new File(ROOT_DIR, "text_file");
textField = new TextField();
VBox controls = new VBox(15.0, textField);
controls.setAlignment(Pos.CENTER);
controls.setPadding(new Insets(30));
setCenter(controls);
}
#Override
protected void updateAppBar(AppBar appBar) {
appBar.setNavIcon(MaterialDesignIcon.MENU.button(e -> System.out.println("Menu")));
appBar.setTitleText("Basic View");
appBar.getActionItems().add(MaterialDesignIcon.SAVE.button(e -> save()));
appBar.getActionItems().add(MaterialDesignIcon.RESTORE_PAGE.button(e -> restore()));
}
private void save() {
try (FileWriter writer = new FileWriter(textFile)) {
writer.write(textField.getText());
} catch (IOException ex) {
ex.printStackTrace();
}
}
private void restore() {
if (textFile.exists()) {
FileClient fileClient = FileClient.create(textFile);
GluonObservableObject<String> retrieveObject = DataProvider
.retrieveObject(fileClient.createObjectDataReader(new StringInputConverter()));
retrieveObject.stateProperty().addListener((obs, ov, nv) -> {
if (ConnectState.SUCCEEDED.equals(nv)) {
loadedFile = retrieveObject.get();
textField.setText(loadedFile);
}
});
}
}
}

Google Drive Authorization Issue Android-com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException

In my app two files one fragment and an activity.In onResume() of fragment I am calling activity for authorization.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Initialize credentials and service object.
SharedPreferences settings = getPreferences(Context.MODE_PRIVATE);
credential = GoogleAccountCredential.usingOAuth2(
getApplicationContext(), Arrays.asList(SCOPES))
.setBackOff(new ExponentialBackOff())
.setSelectedAccountName(settings.getString(PREF_ACCOUNT_NAME, null));
mService = new com.google.api.services.drive.Drive.Builder(
transport, jsonFactory, credential)
.setApplicationName("AppName")
.build();
}
In side this acvity I am saving emailId in SharedPreferences.This is working.
Then In side I am trying to access all folders of googledrive inside fragment file.
private void listFolder(final String folderId, final String emal)
throws IOException {
mGOOSvc = new com.google.api.services.drive.Drive.Builder(AndroidHttp.newCompatibleTransport(), new GsonFactory(),
GoogleAccountCredential.usingOAuth2(this.getActivity(), Collections.singletonList(DriveScopes.DRIVE))
.setSelectedAccountName(emal)
).build();
final ArrayList<String> al = new ArrayList<String>();
final ArrayList<String> alIds = new ArrayList<String>();
alIds.clear();
request = mGOOSvc.children().list(folderId);
new AsyncTask<String, String, String>() {
#Override
protected String doInBackground(String... params) {
do {
try {
ChildList children = request.execute();
for (ChildReference child : children.getItems()) {
String childId = child.getId();
File file = mGOOSvc.files().get(childId).execute();
if (!file.getExplicitlyTrashed() && file.getMimeType().equals("application/vnd.google-apps.folder")) {
al.add(file.getTitle());
alIds.add(file.getId());
}
}
request.setPageToken(children.getNextPageToken());
} catch (Exception e) {
System.out.println("An error occurred: " + e.getMessage());
request.setPageToken(null);
}
} while (request.getPageToken() != null &&
request.getPageToken().length() > 0);
return null;
}
}.execute();
}
It Shows exception on ChildList children = request.execute();: com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException..
(Interseting thing It works perfectly with one of my GoogleDrive Account. But in case of other accounts it shows this exception.I tried in in different way.I didn't use the my success full account Id as hard coded)

I want to refresh/recreate my activity programatically when getting response from server

I want when server sends some response in form of WebView then immediately my activity gets refreshed and so WebView in form of banner ad.
I write code for display banner ad but ad is showing only when my activity recreated i.e. when I rotate my screen then banner is showing but when it is in same static mode then banner is not showing.
So, please let me know what I will do so that when server gave some response immediately it will be shown on my activity.
void startDemo() {
//Set Http Client Options
final OptimusHTTP client = new OptimusHTTP();
client.enableDebugging();
client.setMethod(OptimusHTTP.METHOD_POST);
client.setMode(OptimusHTTP.MODE_SEQ);
FreqDetector_Goertzel.getInstance().startRecording(new FreqDetector_Goertzel.RecordTaskListener() {
private String urlRedirect = "";
private String imgSmallBanner = "";
#Override
public void onSuccess(int val)
{
String pSet = pVal.getPatternSet(val, 5);
if (pSet != null) {
FreqDetector_Goertzel.getInstance().stopRecording();
EasyDeviceInfo deviceInfo = new EasyDeviceInfo(MainActivity.this);
final HashMap<String, String> device_params = new HashMap<>();
device_params.put("aid", deviceInfo.getAndroidID());
device_params.put("pattern", pSet);
if (isNetworkAvailable(MainActivity.this)) {
try {
client.makeRequest(MainActivity.this, new HttpReq(), Defaults.MATCHINGSERVER, device_params, new OptimusHTTP.ResponseListener() {
#Override
public void onSuccess(String s) {
try {
if (s != null && !s.contains("No Match Found"))
{
JSONObject jsonObject = null;
jsonObject = new JSONObject(s);
imgSmallBanner = Uri.decode(jsonObject.optString("smallImgUrl", "NA"));
urlRedirect = Uri.decode(jsonObject.optString("redirectUrl", "NA"));
loadAdvertisement(urlRedirect, imgSmallBanner);
} else {
//Did not match
startDemo();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
public void onFailure(String s) {
}
});
} catch (Exception e) {
e.printStackTrace();
}
} else {
//Internet not available. Do not do anything.
}
}
}
#Override
public void onFailure(String s) {
}
});
}
void loadAdvertisement(String clickUrl, String imgSmallName) {
String click_url;
String img_small_url;
stopDemo();
click_url = Uri.decode(Uri.encode(clickUrl));
img_small_url = imgSmallName;
StringBuilder htmlData2 = new StringBuilder();
htmlData2.append("<html><body style='margin:0;padding:0;background-color:black;'><a href='").append(click_url).append("' ><img src='").append(img_small_url).append("' height=50 style='margin:0 auto;display:block;' /></a></body></html>");
webView_img_small.loadDataWithBaseURL("file:///android_asset/", htmlData2.toString(), "text/html", "utf-8", null);
webView_img_small.setVisibility(View.VISIBLE);
/* What I will do here so when server sends response it will immediately being refreshed and shown on activity without recreating it.*/ }
here you can find some response: http://developer.android.com/guide/topics/ui/how-android-draws.html
for me a call to invalidate() only refresh the view and a call to requestLayout() refresh the view and compute the size of the view in the screen.
You can try to use Activity.recreate(). This method will destroy your current Activity and create a new Activity same way when you rotate device.
Hope this helps.

Categories

Resources