Realm Object Server Swift, changing default permission of a realm - swift

I created a realm with an admin account and when i look at my dashboard my realm is there. Its owner column is blank though? Is it normal? Because I opened that synced realm with my admin account.
My main question is this, in default permissions it says "no access". I tried to give all users permission to write in that realm shown in below:
SyncUser.logIn(with: admin, server: serverURL) { (user, error) in
let permission = SyncPermissionValue(realmPath: "realm://myServerIp/swipeItApp/", username: "*", accessLevel: .write)
user?.applyPermission(permission, callback: { (error) in
if error != nil {
print(error?.localizedDescription)
} else {
print("success")
}
})
}
but neither error or success prints. What is wrong in my code? Thanks!

Thanks for using Realm.
The reason you are not seeing the callback is because you are running the applyPermission() method directly in the logIn() callback. The applyPermission() method has to be run on a thread with an active run loop, and the logIn() callback runs on threads without run loops managed by a background queue.
To fix this problem, use DispatchQueue.main.async to dispatch your code back onto the main queue:
SyncUser.logIn(with: admin, server: serverURL) { (user, error) in
let permission = SyncPermissionValue(realmPath: "realm://myServerIp/swipeItApp/", username: "*", accessLevel: .write)
DispatchQueue.main.async {
user?.applyPermission(permission, callback: { (error) in
if error != nil {
print(error?.localizedDescription)
} else {
print("success")
}
})
}
}
We consider the need to use DispatchQueue.main.async for this use case a design mistake and will be changing the way logIn() works in our upcoming Realm 3.0.0 release to run the callback on the main queue by default. So if you upgrade to Realm 3.0.0 once it's released you will no longer need to use the workaround I detailed above; your original code should work as-is.

Related

swift: How to keep ios user logged in using mongoDB Realm database and authentication

I want to keep user logged and not need to show login form everytime they open the app. I am using MongoDB Realm for database and authentication.
Right now the login works fine but it's required everytime the app is opened.
this my login code
#objc func signUp() {
setLoading(true);
app.usernamePasswordProviderClient().registerEmail(username!, password: password!, completion: {[weak self](error) in
// Completion handlers are not necessarily called on the UI thread.
// This call to DispatchQueue.main.sync ensures that any changes to the UI,
// namely disabling the loading indicator and navigating to the next page,
// are handled on the UI thread:
DispatchQueue.main.sync {
self!.setLoading(false);
guard error == nil else {
print("Signup failed: \(error!)")
self!.errorLabel.text = "Signup failed: \(error!.localizedDescription)"
return
}
print("Signup successful!")
// Registering just registers. Now we need to sign in, but we can reuse the existing username and password.
self!.errorLabel.text = "Signup successful! Signing in..."
self!.signIn()
}
})
}
#objc func signIn() {
print("Log in as user: \(username!)");
setLoading(true);
app.login(withCredential: AppCredentials(username: username!, password: password!)) { [weak self](maybeUser, error) in
DispatchQueue.main.sync {
self!.setLoading(false);
guard error == nil else {
// Auth error: user already exists? Try logging in as that user.
print("Login failed: \(error!)");
self!.errorLabel.text = "Login failed: \(error!.localizedDescription)"
return
}
guard let user = maybeUser else {
fatalError("Invalid user object?")
}
print("Login succeeded!");
self?.navigationController?.pushViewController(hostingController, animated: true)
}
this is my app rootView where I want to check and keep the user logged in
struct AppRootView: View {
var body: some View {
AnyView {
// check if user has already logged in here and then route them accordingly
if auth.token != nil {
homeMainView()
} else {
LoginController()
}
}
}
}
how can I keep user login with MongoDB realm?
From what I understand*, once a user authenticates, they will stay authenticated 'logged in' on that device until they are manually logged out, keeping in mind that once they are logged out their access token remains active for 30 minutes.
Two things from the guide
The access token for a session expires after thirty minutes. However,
a new session can be started by retrieving a new access token from
MongoDB Realm using the refresh token. (Important ->) The SDKs automatically take
care of refreshing access tokens, so you do not need to worry about
this when implementing client applications.
and
MongoDB Realm handles the access tokens and refresh tokens that
comprise a user session automatically.
What we are doing, which appears to be working ok, is this: When the app opens, we call a func handleSignIn which checks to see if the app has a .currentUser. If so, then we configure Realm. If not, a login/signup view is presented. Here's a snippit
func handleSignIn() {
if let _ = gTaskApp.currentUser() {
print("user is logged in")
self.configRealmSync()
} else {
print("not logged in; present sign in/signup view")
with gTaskApp being a global reference to our app
let gTaskApp = RealmApp(id: Constants.REALM_APP_ID)
*This is a work in progress so please feel free to correct me

Firebase signIn not running

I am trying to login to a firebase user through swift code. However, it seems like the code to do so is being completely skipped over. The callback is not being run at all. I have added the dependencies to my Podfile, ran pod install, and the modules show up in Xcode.
pod 'Firebase', '6.15.0'
pod 'Firebase/Auth'
I import Firebase in my file. I also have tried including import FirebaseAuth as well but with no effect, likely because it is implicitly imported with Firebase. Here is the code where I sign in:
Auth.auth().signIn(withEmail: "fake#email.com", password: "fakepassword123") { (user, error) in
if let error = error {
print(error.localizedDescription)
}
else if let user = user {
print(user)
}
}
However, again, this is seemingly just skipped over because the body of the callback is not being run. Shouldn't the callback run regardless, with either a result or an error? Any ideas? Thanks.
Edit: Also, if it helps, I at one point had a simple print statement at the start of the block to see if it was running and the print statement did not fire.
Try this:
Auth.auth().signIn(withEmail: "fake#email.com", password: "fakepassword123") { (user, error) in
if let error = error {
print(error.localizedDescription)
}
else {
print(user)
}
}
If this doesn't work let me know and we can keep troubleshooting, but this is exactly what I use and it works perfectly.

Swift: Proper Firebase error-handling

I'm not able to understand why neither print lines are executed when running the following code:
ref.child("schools/\(schoolTextField.text!)/settings/pin").observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot.value)
}, withCancel: { (error) in
print(error.localizedDescription)
})
It used to work, until I made some changes regarding firebase authentication, but I don't see why the withCancel block is not executed!
How do I catch whatever error is occuring here? No error-message is printed in the log.
EDIT:
I found a similar question here which suggests that the problem might be related to the authentication after all. In appDelegate's didFinishLaunchingWithOptions I check if the user auth-token exists in Firebase Auth:
Auth.auth().currentUser?.getIDTokenForcingRefresh(true, completion: { (response, error) in
guard error == nil, let uid = response else {
print(error)
return
}
...
})
In current case there is an error, which is printed:
Error Domain=FIRAuthErrorDomain Code=17011 "There is no user record corresponding to this identifier. The user may have been deleted."
I'm now also getting these errors printed in the log:
[Common] _BSMachError: port b43b; (os/kern) invalid capability (0x14) "Unable to insert COPY_SEND"
[Common] _BSMachError: port b43b; (os/kern) invalid name (0xf) "Unable to deallocate send right"
Try this way:
if let snapshot = snapshot.children.allObjects as? [DataSnapshot] {
for snap in snapshots {
print("SNAP: \(snap)")
}
Also The error code 17011 is a user not found error see FIRAuthErrorCode for more info also it's better you create a Dataservice class to handle your interaction with firebase see Creating A Reusable Firebase Data Service for more info.

How to check if user needs to re-authenticate using Firebase Authentication

I am using Firebase to log in users into my app, but when I am adding the capability to manage their account like changing their email, password and so on. The documentation says that if the user have not recently signed in they need to re-authenticate, but my question is: How can I check if the user have signed in recently or not? According to the docs the error will return FIRAuthErrorCodeCredentialTooOld, but how can I check this?
Swift 3
I had to do this yesterday when trying to delete a user. One thing to note is FIRAuthErrorCodeCredentialTooOld is now FIRAuthErrorCode.errorCodeRequiresRecentLogin
What I did was trigger a UIView to ask for log in details if that error is thrown. Since I was using email and password, that's what I collected from the user in my example.
private func deleteUser() {
//get the current user
guard let currentUser = FIRAuth.auth()?.currentUser else { return }
currentUser.delete { (error) in
if error == nil {
//currentUser is deleted
} else {
//this gets the error code
guard let errorCode = FIRAuthErrorCode(rawValue: error!._code) else { return }
if errorCode == FIRAuthErrorCode.errorCodeRequiresRecentLogin {
//create UIView to get user login information
let loginView = [yourLoginUIViewController]
self.present(loginView, animated: true, completion: nil)
}
}
}
Once I had the login information I ran this function to reauthenticate the user. In my case I ran it the loginView in the above code if the login in was successful:
func reauthenticateUserWith(email: String, password: String) {
FIRAuth.auth()?.signIn(withEmail: email, password: password) { (user, error) in
if error == nil {
//display UIView to delete user again
let deleteUserView = deleteUserView()
present(deleteUserView, animated: true, completion: nil)
} else {
//handle error
print(error!.localizedDescription)
}
}
}
The deleteUserView in my case calls deleteUser() on a button tap from the user. You can also use UIAlertController in place of the custom UIViews, but that's up to you.
Hope this helps.
Update for current Swift 5
let user = Auth.auth().currentUser
user?.delete { error in
if let error = error {
let authErr = AuthErrorCode(rawValue: error.code)
if authErr == .requiresRecentLogin {
// reauthenticate
}
// other error
} else {
// delete success
}
}
According to the documents, there is currently no way to check FIRAuthErrorCodeCredentialTooOld other than going through the deleting of the account or the other sensitive cases mentioned.
If you are like me and ended up here because you are trying to figure out how to handle removing someone from Auth and removing other user data in Cloud Firestore, Realtime Database, and/or Cloud Storage, then there is a better solution.
Check out the Delete User Data Extension from Firebase to handle this. In short, when a user profile is deleted from Auth, you can use this also to delete data associated with the uid from those other Firebase data storage tools.

In Quickblox is it possible to update the user password without reset?

I am attempting to change a user's password with the following code:
let updateParameters = QBUpdateUserParameters()
updateParameters.password = newPasswordField.text
QBRequest.updateCurrentUser(updateParameters, successBlock: { (response: QBResponse, user: QBUUser?) -> Void in
print("success")
}, errorBlock: { (response: QBResponse) -> Void in
print("error")
})
Upon debugging, I receive a 422 client error. I am assuming this is because QBUpdateUserParameters has a restriction on updating passwords.
I ran into a couple of answers where you could change the password with the old QBUUsers class but recent updates seemed to have removed the use of this class. Can someone point me in the right direction?
You also need to provide your old password:
updateParameters.oldPassword = ...