I'm using Expo's SecureStore to securely store a user identification respectively API key.
The app also sets up an Android Service that subscribes to the ACTION_SCREEN_ON intent. In this Service I need to access the API key that I've saved with SecureStore to perform authenticated API calls. What I've tried:
As described by the docs, SecureStore on Android uses SharedPreferences. This way I am able to get a value for the token from the default SharedPreferences, however it's encrypted as it should be.
I tried to use the implementation of SecureStore because I thought all the logic would already be there to get me the decrypted value. However, I'm unable to successfully use the module. getValueWithKeyAsync expects an implementation of ReadableArguments which operates on a Collection<String> and I don't understand where to get it from. Passing a new Collection, of course, misses relevant data.
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(!Intent.ACTION_SCREEN_ON.equals(intent.getAction())) return;
SecureStoreModule secureStoreModule = new SecureStoreModule(context);
Promise tokenPromise = new Promise() {
#Override
public void resolve(Object value) {
// Perform authenticated API call
}
#Override
public void reject(String code, String message, Throwable e) {
...
}
};
ReadableArguments readableArguments = new ReadableArguments() {
// How to correctly implement this or where to get the correct implementation from?
}
secureStoreModule.getValueWithKeyAsync("TOKEN", readableArguments, tokenPromise);
}
I'd appreciate anything guiding me in the right direction. If you can think of other solutions for secure storage in React Native and accessing this secure storage in custom native code, I'm open for suggestions.
Related
I'm currently building a small Social Media style App which leverages RxJava 2 and Firebase. I'm using MVP style architecture, and I've abstracted out my AuthService with an interface called AuthSource.
For simplicity's sake, I'll work with a Single method in my Service:
public class FirebaseAuthService implements AuthSource {
private FirebaseAuth auth;
private FirebaseAuth.AuthStateListener listener;
//initialization code
#Override
public Maybe<User> getUser() {
return Maybe.create(new MaybeOnSubscribe<User>() {
#Override
public void subscribe(final MaybeEmitter<User> e) throws Exception {
if (auth == null) {
auth = FirebaseAuth.getInstance();
}
if (listener != null) {
auth.removeAuthStateListener(listener);
}
listener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
FirebaseUser firebaseUser = firebaseAuth.getCurrentUser();
auth.removeAuthStateListener(listener);
if (firebaseUser != null) {
User user = new User(
firebaseUser.getDisplayName(),
firebaseUser.getEmail());
user.setUserId(firebaseUser.getUid());
Uri photoUrl = firebaseUser.getPhotoUrl();
if (photoUrl != null){
user.setProfilePhotoUrl(photoUrl.toString());
}
e.onSuccess(user);
} else {
e.onComplete();
}
}
};
auth.addAuthStateListener(listener);
}
}
);
}
}
interface AuthSource {
Maybe<User> getUser();
//Other methods etc.
}
Finally, I'll show my Presenter method which handles the call:
//from with a Presenter:
#Override
private void getUserData() {
disposableSubscriptions.add(
auth.getUser().subscribeOn(schedulerProvider.io())
.observeOn(schedulerProvider.ui())
.subscribeWith(
new DisposableMaybeObserver<User>() {
#Override
public void onError(Throwable e) {
view.makeToast(R.string.error_retrieving_data);
view.startDispatchActivity();
}
#Override
public void onComplete() {
}
#Override
public void onSuccess(User user) {
ProfilePagePresenter.this.currentUser = user;
view.setName(user.getName());
view.setEmail(user.getEmail());
if (user.getProfilePhotoUrl().equals("")) {
view.setDefaultProfilePhoto();
} else {
view.setProfilePhotoURI(user.getProfilePhotoUrl());
}
getUserProfileFromDatabase();
}
}
)
);
}
I realize the topic of the question is a bit general, so I'll try to narrow things down from here. The code I've posted above works insofar as I'm succesfully getting Data from Firebase's API using Create(). The problem is, I'm quite new to using RxJava 2, and I'm not certain what's going on under the hood here for garbage collection and memory leaks. I chose to use Observable.create() as per the RxJava 2 Docs:
"Provides an API (via a cold Observable) that bridges the reactive world with the callback-style world."
RxJava 2 Docs
Finally, the only proactive thing I'm doing at the moment to dispose of these Observables, is to call CompositeDisposable.clear() in my Presenter when events take the user to a new Activity.
Questions:
-Is it safe to assume that simply calling CompositeDisposable.clear() when the Presenter finishes, will handle my Garbage collection? (assuming I haven't created memory leaks in the rest of the code).
-If my understanding is correct, create() is a better option to use than fromCallable() in this case, as fromCallable() should be used for Synchronous events (i.e. not something like Firebase API callbacks)?
-Is it really as simple as just throwing my Asynchronous callbacks in Observable.create()? I'm terrified at how easy that is to do...
Is it safe to assume that simply calling CompositeDisposable.clear()
when the Presenter finishes, will handle my Garbage collection?
(assuming I haven't created memory leaks in the rest of the code).
It's a little trickier than this. Non-disposed Observable won't create memory leak if everything referenced by the Observable belong to the Activity scope. Both the producer and the consumer will be garbage collected alongside Activity. Memory leak may occur if you referenced resources that will survive the Activity, a provider instantiated at Application level for example. So if you want to use CompositeDisposable.clear() make sure to implement emitter.setCancellable() inside Observable.create() to dispose those leaky resources.
If my understanding is correct, create() is a better option to use
than fromCallable() in this case, as fromCallable() should be used for
Synchronous events (i.e. not something like Firebase API callbacks)?
create() use to be named fromAsync(). Use fromCallable() to wrap a synchronous method call, create() when wrapping callback code.
Is it really as simple as just throwing my Asynchronous callbacks in
Observable.create()? I'm terrified at how easy that is to do...
It is as easy ... if you take care of those pesky references outside of scope as mentioned at the first point.
Usually on Android, a memory leak involve the Context, which is big. Be sure to test your code. leakcanary is a great help for this matter.
Last, you could avoid doing the wrapping yourself by using an existing Firebase RxJava binding. Or take inspiration from them:
https://github.com/kunny/RxFirebase
https://github.com/ashdavies/rx-firebase
https://github.com/DariusL/RxFirebaseAndroid
https://github.com/ezhome/Android-RxFirebase
https://github.com/nmoskalenko/RxFirebase
https://github.com/VictorAlbertos/RxFcm
Calling clear will detach the subscriber - the code that reacts to the emitted events, from the Observable, and as a result the subscriber which is enclosed by the presenter/activity and has hard reference to it, will no longer be held by the observer and lived longer than the presenter/activity lifecycle.
But, beware, you still can cause leaks if your Observable itself contains references to your presenter/activity.
In either cases, leak will occur when you reference your activity/presenter by static or other object that lives in longer (for instance Application) context than your activity/presenter.
Indeed, create() method is the correct way to create Observable from async method (BTW, in RxJava1, there was a different obsolete way that called also create, but it was changed in RxJava2, so there will be no way of creating Observable wrongly, but that's a different story)
Well, you still need to make sure you obey to the Observable contract,
make sure that there will be terminal event (either onComplete/onError),
there will be no onNext after terminal event (onCompleted/onError), and backpressure (which is enforced with Flowable Observable)
I'm building an android app that access a server. I'm using a full google solution. The backend is in GAE and I'm using endpoints to expose my API, I'm also using GCM. I use the auto generate tools that are offered by android studio to get my classes.
In my app module I have a class called offer, this is where I put data to be sent to the server, I have also an AsyncTask class that allows to make the api call.
In my backend module I have the exposed API and I also I have a class offer from which the API is generated by android studio and app engine sdk.
Now my problem is I made an attempt, but it resulted in failure, its like the classes in app and backend are not compatible. Whereas they are the same, in fact the one in backend is a simple copy from the one in app, the difference is the "objectify" annotation that I added. Below are pieces from my code and screenshots of my project structure.
public class InsertOfferAsyncTask extends AsyncTask <Offer, Void, Boolean>{
private static OfferApi offer_service;
private Context context;
public InsertOfferAsyncTask(Context context) {
this.context = context;
}
protected Boolean doInBackground(Offer... offer) {
if (offer_service == null) {
OfferApi.Builder builder = new OfferApi.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), null)
.setRootUrl("https://flawless-snow-95011.appspot.com/_ah/api/");
offer_service = builder.build();
}
try {
offer_service.insert(offer[0]); //this where I make the actual API call, I know I shouldn't use Object, it was an attempt to make it work
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
This is a part from where I call the AsyncTask, which is the code above.
Log.i("offer", offer.getUsr_id());
Log.i("offer_id", String.valueOf(offer.getId()));
Log.i("offer_date", offer.getPost());
new InsertOfferAsyncTask(getActivity().getBaseContext()).execute(offer);
getActivity().finish();
All the code above is taken from my app module, the following is the endpoint code that code generated, I am posting only the part I make a call to.
#ApiMethod(
name = "insert",
path = "offer",
httpMethod = ApiMethod.HttpMethod.POST)
public Offer insert(Offer offer) {
ofy().save().entity(offer).now();
logger.info("Created Offer with ID: " + offer.getId());
return ofy().load().entity(offer).now();
}
What I need now is how I can use what I have to send my data to the server. I know that I can connect to the server, I tested.
This is the error message, that i get when I try to build.
Error:(233, 73) error: no suitable method found for execute(.model.Offer)
method AsyncTask.execute(Runnable) is not applicable
(actual argument .model.Offer cannot be converted to Runnable by method invocation conversion)
method AsyncTask.execute(backend.model.offerApi.model.Offer...) is not applicable
(argument type app.model.Offer does not conform to vararg element type backend.model.offerApi.model.Offer)
Any help?? should I use JSON (I doubt, the job is done by the auto-generated classes, as it is shown in the builder)
Could it be that you are using two different "Offer" objects
app.model.Offer and backend.model.offerApi.model.Offer?
The type backend.model.offerApi.model.Offer appears to be the one generated for your Endpoints API, you need to use that type everywhere on the client (android) side.
I believe that you should create a separate project that contains all classes that are shared between the android app and your api.
I have read several articles on this site, and several books about Handlers, Threads, HandlerThreads, Services, SyncAdapters, ContentProviders and on and on. There seems like a lot of different options and I don't know which is appropriate for my project.
I have a simple project that will connect to a simple REST web service when the app starts for the very first time. It will download some JSON data and show this in a list. The user may then edit this data, and after hitting "save" the app will send a POST to the web service with the updated data. The user may also instigate a "sync" manually which will check for any new data. Finally, the app should check the web service periodically to see if there's more data.
I started with a Content Provider but it seemed really overkill (and complicated) tho I'm sure it would eventually work. I then tried a Thread, but Android suggests using AsyncTask or Handlers instead. I have been playing around with them (putting them in a service), and both will do what I want (using a timer to initiate a sync every X minutes) but I don't know if this is the best way of handling this. I am worried because this project may grow to incorporate much more, and I don't want to choose an option that will limit me in the future, but I also don't want to invest tons of hours into something that's overkill.
Can anyone help?
Let's just start with what that whole keep it simple paradigm.
AsyncTask would be something like this:
public class MyAsyncTask extends AsyncTask<Void, Void, Data> {
public interface OnDone {
public void onDone(Data data);
}
private final OnDone mDone;
public MyAsyncTask(OnDone onDone) {
mDone = onDone;
}
public Data doInBackground(Void v) {
// Download and parse your JSON in the background
}
public void onPostExecute(Data data) {
mOnDone.onDone(data);
}
}
public class OnDoneImpl .... implements OnDone, Runnable {
...
// Just need a context in scope some how, an activity, the application whatever.
Context mContext;
public void onDone(Data data) {
updateList(data);
scheduleAgainInXMinutes(TIME_TILL_REFRESH);
}
public void scheduleAgainInXMinutes(long millis) {
// probably want to use an Alarm service but can always use a handler;
new Handler().postDelayed(this, millis);
}
public void run() {
new MyAsyncTask(this).execute();
}
}
I am using parse.com as my backend service for my Android application. I wish to make separation between my activities and parse, for this purpose I have created service class witch will bridge activities and parse (backend). Most parse functions are asynchronous and I don't really know how to handle them. For example if I want to login with a user I will call the service object that should execute login with parse login function. So here is my code in the activity:
LoginService login = new LoginService("username", "password");
login.login();
//from here it is not correct
if(login.getLoginStatus() == 2) {
//user loggedin
}...
and my service code is:
public LoginSrvice(String userName, String pass)
{
this.userName = userName;
this.pass = pass;
}
public void loginUser()
{
ParseUser.logInInBackground(userName, pass, new LogInCallback()
{
#Override
public void done(ParseUser user, ParseException e) {
if (user != null) {
logedIn = 1;
} else {
logedIn = 2;
}
}
});
}
public int getLoginStatus()
{
return logedIn;
}
My question is how should I do it right? how can i keep both activities and services separated but still wait for the response in the activity till the service class will get the callback from parse.
Thanks for the HELP in advance!
Well, I am not an Android developer, but in Java you can use the wait() notifiy() methods of objects for wait until something happens.
But take into consideration you can enter into in a race condition where you wait() after the notify() has been already called.
If a Service's lifecycle isn't tied to your Activity you can bind to it and then get a reference to the Service via the Binder object. The simplest communication method is to use a Messenger object in a way similar to this project.
In this particular instance, I assume you're waiting for the login before the user can use anything other than the login screen. You could probably perform the login in an AsyncTask or, even better, a Fragment/Loader model. In the appropriate callback method, you'd perform the post-login action.
I had a very similar question but for Parse and iOS. I posted the question here on SO along with the answer I found. You will probably find yourself writing Cloud Code in JavaScript for Parse. For that you will need to learn to use Promises. My solution to managing the asynchrony in iOS was to implement Promises in iOS. They allowed me to encapsulate my background Parse operations in a very clean way. The same trick may work for you.
It possible that the code I posted to GitHub will be of help, but it's in Objective-C.
-Bob
I'm not clear why you need an abstraction around Parse's API, but I would recommend something very simple. Parse's API already handles thread safety, so you can write your interface to query Parse state and KISS. I.e.
class UserAbstraction {
// You may find it useful to also use the callback object for other reasons.
public static void logIn(string userName, string password) {
ParseUser.logInInBackground(userName, password);
}
public static boolean isLoggedIn() {
return ParseUser.getCurrentUser() == null;
}
}
This is a follow up from Java Play! 2 - User management with cookies
from the zentask example
public class Secured extends Security.Authenticator {
#Override
public String getUsername(Context ctx) {
return ctx.session().get("email");
}
#Override
public Result onUnauthorized(Context ctx) {
return redirect(routes.Application.login());
}
// Access rights
public static boolean isMemberOf(Long project) {
return Project.isMember(
project,
Context.current().request().username()
);
}
public static boolean isOwnerOf(Long task) {
return Task.isOwner(
task,
Context.current().request().username()
);
}
}
For me this doesn't really makes sense.
User gets the following cookie. for example "email=test#test.com"
If I go to a "secured" page , zentask only checks if email is not null. How can this be secure?
The reason of sessions are to get load off the db. But with this approach he has to constantly check if the user has the rights to on a secured page.
For me it doesn't really makes sense. Why is there a function getUsername? And why is the return type a string?
I want to do somthing like this:
User logs in and gets a cookie which looks somthing like this "value=randomString"
Safe the user OBJECT in the cache for example Cache.set(randomstring,userObject);
Now if the visitor comes back I check if his randomstring is in my cache, if yes check if the User object in the cash has the rights to be on the secured page.
I was able to achieve this, just without the #Security.Authenticated() annotation.
Is it possible to achieve this with this annotation?
It is just a sample, nothing else. You don't need to store a email in the cookie. You can for an example save some hash to identify logged user, or do some other matching.
Samples are as simple as possible, changing it to more sophisticated scenarios lays on the developers side.
BTW of course all Play's cookies are signed and I really doubt if you'll be able to manually change it.