I am having a problem with Firebase Auth-UI user metadata - firebase

I am using Firebase Auth UI to register and store users in my app.
When the user is new in the app, I need to register some things, so I need to know when a user is new or not.
According to the documentation I am using the right way to check new users:
Auth-UI Metadata
The way I check to know wheter a user is new or not is comparing the metadata, user creation timestamp and Last Signed Timestamp and it worked perfect.
if (metadata.getCreationTimestamp() == metadata.getLastSignInTimestamp()){
//do some new user stuff
}else{
//log in old user
}
This code is not working right now, because they might have changed something.
The last time I am sure this code worked is the 30th of January.
There is a little difference in miliseconds between the creation timestamp and the sign in timestamp when the user is new:
Creation timestamp: 1549462011000 Last Sign in Timestamp: 1549462011028
I've tried in two different Firebase projects and the problem is the same.
Can anyone help?

I experienced the same problem with my app.
The two timestamps have now few milliseconds difference.
A way to fix it is to check the two timestamps are close enough ( 3 seconds in the code below)
val signUpInterval = 3000L
val isNewUser = Math.abs(metadata.creationTimestamp - metadata.lastSignInTimestamp) < signUpInterval

Related

is firebase data base realtime does delete Id it's self if user not active for several days?

i have these 3 methods
one listening to internet status
listenToInternet() {
FirebaseDatabase.instance.ref().child(currentUser.uid!).onDisconnect().set({
"activity": DateTime.now()
});
}
and one for manual get online when user open the app
getOnlineInResumedOrAtTheStartRun(){
FirebaseDatabase.instance.ref().child(currentUser.uid!).set({
'activity': "online",
});
}
and one for manual get offline when user close the app
getOfflineInInactive(){
FirebaseDatabase.instance.ref().child(currentUser.uid!).set({
'activity': DateTime.now(),
});
}
ok now everything going fine as well ..
but i noticed if user didn't open his account on the app for 4-5 days so his Id .child(currentUser.uid!) disappear from data base without any order from user , and if he open the app again so his .child(currentUser.uid!)show again in data base
note : i also noticed there is strange id get instead that one who disappeared !
Is there something I missed or does it happen normal in data base ? or i should chick my code again ?
thanks in advance
To answer your question, No, it doesn't delete users on its own. I have multiple applications that are not active more than two years from now and the users are still there. Make sure you are authenticating the users and then saving those in your Database.
In addition to this, define security rules from the console so as to keep your data secure.

Request.auth.metadata in security rules?

I have a Firebase project where I'd like for users to be able to see when other users created their profiles. My initial hope was that I could use "user.metadata.creationTime" on the frontend to pass the date into the user's extra info document and verify that it is correct by having "request.resource.data.datecreated == request.auth.metadata.creationTime" as a Database Rule, but it looks like it is not possible according to the documentation.
Is there any way I can verify that the creation date is correct on the backend?
More info edit: Below is the code that is being triggered when a user creates a new account on my profile. The three values are displayed publicly. I'm creating a niche gear for sale page so being able to see when a user first created their account could be helpful when deciding if a seller is sketchy. I don't want someone to be able to make it seem like they have been around for longer than they have been.
db.collection('users').doc(user.uid).set({
username: "Username-156135",
bio: "Add a bio",
created: user.metadata.creationTime
});
Firestore rules:
match /users/{id} {
allow get;
allow create, update: if request.resource.data.username is string &&
request.resource.data.bio is string &&
request.resource.data.created == request.auth.metadata.creationTime;
}
user.metadata.creationTime, according to the API documentation is a string with no documented format. I suggest not using it. In fact, what you're trying to do seems impossible since that value isn't available in the API documentation for request.auth.
What I suggest you do instead is use a Firebase Auth onCreate trigger with Cloud Functions to automatically create that document with the current time as a proper timestamp. Then, in security rules, I wouldn't even give the user the ability to change that field, so you can be sure it was only ever set accurately by the trigger. You might be interested in this solution overall.

How to prevent generation of the same OTPs in MVC 2FA

MVC 2FA sometimes generates the same OTP (I have set to 6 numericals) and when you generate multiple OTPs, one can use the previous OTP.
Is there a way to generate unique OTPs and disable the previous generated OTP?
string code = await UserManager.GenerateTwoFactorTokenAsync(user.Id, provider);
This is the time set before the OTP expires
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(2));
I just stumbled across this post today and found a simple solution to the problem.
https://www.stevejgordon.co.uk/asp-net-core-identity-token-providers
This link describes the fact that the SecurityTokenStamp is used in the verification process. So for me it was a simple matter of updating it each time I sent out an SMS token for the user. Effectively invalidating the original one.
if(await userManager.UpdateSecurityStampAsync(user.Id) != IdentityResult.Success)
{
// https://www.stevejgordon.co.uk/asp-net-core-identity-token-providers
// we update it to effectively reset all the token validation stuff
return IdentityResult.Failed("failed to update the security stamp");
}
// Send token - this may throw but thats ok as we just rollback
string code = await userManager.GenerateTwoFactorTokenAsync(user.Id, "twilio");
await userManager.SmsService.SendAsync(new Microsoft.AspNet.Identity.IdentityMessage
{
Destination = user.UserName,
Body = "Your security code is: " + code
});
The OTP which is generating via UserManager.GenerateTwoFactorTokenAsync is not a One Time Password even though we called it OTP. It is a TOTP ( Time based one time password).
https://en.wikipedia.org/wiki/Time-based_One-Time_Password
Therefore in a particular time period the generated passwords can be slimier.
For SMS and Email I have noticed that the time period is around 90 seconds. That means within 90 seconds it generates the same password.
For authenticator app also there is this default time period.
By doing lot of researches around this, What I have noticed is, to change this default time period we need to create a custom 2FA token provider.
OTP are time based and not recorded anywhere. If you generate 2 OTPs within a short period of time, you'll get identical strings. And this is how algorithm is working and there is no easy way around it.

Paypal Processing - Need to grab TransactionId, CorrelationId and TimeStamp

Current Project:
ASP.NET 4.5.2
MVC 5
PayPal API
I am using this example to build myself a PayPal transaction (and yes, my code is virtually identical), as I do not know of any other method that will return the three values in the title.
My main problem is that, the example I am utilizing is much more concise and compact than the one I used for a much older Web Forms application, and as such, I am unsure as to where or even how to grab the three values I need.
My initial thought was to do so right after the ACK, and indeed I was able to obtain the CorrelationId as well as the TimeStamp, but because this was prior to the user being carted off to PayPal’s site (sandbox in this case -- see the return new PayPalRedirect contained within the if), the TransactionId was blank. And in this example, PayPal explicitly redirects the user to a Success page without returning to the Action that sent the user to PayPal in the first place, and I am not seeing any GET values in the URL at all aside from the Token and the PayerId, much less ones that could provide me with the TransactionId.
Suggestions?
I have also looked at the following examples:
For ASP.NET Core, was unsure how to adapt to my current project particularly due to appsettings.json, but it looked quite well done. I really liked how the values were rolled up in lists.
For MVC 4, but I couldn’t find where ACK was being used to determine success or successwithwarning so I couldn’t hook into that.
I have also found the PayPal content to be like trying to drink from a fire hose at full blast -- not only was the content was hopelessly outdated (Web Forms code, FTW!) but there was also so many different examples it would have taken me days to determine which one was most appropriate to use.
Any assistance would be greatly appreciated.
Edit: my initial attempt at modifying the linked code has this portion:
values = Submit(values);
var ack = values["ACK"].ToLower();
if(ack == "success" || ack == "successwithwarning") {
using(_db = new ApplicationDbContext()) {
var updateOrder = await _db.Orders.FirstOrDefaultAsync(x => x.OrderId == order.OrderId);
if(updateOrder != null) {
updateOrder.OrderProcessed = false;
updateOrder.PayPalCorrelationId = values["CORRELATIONID"];
updateOrder.PayPalTransactionId = values["TRANSACTIONID"];
updateOrder.PayPalTimeStamp = values["TIMESTAMP"];
updateOrder.IPAddress = HttpContext.Current.Request.UserHostAddress;
_db.Entry(updateOrder).State = EntityState.Modified;
await _db.SaveChangesAsync();
}
}
return new PayPalRedirect {
Token = values["TOKEN"],
Url = $"https://{PayPalSettings.CgiDomain}/cgi-bin/webscr?cmd=_express-checkout&token={values["TOKEN"]}"
};
}
Everything within and including the using() is my added content. As I mentioned, the CorrelationId and the TimeStamp come through just fine, but I have yet to successfully obtain the TransactionId.
Edit 2:
More problems -- the transactions that are “successful” through the sandbox site (the ReturnUrl is getting called) aren’t reflecting properly on my Facilitator and Buyer accounts, even when I do payments straight from the buyer’s PayPal account (not using the Credit Card). I know I am supposed to see transactions in the Buyer’s account, either through the overall Dev account (Accounts -> Profile -> balance or Accounts -> Notifications) or through the Buyer’s account in the sandbox front end. And yet -- multiple transactions returning me to the ReturnUrl path, and yet no transactions in either.
Edit 3:
Okay, this is really, really weird. I have gone over all settings with a fine-toothed comb, and intentionally introduced errors to see where things should crap out. It turns out that the entire process goes swimmingly - except nothing shows up in my notifications and no amounts get moved between my different accounts (Facilitator and Buyer). It’s like all my transactions are going into /dev/null, yet the process is successful.
Edit 4: A hint!
In the sandbox, where Buyer accepts the transaction, there is a small note, “You will be able to review the transaction before completing it” or something like that -- suggesting that an additional page is not coming up and that the user is being uncerimoniously dumped back to the success page. Why the success page? No clue. But it’s happening.
It sounds like you are only doing the first part of the process.
Express Checkout consists of 3 API calls:
SetExpressCheckout
GetExpressCheckoutDetails
DoExpressCheckoutPayment
SEC generates a token, and then you redirect to PayPal where the user signs in and reviews the transactions before agreeing to pay.
They are then sent to the ReturnURL included in your SEC request, and this is where you'll call GECD in order to obtain all the buyer details that are now available since they signed in.
Using that data you can complete the final DECP request, which is what finalizes the procedure. No money is actually processed until this final call is completed successfully.

firebase more complex validation

I'm creating an angular app with firebase back end as an API.
People will be able to book appointments on a calendar but 2 persons CANNOT share the same hour slot. Furthermore, since appointments can start every half and hour, checking becomes a bit more complex.
Can I make firebase perform some more complex validation like that? It pretty much covers everything else I need and I'd hate to create something custom, only because of that feature!
Thanks!
If I am correct, you said you don't want to do the checking client-side. Sounds good. Here's what I would do:
When storing the appointments, I would name them based on their times. Client-side code:
var dataRef = new Firebase('https://example.firebaseio.com/');
dataRef.child('2014-6-9-0500').set('name'); // 5:00 6/9/2014 converted to a string
So the appointments will all be named based on their time, and their values will be equal to the name of the person being scheduled at that time. This will make it impossible for two people to be scheduled at the same time (because in Firebase, there cannot be two children with the same name).
In your security tab, check that the data doesn't already exist (to prevent over-writing existing appointments). Then, for the validate, you could check the appointment time and make sure it ends with either "00" or "30", and is 12 digits long. The rules would look something like this:
"rules": {
".read": true,
"$time": {
".write": "!data.exists()",
".validate": "$time.endsWith('00') || $time.endsWith('30')"
}
}
Although it's possible for a nonvalid time to be accepted (such as "0000-0-0-0030" or even "qt00"), a valid appointment which is submitted will not be scheduled at the same time as another appointment, and the appointments will be at times ending at ":00" or ":30" (half-hour intervals).
The only problem is if a person has an hour-long appointment starting at noon. You would have to schedule multiple appointments: one at 12:00, and another at 12:30. That could get a little annoying, but I don't know of any other way to do it.
In my understanding, it is possible with Firebase. However, Firebase does not have the dynamic querying capabilities like Mongo does. I believe you have to take a pretty primitive approach to solving this issue by doing something like:
db.child('calendar').once('value', function(snapshot){
var hours = snapshot.val();
// for each hour
// do validation here
})

Resources