From 58ed27fe9c866c044a9cb0f59a2d9c4a43a2ef79 Mon Sep 17 00:00:00 2001 From: Arnaud Dorgans Date: Sun, 9 Sep 2018 12:59:49 +0200 Subject: [PATCH] auth adds user, userProfileChangeRequest --- Sources/Auth/FIRUser+Rx.swift | 468 ++++++++++++++++++ .../Auth/FIRUserProfileChangeRequest+Rx.swift | 34 ++ 2 files changed, 502 insertions(+) create mode 100644 Sources/Auth/FIRUser+Rx.swift create mode 100644 Sources/Auth/FIRUserProfileChangeRequest+Rx.swift diff --git a/Sources/Auth/FIRUser+Rx.swift b/Sources/Auth/FIRUser+Rx.swift new file mode 100644 index 0000000..8aa49f4 --- /dev/null +++ b/Sources/Auth/FIRUser+Rx.swift @@ -0,0 +1,468 @@ +// +// FIRUser+Rx.swift +// RxFirebase +// +// Created by Arnaud Dorgans on 09/09/2018. +// + +import FirebaseAuth +import RxSwift + +extension Reactive where Base: User { + + /** + @brief Updates the email address for the user. On success, the cached user profile data is + updated. + @remarks May fail if there is already an account with this email address that was created using + email and password authentication. + + @param email The email address for the user. + @param completion Optionally; the block invoked when the user profile change has finished. + Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeInvalidRecipientEmail` - Indicates an invalid recipient email was + sent in the request. + + `FIRAuthErrorCodeInvalidSender` - Indicates an invalid sender email is set in + the console for this action. + + `FIRAuthErrorCodeInvalidMessagePayload` - Indicates an invalid email template for + sending update email. + + `FIRAuthErrorCodeEmailAlreadyInUse` - Indicates the email is already in use by another + account. + + `FIRAuthErrorCodeInvalidEmail` - Indicates the email address is malformed. + + `FIRAuthErrorCodeRequiresRecentLogin` - Updating a user’s email is a security + sensitive operation that requires a recent login from the user. This error indicates + the user has not signed in recently enough. To resolve, reauthenticate the user by + invoking reauthenticateWithCredential:completion: on FIRUser. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all FIRUser methods. + */ + public func updateEmail(to email: String) -> Observable { + return Observable.create { observer in + self.base.updateEmail(to: email) { error in + guard let error = error else { + observer.onNext(()) + observer.onCompleted() + return + } + observer.onError(error) + } + return Disposables.create() + } + } + + /** + @brief Updates the password for the user. On success, the cached user profile data is updated. + + @param password The new password for the user. + @param completion Optionally; the block invoked when the user profile change has finished. + Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeOperationNotAllowed` - Indicates the administrator disabled + sign in with the specified identity provider. + + `FIRAuthErrorCodeRequiresRecentLogin` - Updating a user’s password is a security + sensitive operation that requires a recent login from the user. This error indicates + the user has not signed in recently enough. To resolve, reauthenticate the user by + invoking reauthenticateWithCredential:completion: on FIRUser. + + `FIRAuthErrorCodeWeakPassword` - Indicates an attempt to set a password that is + considered too weak. The NSLocalizedFailureReasonErrorKey field in the NSError.userInfo + dictionary object will contain more detailed explanation that can be shown to the user. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all FIRUser methods. + */ + public func updatePassword(to password: String) -> Observable { + return Observable.create { observer in + self.base.updatePassword(to: password) { error in + guard let error = error else { + observer.onNext(()) + observer.onCompleted() + return + } + observer.onError(error) + } + return Disposables.create() + } + } + + #if os(iOS) + /** + @brief Updates the phone number for the user. On success, the cached user profile data is + updated. + + @param phoneNumberCredential The new phone number credential corresponding to the phone number + to be added to the Firebase account, if a phone number is already linked to the account this + new phone number will replace it. + @param completion Optionally; the block invoked when the user profile change has finished. + Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeRequiresRecentLogin` - Updating a user’s phone number is a security + sensitive operation that requires a recent login from the user. This error indicates + the user has not signed in recently enough. To resolve, reauthenticate the user by + invoking reauthenticateWithCredential:completion: on FIRUser. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all FIRUser methods. + */ + public func updatePhoneNumber(_ credential: PhoneAuthCredential) -> Observable { + return Observable.create { observer in + self.base.updatePhoneNumber(credential) { error in + guard let error = error else { + observer.onNext(()) + observer.onCompleted() + return + } + observer.onError(error) + } + return Disposables.create() + } + } + #endif + + /** + @brief Reloads the user's profile data from the server. + + @param completion Optionally; the block invoked when the reload has finished. Invoked + asynchronously on the main thread in the future. + + @remarks May fail with a `FIRAuthErrorCodeRequiresRecentLogin` error code. In this case + you should call `FIRUser.reauthenticateWithCredential:completion:` before re-invoking + `FIRUser.updateEmail:completion:`. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all API methods. + */ + public func reload() -> Observable { + return Observable.create { observer in + self.base.reload { error in + guard let error = error else { + observer.onNext(()) + observer.onCompleted() + return + } + observer.onError(error) + } + return Disposables.create() + } + } + + /** + @brief Renews the user's authentication tokens by validating a fresh set of credentials supplied + by the user and returns additional identity provider data. + + @param credential A user-supplied credential, which will be validated by the server. This can be + a successful third-party identity provider sign-in, or an email address and password. + @param completion Optionally; the block invoked when the re-authentication operation has + finished. Invoked asynchronously on the main thread in the future. + + @remarks If the user associated with the supplied credential is different from the current user, + or if the validation of the supplied credentials fails; an error is returned and the current + user remains signed in. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeInvalidCredential` - Indicates the supplied credential is invalid. + This could happen if it has expired or it is malformed. + + `FIRAuthErrorCodeOperationNotAllowed` - Indicates that accounts with the + identity provider represented by the credential are not enabled. Enable them in the + Auth section of the Firebase console. + + `FIRAuthErrorCodeEmailAlreadyInUse` - Indicates the email asserted by the credential + (e.g. the email in a Facebook access token) is already in use by an existing account, + that cannot be authenticated with this method. Call fetchProvidersForEmail for + this user’s email and then prompt them to sign in with any of the sign-in providers + returned. This error will only be thrown if the "One account per email address" + setting is enabled in the Firebase console, under Auth settings. Please note that the + error code raised in this specific situation may not be the same on Web and Android. + + `FIRAuthErrorCodeUserDisabled` - Indicates the user's account is disabled. + + `FIRAuthErrorCodeWrongPassword` - Indicates the user attempted reauthentication with + an incorrect password, if credential is of the type EmailPasswordAuthCredential. + + `FIRAuthErrorCodeUserMismatch` - Indicates that an attempt was made to + reauthenticate with a user which is not the current user. + + `FIRAuthErrorCodeInvalidEmail` - Indicates the email address is malformed. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all API methods. + */ + public func reauthenticateAndRetrieveData(with credential: AuthCredential) -> Observable { + return Observable.create { observer in + self.base.reauthenticateAndRetrieveData(with: credential) { result, error in + if let error = error { + observer.onError(error) + } else if let result = result { + observer.onNext(result) + observer.onCompleted() + } + } + return Disposables.create() + } + } + + /** + @brief Retrieves the Firebase authentication token, possibly refreshing it if it has expired. + + @param completion Optionally; the block invoked when the token is available. Invoked + asynchronously on the main thread in the future. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all API methods. + */ + public func getIDTokenResult() -> Observable { + return Observable.create { observer in + self.base.getIDTokenResult { result, error in + if let error = error { + observer.onError(error) + } else if let result = result { + observer.onNext(result) + observer.onCompleted() + } + } + return Disposables.create() + } + } + + /** + @brief Retrieves the Firebase authentication token, possibly refreshing it if it has expired. + + @param forceRefresh Forces a token refresh. Useful if the token becomes invalid for some reason + other than an expiration. + @param completion Optionally; the block invoked when the token is available. Invoked + asynchronously on the main thread in the future. + + @remarks The authentication token will be refreshed (by making a network request) if it has + expired, or if `forceRefresh` is YES. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all API methods. + */ + public func getIDTokenResult(forcingRefresh: Bool) -> Observable { + return Observable.create { observer in + self.base.getIDTokenResult(forcingRefresh: forcingRefresh) { result, error in + if let error = error { + observer.onError(error) + } else if let result = result { + observer.onNext(result) + observer.onCompleted() + } + } + return Disposables.create() + } + } + + /** + @brief Retrieves the Firebase authentication token, possibly refreshing it if it has expired. + + @param completion Optionally; the block invoked when the token is available. Invoked + asynchronously on the main thread in the future. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all API methods. + */ + public func getIDToken() -> Observable { + return Observable.create { observer in + self.base.getIDToken { token, error in + if let error = error { + observer.onError(error) + } else if let token = token { + observer.onNext(token) + observer.onCompleted() + } + } + return Disposables.create() + } + } + + /** @fn getIDTokenForcingRefresh:completion: + @brief Retrieves the Firebase authentication token, possibly refreshing it if it has expired. + + @param forceRefresh Forces a token refresh. Useful if the token becomes invalid for some reason + other than an expiration. + @param completion Optionally; the block invoked when the token is available. Invoked + asynchronously on the main thread in the future. + + @remarks The authentication token will be refreshed (by making a network request) if it has + expired, or if `forceRefresh` is YES. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all API methods. + */ + public func getIDTokenForcingRefresh(_ forceRefresh: Bool) -> Observable { + return Observable.create { observer in + self.base.getIDTokenForcingRefresh(forceRefresh) { token, error in + if let error = error { + observer.onError(error) + } else if let token = token { + observer.onNext(token) + observer.onCompleted() + } + } + return Disposables.create() + } + } + + /** + @brief Associates a user account from a third-party identity provider with this user and + returns additional identity provider data. + + @param credential The credential for the identity provider. + @param completion Optionally; the block invoked when the unlinking is complete, or fails. + Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeProviderAlreadyLinked` - Indicates an attempt to link a provider of a + type already linked to this account. + + `FIRAuthErrorCodeCredentialAlreadyInUse` - Indicates an attempt to link with a + credential + that has already been linked with a different Firebase account. + + `FIRAuthErrorCodeOperationNotAllowed` - Indicates that accounts with the identity + provider represented by the credential are not enabled. Enable them in the Auth section + of the Firebase console. + + @remarks This method may also return error codes associated with updateEmail:completion: and + updatePassword:completion: on FIRUser. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all FIRUser methods. + */ + public func linkAndRetrieveData(with credential: AuthCredential) -> Observable { + return Observable.create { observer in + self.base.linkAndRetrieveData(with: credential) { result, error in + if let error = error { + observer.onError(error) + } else if let result = result { + observer.onNext(result) + observer.onCompleted() + } + } + return Disposables.create() + } + } + + /** + @brief Disassociates a user account from a third-party identity provider with this user. + + @param provider The provider ID of the provider to unlink. + @param completion Optionally; the block invoked when the unlinking is complete, or fails. + Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeNoSuchProvider` - Indicates an attempt to unlink a provider + that is not linked to the account. + + `FIRAuthErrorCodeRequiresRecentLogin` - Updating email is a security sensitive + operation that requires a recent login from the user. This error indicates the user + has not signed in recently enough. To resolve, reauthenticate the user by invoking + reauthenticateWithCredential:completion: on FIRUser. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all FIRUser methods. + */ + public func unlink(fromProvider provider: String) -> Observable { + return Observable.create { observer in + self.base.unlink(fromProvider: provider) { user, error in + if let error = error { + observer.onError(error) + } else if let user = user { + observer.onNext(user) + observer.onCompleted() + } + } + return Disposables.create() + } + } + + /** + @brief Initiates email verification for the user. + + @param completion Optionally; the block invoked when the request to send an email verification + is complete, or fails. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeInvalidRecipientEmail` - Indicates an invalid recipient email was + sent in the request. + + `FIRAuthErrorCodeInvalidSender` - Indicates an invalid sender email is set in + the console for this action. + + `FIRAuthErrorCodeInvalidMessagePayload` - Indicates an invalid email template for + sending update email. + + `FIRAuthErrorCodeUserNotFound` - Indicates the user account was not found. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all FIRUser methods. + */ + public func sendEmailVerification() -> Observable { + return Observable.create { observer in + self.base.sendEmailVerification { error in + guard let error = error else { + observer.onNext(()) + observer.onCompleted() + return + } + observer.onError(error) + } + return Disposables.create() + } + } + + /** + @brief Initiates email verification for the user. + + @param actionCodeSettings An `FIRActionCodeSettings` object containing settings related to + handling action codes. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeInvalidRecipientEmail` - Indicates an invalid recipient email was + sent in the request. + + `FIRAuthErrorCodeInvalidSender` - Indicates an invalid sender email is set in + the console for this action. + + `FIRAuthErrorCodeInvalidMessagePayload` - Indicates an invalid email template for + sending update email. + + `FIRAuthErrorCodeUserNotFound` - Indicates the user account was not found. + + `FIRAuthErrorCodeMissingIosBundleID` - Indicates that the iOS bundle ID is missing when + a iOS App Store ID is provided. + + `FIRAuthErrorCodeMissingAndroidPackageName` - Indicates that the android package name + is missing when the `androidInstallApp` flag is set to true. + + `FIRAuthErrorCodeUnauthorizedDomain` - Indicates that the domain specified in the + continue URL is not whitelisted in the Firebase console. + + `FIRAuthErrorCodeInvalidContinueURI` - Indicates that the domain specified in the + continue URI is not valid. + */ + public func sendEmailVerification(with settings: ActionCodeSettings) -> Observable { + return Observable.create { observer in + self.base.sendEmailVerification(with: settings) { error in + guard let error = error else { + observer.onNext(()) + observer.onCompleted() + return + } + observer.onError(error) + } + return Disposables.create() + } + } + + /** + @brief Deletes the user account (also signs out the user, if this was the current user). + + @param completion Optionally; the block invoked when the request to delete the account is + complete, or fails. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeRequiresRecentLogin` - Updating email is a security sensitive + operation that requires a recent login from the user. This error indicates the user + has not signed in recently enough. To resolve, reauthenticate the user by invoking + reauthenticateWithCredential:completion: on FIRUser. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all FIRUser methods. + + */ + public func delete() -> Observable { + return Observable.create { observer in + self.base.delete { error in + guard let error = error else { + observer.onNext(()) + observer.onCompleted() + return + } + observer.onError(error) + } + return Disposables.create() + } + } +} diff --git a/Sources/Auth/FIRUserProfileChangeRequest+Rx.swift b/Sources/Auth/FIRUserProfileChangeRequest+Rx.swift new file mode 100644 index 0000000..67a0522 --- /dev/null +++ b/Sources/Auth/FIRUserProfileChangeRequest+Rx.swift @@ -0,0 +1,34 @@ +// +// FIRUserProfileChangeRequest+Rx.swift +// RxFirebase +// +// Created by Arnaud Dorgans on 09/09/2018. +// + +import RxSwift +import FirebaseAuth + +extension Reactive where Base: UserProfileChangeRequest { + + /** + @brief Commits any pending changes. + @remarks This method should only be called once. Once called, property values should not be + changed. + + @param completion Optionally; the block invoked when the user profile change has been applied. + Invoked asynchronously on the main thread in the future. + */ + public func commitChanges() -> Observable { + return Observable.create { observer in + self.base.commitChanges { error in + guard let error = error else { + observer.onNext(()) + observer.onCompleted() + return + } + observer.onError(error) + } + return Disposables.create() + } + } +}