Unable to login with a specific user in FaunaDB - faunadb

It always worked before, but it is no longer working.
I have a rate limiting logic, but even if I clear all rate limiting data, it still happens. Only with a specific user.
I created another account on FaunaDB for testing purposes and a new database. If I restore the old database data to that new database, everything works!
So I recreated the entire database on the old FaunaDB account and the problem persists.
Is anyone experiencing something similar?
Is there any information in cache?
Login(Match(Index("accounts_by_email"), "email#email.com"), {
password: "secret",
})
/* returns
Error: [
{
"position": [],
"code": "authentication failed",
"description": "The document was not found or provided password was incorrect."
}
]
*/
The password is not incorrect. It works on the other FaunaDB account with the data restored.
./fdm -source path=backup -dest key={admin_key}

Yes, that was a temporary problem. I experienced it was well at a certain moment in my own Fwitter example. Our uniqueness detection didn't play well with code that created/updated/deleted things in one complex FQL flow which the code is doing :). I ticketed that and it should be fixed in the meantime.
It's good to know that the rate limiting in there was a bit me experimenting with events. It can also be written much simpler, I guess I was a bit to deep zoned and to be fair.. I just joined FaunaDB back then. I'm working on a skeleton app that will contain that simpler version. In the meantime here is the code:
Simpler rate limiting
import { rateLimiting } from '../../fauna-queries/helpers/errors'
import faunadb from 'faunadb'
/*
* Ideally we limit the amount of calls that come to Login.
*/
const q = faunadb.query
const {
If,
Epoch,
Match,
Index,
Collection,
Let,
Var,
Paginate,
Select,
TimeDiff,
Or,
GTE,
Abort,
Create,
IsEmpty,
Count,
LT,
Do,
Now,
Subtract
} = q
function AddRateLimiting(action, FqlQueryToExecute, Identifier, calls, perMilliseconds) {
const ExecuteAndCreateLog = Do(
Create(Collection('logs'), {
data: {
action: action,
identity: Identifier
}
}),
FqlQueryToExecute
)
return Let(
{
logsPage: Paginate(Match(Index('logs_by_action_and_identity_ordered_by_ts'), action, Identifier), {
size: calls
})
},
If(
Or(IsEmpty(Var('logsPage')), LT(Count(Select(['data'], Var('logsPage'))), calls)),
// If no logs exist yet, create one.
ExecuteAndCreateLog,
Let(
{
// the page looks like { data: [timestamp1, timestamp2,...]},
// we will retrieve the last timestamp of that page. If the pagesize would be 3, it would be the oldest of these 3 events.
// since the index is ordered from new to old.
timestamp: Select(['data', Subtract(calls, 1)], Var('logsPage')),
// transform the Fauna timestamp to a Time object
time: Epoch(Var('timestamp'), 'microseconds'),
// How long ago was that event in ms
ageInMs: TimeDiff(Var('time'), Now(), 'milliseconds')
},
If(
GTE(Var('ageInMs'), perMilliseconds),
// Then great we execute
ExecuteAndCreateLog,
// Else.. Abort! Rate-limiting in action
Abort(rateLimiting)
)
)
)
)
}
Blocking after faulty logins
I also separated blocking three faulty logins since I was kinda abusing that rate-limiting system for it. A few undefines in this code of course, it's just meant to give you an idea of how it looks for more info, keep an eye out for the skeletons + blogs to come out.
// Let's wrap some other functionality around the login.
const BlockThreeFaultyLogins = Do(
If(
GTE(Count(Match(Index('logs_by_action_and_identity'), 'faulty_login', email)), MAX_LOGIN_ATTEMPTS),
// Abort if exceeded
Abort(tooManyFaultyLogins),
// Else, just continue as usual!
Let(
{
login: LoginFQL
},
Do(
If(
Equals(false, Var('login')),
// if the login is faulty, we'll add a log entry
Create(Collection('logs'), {
data: {
action: 'faulty_login',
identity: email
}
}),
// Else, we will clean up the faulty_login logs
q.Map(
Paginate(Match(Index('logs_by_action_and_identity'), 'faulty_login', email)),
Lambda(['logRef'], Delete(Var('logRef')))
)
),
Var('login')
)
)
)
)

Related

How to use IF / ELSE in a method of Vue

Issue: This method is supposed to accomplish the following:
IF the user is NOT in a specific room already found inside joinedRooms then join them and make the room tab above active. (this part works fine as shown below as the if statement)
ELSE (which means the user is already joined to said room), then just take them to the active tab above.
Here is where I am confused. The code below in my eyes SHOULD work. However, it isnt, it seems to always run the IF statement regardless. What is the incorrect syntax being used.
methods: {
joinRoom(room) {
if (room != this.$store.state.rooms.joinedRooms) {
this.$store.dispatch(RoomTypes.JOIN_ROOM, room);
this.$store.dispatch(RoomTypes.CURRENT_ROOM, room);
this.$emit('onClose')
}
else if (room === this.$store.state.rooms.joinedRooms ) {
this.$emit('onClose')
}
}
},
EDIT: What I am realizing thanks to a comment below is I need to check if the room is part of the array joinedRooms How would I accomplish this
Thanks to #CherryDT, I was able to realize I needed to use includes as part of the if statement. The code should look as follows
methods: {
joinRoom(room) {
if (!this.$store.state.rooms.joinedRooms.includes(room)) {
this.$store.dispatch(RoomTypes.JOIN_ROOM, room);
this.$store.dispatch(RoomTypes.CURRENT_ROOM, room);
this.$emit('onClose')
}
else if (this.$store.state.rooms.joinedRooms.includes(room)) {
this.$store.dispatch(RoomTypes.CURRENT_ROOM, room);
this.$emit('onClose')
}
}
},

How to manage errors on vue

i'm not sure on how to handle errors and global errors in vue. It's not specifically about the code, it is about the logic.
What i mean is, at the moment i placed a global error handler in the vue, something like:
app.config.errorHandler = function (err, vm, info) {
notyf.error(
"Something went wrong. Please try again."
);
}
with this, every error that propagates up to the root will be shown to the user with a small popup.
This works great for unexpected errors.
What confuses me is how should i manage "expected fails", let me give you an example:
Let's take the standard "refreshToken" method that takes care of the jwt token refresh when it is expired.
So, to manage this i'll make an interceptor in the axios client, so that every time i get a 401, i'll try to refresh:
if everything works fine
i'll proceed with the request
otherwise
i'll redirect to the login.
So the simplified code should be something like:
api.interceptors.response.use(
async res => {
return res;
}
,
async err => {
const originalRequest = err.config;
if (err.response.status === 401) {
if (session.accessToken && !isRefreshing) {
isRefreshing = true;
const tokenRefreshed = await tryRefreshToken(api, session);
if (tokenRefreshed === true) {
isRefreshing = false;
return api(originalRequest);
}
else {
router.push({ name: 'auth-login' }); <---------------------------
return Promise.reject("Unable to refresh token. Need login."); <-----------
}
}
}
else {
return Promise.reject(err);
}
},
)
Now, looking at the arrows, once i see that i'm unable to refresh i redirect the user, and from a logical point of view, this means that i've "managed" the problem. But since i'm in a async method i've to return a rejected promise, that clearly propagates upward until it hit the global error handler and gets finally managed.
This looks strange to me because global handler should be hit only by "unexpected" exception, not from things that i've already managed.
Looking at the logical hirerarchy here we can see:
level-1 app ( where the global handler resides )
level-2 page component ( user.vue )
level-3 page method ( saveUser(user) )
level-4 module method ( userService.updateUser(user) )
level-5 axios method ( axios.patch(....) )
level-6 axios.interceptor
level-7 tryRefreshToken method
What's the correct way to "manage" this situation?
From my point of view redirecting the user to the login page because it wansn't able to refresh the token means that i've managed the problem, but i totally understand that i've a chain of methods waiting a promise response ( that must be fullfilled )
The solutions i came up with are:
SOLUTION 1)
At level 7 reject passing a particular standard error "unable to refresh token"
At level 3 wrap the await saveUser(user) in a try catch and in case of "unable to refresh error" manage the redirect there.
This should totally work but what does it mean? That every single time i've an axios call i've to manage a potential "unable to refresh error", this seems tremendously wrong.
SOLUTION 2)
At level 7 reject passing a particular standard error "unable to refresh token"
At level 1, in the global handler, perform a switch case and in case of "unable to refresh error" manage the redirect there.
This should totally work too, but why should i manage a problem so far away from where it manifested? ( It manifested in the level-7 and i'm actually managing it at level 1 ).
From my point of view the global handler should manage only unamanaged errors and errors should be taken care as soon as possible ( so at level 7 in this example ).
SOLUTION 3) ( i don't know how to implement it )
At level 7 i manage the problem ( like i'm doing ) and then i find a way to "abort" the whole upward chain so that, on the redirect everything waiting is aborted.
This looks "kind of logically correct" but i'm not sure it really is and i don't know how to do that.
Do you have any suggestion or consideration on the matter?
Someone can help me understand better how to proceed?
Thank you very much in advance
Have a nice day

Apple Media Library Access Permission retrieved programmatically

I would appreciated some help please even if this is maybe a trivial question.
I've written a SwiftUI app that reads the media library from the device and plays it depending on user settings. That is all fine.
The problem I have is that if you install the app for the first time, the user needs to grant permission to access the media library. This appears to be a system generated dialog but I cannot see which step in the also triggers it. I tried to have the access request be triggered code generated but that doesn't seem to trigger the pop up but it still only appears at a later stage in the app load process. The code seems to recognise though that the user reacted to the access request pop up and does select the correct switch case.
What it does not seem to do though is that it still can't read the media library. The MPMediaQuery returns nil.
My suspicion is that it somehow connected to the fact that the access request doesn't run on the main thread but I am not experienced enough in Swift programming to know what the problem is. I would be most grateful for some helpful hints.
Here is my code:
import MediaPlayer
import SwiftUI
import Foundation
class Library {
var artists : [Artist] = []
#EnvironmentObject var settings : UserSettings
var counter : Float = 0
init() {
switch MPMediaLibrary.authorizationStatus() {
case .authorized:
print("authorized")
case .denied:
print("denied")
return
case .notDetermined:
print("not determined")
MPMediaLibrary.requestAuthorization() { granted in
if granted != .authorized {
return
}
}
case .restricted:
print("restricted")
#unknown default:
print("default")
}
if MPMediaLibrary.authorizationStatus() == .notDetermined { return }
let filter : Set<MPMediaPropertyPredicate> = [MPMediaPropertyPredicate(value: MPMediaType.music.rawValue, forProperty: MPMediaItemPropertyMediaType)]
let mediaQuery = MPMediaQuery(filterPredicates: filter )
var artistsInCollection : [Artist] = []
guard let _ = mediaQuery.items?.count else { return }
for item in mediaQuery.items! {
//here I do something but that's not relevant to my question
}
self.artists = artistsInCollection
}
}

what make getCurrentPosition fail?

I made a simple website with javascript on it that calls to:
navigator.geolocation.getCurrentPosition(show_map, show_map_error);
I have put the website on the internet. I tried to open the website from different PCs (no GPS gadget) on different locations. One from my home, one from a friends office.
But the script does not always get a position.
What would be a problem?
Thank you.
The method is not guaranteed to return a position, especially if there is no GPS attached.
You could try getting a cached position instead. See the following from the API specification
// Request a position. We only accept cached positions, no matter what
// their age is. If the user agent does not have a cached position at
// all, it will immediately invoke the error callback.
navigator.geolocation.getCurrentPosition(successCallback,
errorCallback,
{maximumAge:Infinity, timeout:0});
function successCallback(position) {
// By setting the 'maximumAge' to Infinity, the position
// object is guaranteed to be a cached one.
// By using a 'timeout' of 0 milliseconds, if there is
// no cached position available at all, the user agent
// will immediately invoke the error callback with code
// TIMEOUT and will not initiate a new position
// acquisition process.
if (position.timestamp < freshness_threshold &&
position.coords.accuracy < accuracy_threshold) {
// The position is relatively fresh and accurate.
} else {
// The position is quite old and/or inaccurate.
}
}
function errorCallback(error) {
switch(error.code) {
case error.TIMEOUT:
// Quick fallback when no cached position exists at all.
doFallback();
// Acquire a new position object.
navigator.geolocation.getCurrentPosition(successCallback, errorCallback);
break;
case ... // treat the other error cases.
};
}
function doFallback() {
// No cached position available at all.
// Fallback to a default position.
}

DADiskEject causing problems with error code 12 (kDAReturnUnsupported)

I try to eject external USB drives and Disk Images after being unmounted in the following callback function:
void __unmountCallback(DADiskRef disk, DADissenterRef dissenter, void *context )
{
...
if (!dissenter)
{
DADiskEject(disk,
kDADiskEjectOptionDefault,
__ejectCallback,
NULL);
}
}
Unfortunately I get an error in __ejectCallback...
void __ejectCallback(DADiskRef disk, DADissenterRef dissenter, void * context)
{
if(dissenter)
{
DAReturn status = DADissenterGetStatus(dissenter);
if(unix_err(status))
{
int code = err_get_code(status);
...
}
}
}
The error code is 12 meaning kDAReturnUnsupported. I don't really know what is going wrong. Can anyone please comment on this? Does this mean disk images can not be ejected???
Many thanks in advance!!
The documentation is pretty unclear on this. Therefore, it's a good idea to look into the actual source code of the DARequest class to find out what causes the kDAReturnUnsupported response.
It reveals the following conditions that return a kDAReturnUnsupported response:
Does your DADisk instance represent the entire volume or not?
if ( DADiskGetDescription(disk, kDADiskDescriptionMediaWholeKey) == NULL )
{
status = kDAReturnUnsupported;
}
if ( DADiskGetDescription(disk, kDADiskDescriptionMediaWholeKey) == kCFBooleanFalse )
{
status = kDAReturnUnsupported;
}
Looking into the IO Kit documentation (for which DiscArbitation.framework is a wrapper for), we find that kDADiskDescriptionMediaWholeKey describes whether the media is whole or not (that is, it represents the whole disk or a partition on it), so check that you're ejecting the entire disc and not a partition. Remember, you can unmount a partition, but you can't eject it. (that wouldn't make sense)
Is the disc mountable?
Another condition in DARequest.c is whether the volume is mountable or not, so make sure it is:
if (DADiskGetDescription(disk, kDADiskDescriptionVolumeMountableKey) == kCFBooleanFalse )
{
status = kDAReturnUnsupported;
}
Is the DADisk instance's name valid?
A third check validates the volume's name. Some system provided (internal) volumes don't have a name and can't be ejected. The check is very simple and simply looks for any name, so this shouldn't be a big deal.
if (DARequestGetArgument2(request) == NULL)
{
status = kDAReturnUnsupported;
}
Go through these three checks and see if they apply to you. This way you're bound to find out what's wrong.