Unable to Update User: UserCannotBeAlteredWithoutSessionError - swift

Greetings from a Parse Neophyte:
Task: Update current user's attributes (in Parse's User table).
Problem: Received the 'UserCannotBeAlteredWithoutSessionError' error.
Here's my code:
func updateParseUser(newUser:User, sender:UIViewController) {
let currentUser = PFUser.currentUser()
if ((currentUser) == nil) {
return
}
if let location = newUser.location {
currentUser["location"] = location
}
if let phone = newUser.phoneNumber {
currentUser["phone"] = phone
}
currentUser["displayName"] = "Turkey"
PFUser.currentUser().save()
}
Result:
Error: Parse::UserCannotBeAlteredWithoutSessionError (Code: 206, Version: 1.5.0)
Do I need to create a session or something?
Remedy?

Update your SDK. I had the exact same issue. When I updated to 1.6.0 the issue resolved itself.

Related

Firestore crashes while trying to create a document

I have a problem with a FireStore, hope some of you could help me.
I'm trying to create a document this way:
class FireStoreUtils: NSObject {
static let defaultUtils = FireStoreUtils()
var db = Firestore.firestore()
var fireStoreSettings = FirestoreSettings.init()
override init() {
super.init()
fireStoreSettings.host = FireStoreParameters.host
fireStoreSettings.isSSLEnabled = FireStoreParameters.sslEnabled
fireStoreSettings.isPersistenceEnabled = FireStoreParameters.persistenceEnabled
fireStoreSettings.cacheSizeBytes = Int64(FireStoreParameters.cacheSizeBytes)
db.settings = fireStoreSettings
}
weak var delegate:FireStoreUtilsDelegate?
func addNewUser(userData userDictionary: [String: Any],userId uId: String) {
do {
let table = self.db.collection("Collection_name")
let documentRef = table.document(uId)
try? documentRef.setData(userDictionary, completion: { (error) in
if (error != nil) {
self.delegate?.didFailToPerformOperation(errorMessage: error?.localizedDescription)
}
else {
self.delegate?.didSucceedToPerformOperation(message: "Success")
}
})
}
catch let error {
self.delegate?.didFailToPerformOperation(errorMessage: error.localizedDescription)
}
}
But from some reason executing setData I get the following crash
assertion failed: 0 == pthread_setspecific(tls->key, (void)value)*
I tried to use FireStore logs but the last log message I got is
2021-01-17 18:55:12.114707+0200 7.3.0 - [Firebase/Firestore][I-FST000001] Creating Firestore stub.
I added Firestore manually and din't use nor Swift PM or Pods, because both of the didn't work with FirebaseAuth in pod file.
It starts to look like everything is dead end.
If somebody knows what's going on or got similar problem, please,help!
Thank you,
Maria.

ASWebAuthentication and SFAuthentication login problem after logout on iOS 11 and iOS 12, not able to invalidate session

I am using ASWebAuthentication and SFAuthenticationto authenticate on a OAuth2 server with grant_type : authorization_code.
Everything work perfect except of:
user login successfully
Logout by revoking access token and refresh token with status code :200
Tested that the revocation works <------
User press login again and opens ASWebAuthentication or SFAuthentication according the iOS version and just goes directly in the app like the session is validating that the tokens are valid somehow.
On iOS 13 ASWebAuthentication provides prefersEphemeralWebBrowserSession = true which solves the issue but for iOS 11/12 it looks like it is nothing I can do (except that the issue is probably on BackEnd)
When I am logging in I am passing the parameters prompt:login but still it doesn't help.
Questions
Is there something that I can do to invalidate the session on ASWebAuthentication and SFAuthentication on iOS 11/12 similar to iOS 13 prefersEphemeralWebBrowserSession? (I haven't found something on the documentation. Apple doesn't allow anything)
Is this an issue that can be solved on frontend (iOS) or it is a backend issue?
Thank you
Providing the code just for documentation
print("Auth-Login : Process: Authenticate user")
let state = String().createState(length: 4)
let codeVerifier = String().createCodeVerifier()
let codeChallenge = codeVerifier.pkceEncode.base64UriEncode
let parameters = ["state=\(state)", "code_challenge=\(codeChallenge)"]
let url = createUrl(parameters: parameters)
guard let authURL = url else { return }
DispatchQueue.main.async {
self.delegate?.removeLoader()
if #available(iOS 12.0, *) {
print("Auth-Login : Process: Run ASWebAuthenticationSession")
self.webAuthSession = ASWebAuthenticationSession(url: authURL, callbackURLScheme: "no.bilkollektivet.app") { (callbackUrl, error) in
print(callbackUrl)
if let error = error {
completionHandler(nil, nil, error)
} else {
let result = self.getCodeFromCallbackUrl(url: callbackUrl, state: state)
completionHandler(result.code, codeVerifier, result.error)
}
}
if #available(iOS 13.0, *) {
self.webAuthSession.presentationContextProvider = self
self.webAuthSession.prefersEphemeralWebBrowserSession = true
}
self.webAuthSession.start()
} else {
print("Auth-Login : Process: Run SFAuthenticationSession")
self.sfAuthSession = SFAuthenticationSession(url: authURL, callbackURLScheme: "no.bilkollektivet.app") { (callbackUrl, error) in
if let error = error {
completionHandler(nil, nil, error)
} else {
let result = self.getCodeFromCallbackUrl(url: callbackUrl, state: state)
completionHandler(result.code, codeVerifier, result.error)
}
}
self.sfAuthSession.start()
}
}

How to get an array of CNGroup from a CNContainer using CNContactStore?

I'm looking for a way to get a list of groups (CNGroup) that relate to a contact container (CNContainer). When I use a predicate it fails.
The code I'm using is
func populateGroups(tableView:NSTableView,container:CNContainer){
print("populateGroups.start")
print(container.name)
print(container.identifier)
let contactStore = CNContactStore()
do {
let groupsPredicate = CNGroup.predicateForGroups(withIdentifiers: [container.identifier])
groups = try contactStore.groups(matching: groupsPredicate)
groupNames.removeAll();
for group:CNGroup in groups {
self.groupNames.append(group.name)
}
tableView.reloadData()
} catch {
print( "Unexpected error fetching groups")
}
print("populateGroups.finish")
}
I'm getting an error from that doesn't make sense to me.
The line groups = try contactStore.groups(matching: groupsPredicate) causes an error.
[Accounts] Failed to update account with identifier 47008233-A663-4A52-8487-9D7505847E29, error: Error Domain=ABAddressBookErrorDomain Code=1002 "(null)"
Which is confusing as I'm not updating any account.
If I change that line of code to groups = try contactStore.groups(matching: nil)
I get all the groups for all the containers.
How do you create a predicate that will return all the CNGroups that belong to a CNContactContainer?
I worked around this by checking that each group from all the groups belonged to the container in question using CNContainer.predicateForContainerOfGroup
func populateGroups(tableView:NSTableView,container:CNContainer){
let contactStore = CNContactStore()
do {
let groups:[CNGroup] = try contactStore.groups(matching: nil)
self.groups.removeAll();
groupNames.removeAll();
for group:CNGroup in groups {
let groupContainerPredicate:NSPredicate = CNContainer.predicateForContainerOfGroup(withIdentifier: group.identifier)
let groupContainer:[CNContainer] = try contactStore.containers(matching: groupContainerPredicate)
if( groupContainer[0].identifier == container.identifier) {
self.groupNames.append(group.name)
self.groups.append(group)
}
}
tableView.reloadData()
} catch {
print( "Unexpected error fetching groups")
}
}

Firebase audience based on user properties

I need to test some features of my app with just a previously selected group of users.
I created an Audience where user_id exactly matches 123456. 123456 being my own ID.
In Remote Config I created a Condition that matches users in the Audience above.
Then I created a parameter in Remote Config called feature_available and for the condition, I set a return value of true. The Default value is false.
In my app I set up Firebase:
FIRApp.configure()
let remoteConfig = FIRRemoteConfig.remoteConfig()
if let remoteConfigSettings = FIRRemoteConfigSettings(developerModeEnabled: false) {
remoteConfig.configSettings = remoteConfigSettings
}
remoteConfig.setDefaultsFromPlistFileName("FirebaseRemoteConfigDefaults")
And set the user ID:
FIRAnalytics.setUserID("123456")
Then I fetch from Firebase:
var expirationDuration: Double
// If in developer mode cacheExpiration is set to 0 so each fetch will retrieve values from the server.
expirationDuration = remoteConfig.configSettings.isDeveloperModeEnabled ? 0 : 3600
remoteConfig.fetch(withExpirationDuration: TimeInterval(expirationDuration)) { (status, error) -> Void in
if status == .success {
remoteConfig.activateFetched()
} else {
assertionFailure("Firebase config not fetched. Error \(error!.localizedDescription)")
}
}
The last thing I do is to get the value from Firebase and check if I have the feature enable:
let featureIsAvailable = remoteConfig["feature_available"].boolValue
if featureIsAvailable { ... }
The problem is that every single time the value returns from Firebase it is false and I can't manage to get it to return the correct value that matches that Audience I created.
I also tried to do it setting a user property instead of using setUserID() and had the same result.
Any suggestions?
I've run into similar issues before, sometimes it can take a while for the fetch to finish. The check if the feature is available needs to be done when the config is successfully fixed. Something like this hopefully works for you as well:
var featureIsAvailable : Bool?
override func viewDidLoad() {
super.viewDidLoad()
configureRemoteConfig()
fetchConfig()
}
func configureRemoteConfig() {
remoteConfig = FIRRemoteConfig.remoteConfig()
// Create Remote Config Setting to enable developer mode.
// Fetching configs from the server is normally limited to 5 requests per hour.
// Enabling developer mode allows many more requests to be made per hour, so developers
// can test different config values during development.
let remoteConfigSettings = FIRRemoteConfigSettings(developerModeEnabled: true)
remoteConfig.configSettings = remoteConfigSettings!
remoteConfig.setDefaultsFromPlistFileName("RemoteConfigDefaults")
}
func fetchConfig() {
var expirationDuration: Double = 3600
// If in developer mode cacheExpiration is set to 0 so each fetch will retrieve values from
// the server.
if (self.remoteConfig.configSettings.isDeveloperModeEnabled) {
expirationDuration = 0
}
// cacheExpirationSeconds is set to cacheExpiration here, indicating that any previously
// fetched and cached config would be considered expired because it would have been fetched
// more than cacheExpiration seconds ago. Thus the next fetch would go to the server unless
// throttling is in progress. The default expiration duration is 43200 (12 hours).
remoteConfig.fetch(withExpirationDuration: expirationDuration) { (status, error) in
if (status == .success) {
print("Config fetched!")
self.remoteConfig.activateFetched()
let featureIsAvailable = self.remoteConfig["feature_available"]
if (featureIsAvailable.source != .static) {
self.featureIsAvailable = featureIsAvailable.boolValue
print("should the feature be available?", featureIsAvailable!)
}
} else {
print("Config not fetched")
print("Error \(error)")
}
self.checkIfFeatureIsAvailable()
}
}
func checkIfFeatureIsAvailable() {
if featureIsAvailable == false {
// Don't show new feature
} else {
// Show new feature
}
}
I sent an email to the Firebase team requesting support and they told me that the issue was a bug in Xcode 8(.0 and .1) using Swift.
Updating to the latest version released today, 8.2, fixed the issue.

How to update both Email and Password with new Firebase in swift

I'm developing app with new firebase from google.
And I'm having problem with updating user email and password.
Here's what I've tried.
let currentUser = FIRAuth.auth()?.currentUser
currentUser?.updateEmail(email) { error in
if let error = error {
print(error)
} else {
// Email updated.
currentUser?.updatePassword(password) { error in
if let error = error {
} else {
// Password updated.
print("success")
}
}
}
}
But when updating password this occurs error like this.
"Domain=FIRAuthErrorDomain Code=17014 "This operation is sensitive and requires recent authentication..."
As I know we have to re-configure user after updating email.
I tried with this code for re-cofiguring from the firebase.
let user = FIRAuth.auth()?.currentUser
var credential: FIRAuthCredential
// Prompt the user to re-provide their sign-in credentials
user?.reauthenticateWithCredential(credential) { error in
if let error = error {
// An error happened.
} else {
// User re-authenticated.
}
}
But this occurs error
Variable 'credential' used before being initialed
I know this is because I don't initialize 'credential' variable but I don't know how to fix this to work.
Is there anybody who knows solution?
In your edit you didn't initialize your FIRAuthCredential ... it should be var credential = FIRAuthCredential() or simply use it like below code
let credential = FIREmailPasswordAuthProvider.credentialWithEmail(email, password: password)
user?.reauthenticateWithCredential(credential) { error in
if let error = error {
// An error happened.
} else {
// User re-authenticated.
}
}