How to retrieve userId from amplify authentication response using swift - ios

I am using amplify to register and sign user in my app written in swift. User registration works but I need a way to retrieve the userId from the response. Sample code below I always get the userId value to be nil even though in the cognito session of IAM I see the user just created
func signUp(username: String, password: String, email: String, firstName: String, lastName: String, phoneNumber: String) {
//get token ID
let guestToken = DashboardView.getGuesToken()
let guestTokenID = DashboardView.getGuesTokenID()
let userAttributes = [
AuthUserAttribute(.email, value: email),
AuthUserAttribute(.givenName, value: firstName),
AuthUserAttribute(.familyName, value: lastName),
AuthUserAttribute(.phoneNumber, value: phoneNumber),
AuthUserAttribute(.preferredUsername, value: username)
]
let options = AuthSignUpRequest.Options(userAttributes: userAttributes)
Amplify.Auth.signUp(username: email, password: password, options: options) { result in
switch result {
case .success(let signUpResult):
if case let .confirmUser(deliveryDetails, userId) = signUpResult.nextStep {
print("Delivery details \(String(describing: deliveryDetails))")
print("Delivery details \(String(describing: userId))")
DispatchQueue.main.async {
self.activityLoaderView.alpha = 0
self.activityLoader.alpha = 0
self.txtPassword.alpha = 0
self.txtPassword.isEnabled = false
self.txtVerifCode.alpha = 1
self.txtVerifCode.isEnabled = true
self.btnVerify.alpha = 1
self.btnVerify.isEnabled = true
}
} else {
print("SignUp Complete")
}
case .failure(let error):
DispatchQueue.main.async {
self.activityLoaderView.alpha = 0
self.activityLoader.alpha = 0
self.toastView.alpha = 1
self.toastViewLabel.text = "Operation couldn't be completed. Please try again."
print("An error occurred while registering a user \(error)")
}
}
}
}
I wrote a signup function which when successful I will receive a success message and details pertaining to the user that was just created. I print out a unique userId but it is always empty

Related

same struct for sending and receiving json data in swift

I want to use the same model struct for sending parameters and receiving JSON response from an API.
I want to send email and password and receive JSON response message.
But when I declare a property referencing another model in my user model, I am forced to provide a value.
My API does not return the parameters email and password, it simply returns an array if login is unsuccessful and returns the user info on successful login.
this is the json response on error :
Optional({
errors = {
msg = "USER_DOES_NOT_EXIST";
};
this is my model I used to post:
struct LoginUser: Codable {
let email: String?
let password: String?
}
this is the response on successful login:
Optional({
token = 267e6a9d5a128fb1f44e670fcd89793af50fa9a831e6ae7dc2f0592b508bd224a71290fbdf1619cf52ed0f2c034b26383b915343f3822a52e1386c042484744b71811f80d3cb663fc76a6cc74d4866737421e3b9d62e35b415c0f7c385e5c70d472a5facf7f0101165d321c35eb20ae5f8bb32f06120e66a42de47c79a7587a2aa7f81f35c3821b9418e0c9142a7ec2b67b9755d3e17753dd8f1cdf3f71c0816627e2be26485f9b50ee1ad96a867856f0de736963c5ff59e9e37e92d5f3386f7;
user = {
"_id" = 5e52c0c5cf65d33726a98590;
email = "test7#gmail.com";
"first_name" = gagz;
"last_name" = bhullar;
verified = 0;
};
})
I want to modify my loginUser model such that it can both receive and send data.
is it possible?
if not, why?
For an API which returns two different models on success and failure I highly recommend to use an enum with associated values. The benefit is you get rid of the tons of optionals (and if let expressions) and you can use a descriptive switch for the success and failure cases.
enum Response : Decodable {
case success(UserResponse)
case failure(ErrorResponse)
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
do {
let userData = try container.decode(UserResponse.self)
self = .success(userData)
} catch DecodingError.typeMismatch {
let errorData = try container.decode(ErrorResponse.self)
self = .failure(errorData)
}
}
}
And these are the corresponding structs
struct ErrorResponse: Decodable {
let errors: [String:String]
}
struct UserResponse: Decodable {
let token : String
let user: User
}
struct User: Decodable {
private enum CodingKeys : String, CodingKey {
case id = "_id"
case email
case firstName = "first_name"
case lastName = "last_name"
case verified
}
let id, email, firstName, lastName : String
let verified : Int // maybe Bool
}
To send only two key-value pairs an extra struct and Codable is overkill. Create a temporary [String:String] dictionary and encode it with JSONSerialization or create the JSON Data directly for example
func jsonSendData(email: String, password: String) -> Data {
let jsonString =
"""
{"email":"\(email)","password":"\(password)"}
"""
return Data(jsonString.utf8)
}
Although it is recommended to create separate model for handling the failure and success cases, still if you want to create a single model, you can do it like so,
struct LoginUser: Codable {
let email, password, token, id, firstName, lastName: String?
let verified: Int?
let errorMessage: String?
enum CodingKeys: String, CodingKey {
case email, token, _id, firstName, lastName, verified, user
case errors, msg
case password
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
token = try container.decodeIfPresent(String.self, forKey: .token)
if container.contains(.user) {
let user = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .user)
id = try user.decodeIfPresent(String.self, forKey: ._id)
email = try user.decodeIfPresent(String.self, forKey: .email)
firstName = try user.decodeIfPresent(String.self, forKey: .firstName)
lastName = try user.decodeIfPresent(String.self, forKey: .lastName)
verified = try user.decodeIfPresent(Int.self, forKey: .verified)
errorMessage = nil
} else if container.contains(.errors) {
let errors = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .errors)
errorMessage = try errors.decodeIfPresent(String.self, forKey: .msg)
id = nil
email = nil
firstName = nil
lastName = nil
verified = nil
} else {
id = nil
email = nil
firstName = nil
lastName = nil
verified = nil
errorMessage = nil
}
password = nil
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(email, forKey: .email)
try container.encode(password, forKey: .password)
//add the keys that you want to send in the request...
}
}
Since, you haven't added the the JSON that you want to send in the request, I've assumed that you're only sending email and password in the request. You can add more in the above encode(to:) method.

How to retrieve a variable from a Firebase Database in Swift

I am attempting to simply read into the database that is structured as stated below. I am attempting to read the user's "userType" and use it in the following if statements below. Any help is appreciated!
Swift Code:
// Create firebase reference and link to database
var dataRef : DatabaseReference?
dataRef = Database.database().reference()
let userID = Auth.auth().currentUser!.uid // Get the User's ID
// Gather user's type (Customer or Company)
/*Use this space to gather the user's type into some variable named currUserType*/
if (currUserType == "Customer"){
self.performSegue(withIdentifier: "LoginToCustomer", sender: self)
print("User: " + userID + " has been signed in!")
}
else if (currUserType == "Company"){
self.performSegue(withIdentifier: "LoginToHost", sender: self)
}
else{
self.showMessage(alertTitle: "Error",
alertMessage: "Please report the following error with a description of what lead to to the error.",
actionTitle: "Dismiss")
}
Database Structure:
"Users" : {
"ZFH0lFe1fIb5bwSO2Q95ektD33L2" : {
"email" : "cust#test.com",
"userType" : "Customer"
}
First take the ref like i have took below:
let dbRef = Database.database().reference().child("Users")
Then create model like i have created below:
class Users {
var email: String?
var userType: String?
init(email: String, userType: String) {
self.email = email
self.userType = userType
}
}
Then create completion Handler like i have created below:
func getUsersData(handler: #escaping (_ usersArray: [Users]) -> ()) {
var usersArray = [Users]()
dbRef.observe(.value) { (datasnapshot) in
guard let usersnapshot = datasnapshot.children.allObjects as? [DataSnapshot] else { return }
for user in usersnapshot {
let email = user.childSnapshot(forPath: "email").value as! String
let userType = user.childSnapshot(forPath: "userType").value as! String
let userObj = Users(email: email, userType: userType)
usersArray.append(userObj)
}
handler(usersArray)
}
}
simply call this function which returns the whole array of users.
Refrence https://firebase.google.com/docs/database/ios/read-and-write#reading_and_writing_data

How can i get the user value from this output

I really can't find a way to get the user value from the below output
If I print the result directly I get
(TotersAPIFrameWork.Result<TotersAPIFrameWork.DataContainer<TotersAPIFrameWork.User>>) $R5 = success {
success = {
user = {
id = 200
first_name = "yara"
last_name = "Padberg"
email = "client#client.com"
phone_number = "+9999"
type = "client"
account_type = "email"
sm_user_id = nil
sm_access_token = nil
picture = ""
deleted_at = nil
created_at = "2018-04-04 14:33:29"
updated_at = "2018-04-24 11:15:45"
rating = "5"
rating_count = 1
regid = ""
platform = "ios"
is_agora = nil
currency_id = 1
is_verified = true
promo_code_id = nil
referral_promo_code_id = nil
op_city_id = 1
is_daas = false
token = ""
retailer_info = nil
}
}
}
I tried to convert directly to user like below
p result as? User
it is returning nil, so how should i get the result from the DataContainer?
Thanks for your help
After spending more time and understanding what i'm dealing with :) i figured out how should i get the user object.
First of all the Result that i'm using is an enum and my callback is returning Result so below was the solution:
let login = PostLogin.init(email: "client#client.com", password: "pass")
let client = APIClient(publicKey: "", privateKey:"")
client.send(login) { (result) in
switch result {
case .success(let value):
print(value)
case .failure(let error):
print(error)
}
}
The result is an enum:
import Foundation
public enum Result<Value> {
case success(Value)
case failure(Error)
}
public typealias ResultCallback<Value> = (Result<Value>) -> Void
The Value struct is below:
import Foundation
/// All successful responses return this, and contains all
/// the metainformation about the returned chunk.
public struct DataContainer<T: Decodable>: Decodable {
public var user:T?
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: UserResponseKeys.self)
if let u = try container.decodeIfPresent(T.self, forKey: .user)
{
self.user = u
}
}
}
now i can get user like this:
let user = value.user
Hope this will help others.

Displaying firebase child from user.uid to username in Swift 3

I have a view controller for My Profile. Logging in allows the profile page to appear without errors but when signing up, app crashes when pressing the contacts button located at bottom of view controller as seen below.
The process:
User Signs Up:
func signUp(_ email: String, usersname: String, password: String, data: Data!, loginHandler: LoginHandler?) {
FIRAuth.auth()?.createUser(withEmail: email, password: password, completion: { (user, error) in
if error != nil {
// Show error to user
self.handleFirebaseErrors(err: error as! NSError, loginHandler: loginHandler)
} else { // success creating user
if user?.uid != nil { // if there is a valid user id
// Store user to database
self.setUserInfo(user, usersname: usersname, email: email, password: password, data: data!)
// Log In the user
self.login(email: email, password: password, loginHandler: loginHandler)
}
}
})
}
As in the signUp(), setUserInfo() is called, which contains images, and then calls saveUser()
Save User
func saveUser(_ user: FIRUser!, usersname: String, email: String, password: String) {
// Create the user dictionary info
let userInfo = ["email": user.email!, "password": password, "usersname": usersname, "uid": user.uid, "photoUrl": String(describing: user.photoURL!)]
// create user reference
let userRef = DataService.Instance.dbRef.child("riders").child(user.uid)
// Save the user info in the database
userRef.setValue(userInfo)
}
Logs In
func login(email: String, password: String, loginHandler: LoginHandler?) {
FIRAuth.auth()?.signIn(withEmail: email, password: password, completion: { (user, error) in
if error != nil {
self.handleFirebaseErrors(err: error as! NSError, loginHandler: loginHandler)
} else {
loginHandler?(nil, nil)
}
})
}
The problem here is in saveUser():
At the moment, firebase shows the user.uid but I want it to show the username of the user.
let userRef = DataService.Instance.dbRef.child("riders").child(usersname)
With the above code, once the contacts button is pressed on the RidersVC, it crashes the app with error:
fatal error: unexpectedly found nil while unwrapping an Optional value
on line 56 of MyProfileVC:
let imageUrl = String(user.photoUrl)
Any ideas as how I can get the username to be displayed as the child of "riders" instead of the user.uid without it crashing?
MyProfileVC.swift
if FIRAuth.auth()?.currentUser == nil {
let vc = UIStoryboard(name: "Rider", bundle: nil).instantiateViewController(withIdentifier: "Login")
present(vc, animated: true, completion: nil)
} else {
dbRef.child("riders/\(FIRAuth.auth()!.currentUser!.uid)").observe(.value, with: { (snapshot) in
DispatchQueue.main.async(execute: {
let user = User(snapshot: snapshot)
self.username.text = user.usersname
self.email.text = FIRAuth.auth()?.currentUser?.email
let imageUrl = String(user.photoUrl)
Firebase Database Structure: (how I want it to be)
{
"riders" : {
"rider 1" : {
"email" : "rider1#me.com",
"password" : "whatever",
"photoUrl" : "https://firebasestorage.googleapis.com/...",
"usersname" : "rider 1"
}
}
}
User.swift
struct User {
let usersname: String!
let email: String!
let password: String!
let photoUrl: String!
var ref: FIRDatabaseReference?
var key: String
init(snapshot: FIRDataSnapshot) {
key = snapshot.key
ref = snapshot.ref
let snapshotValueUsersname = snapshot.value as? NSDictionary
usersname = snapshotValueUsersname?["usersname"] as? String
let snapshotValueEmail = snapshot.value as? NSDictionary
email = snapshotValueEmail?["email"] as? String
let snapshotValuePass = snapshot.value as? NSDictionary
password = snapshotValuePass?["password"] as? String
let snapshotValuePhoto = snapshot.value as? NSDictionary
photoUrl = snapshotValuePhoto?["photoUrl"] as? String
}
Firebase structure - (the way it is now)
{
"drivers" : {
"RideRequests" : {
"europeanjunkie" : {
"active" : true,
"latitude" : "45.267",
"longitude" : "-66.059",
"userId" : "5c17ByRJljZFcM703Vqn5eSFwYJ3",
"username" : "europeanjunkie"
}
}
},
"riders" : {
"5c17ByRJljZFcM703Vqn5eSFwYJ3" : {
"email" : "europeanjunkie#me.com",
"password" : "whatever",
"photoUrl" : "https://firebasestorage.googleapis.com",
"uid" : "5c17ByRJljZFcM703Vqn5eSFwYJ3",
"usersname" : "europeanjunkie"
}
}
}
Here's some stuff to consider - a little, some or all may get you headed in the right direction. Also, you can probably remove all of the DispatchQueue calls as Firebase does most of the heavy lifting for you, and with proper code structure, they are not needed.
1) A Swifty user class
class UserClass {
var usersname = ""
var email = ""
var password = ""
var photoUrl = ""
var uid = ""
init(withSnapshot: FIRDataSnapshot) {
let dict = withSnapshot.value as! [String:AnyObject]
uid = withSnapshot.key
usersname = dict["usersname"] as! String
email = dict["email"] as! String
password = dict["password"] as! String
photoUrl = dict["photoUrl"] as! String
}
}
note that we are using the var uid of each user to identify them (their 'key')
The structure that matches that class
users
uid_0
email: "bill#email.com"
password: "myPassword"
photoUrl: "http://www.url.com"
usersname: "Bill"
uid_1
email: "leroy#email.com"
password: "aPassword"
photoUrl: "http://www.anotherUrl.com"
usersname: "Leroy"
Notice again the users and their associated info are stored within the /users node in each child node that has that users uid as the key.
And some code that reads in uid_0, prints the uid and name. This code is a one-shot so it reads uid_0, but does NOT leave an observer attached to the node.
let userRef = rootRef.child("users/uid_0")
userRef.observeSingleEvent(of: .value, with: { snapshot in
let aUser = UserClass(withSnapshot: snapshot)
print("uid \(aUser.uid) has name \(aUser.usersname)")
})
Now the Geofire node would like something like this
user_locations
uid_0
//geofire data
uid_1
//geofire data
So now there is a direct correlation between the users node and their location.
In general, it's a good idea to disassociate node names (keys, which are static data) from the data they contain, which is dynamic.
With the structure in the initial question, imagine if 'europeanjunkie' changed his name to 'europeanjunkieDude'. Every place you reference 'europeanjunkie' would then have to be changed - and if it's used as a key, the entire node would have to be read in, deleted, updated, and re-written.
Using child keys created by Firebase, uid's and childByAutoId(), removes that issue.
Hope that helps!
In my opinion, if you want to query the username as the keyword. There are two possible ways to struct your dictionary.
First, use childByAutoId, username and userid will be at the same level, so you can get which value you like.
{
"riders" : {
"-KQaU9lVcUYzIo52LgmN" : {
"email" : "rider1#me.com",
"password" : "whatever",
"photoUrl" : "https://firebasestorage.googleapis.com/...",
"usersname" : "rider 1",
"userid" : "rider 1"
}
}
}
Second, make username as the child of riders. However, there would be tons of Mike.
{
"riders" : {
"username" : {
"email" : "rider1#me.com",
"password" : "whatever",
"photoUrl" : "https://firebasestorage.googleapis.com/...",
"userid" : "rider 1"
}
}
}

VPN connection using Network Extension Framework iOS 8 in Swift not working

I've been trying to use the iOS 8 Network Extension Framework to setup a VPN connection when the users presses a UIButton. I've used the following tutorial: http://ramezanpour.net/post/2014/08/03/configure-and-manage-vpn-connections-programmatically-in-ios-8/. I also looked at this post Can't setup VPN connection using Network Extension Framework iOS 8 in Swift, which is the same behavior I am getting. When I run the app I get prompted for the vpn password and shared secret when installing the profile even though they were set with all the other required values in the code. And if I enter these details when installing the profile it still does not work. When trying to connect using the app it gives a "there's no sharedSecret" error. In the referenced post, the problem was apparently solved by rewriting the code that saves and accesses the keychain data in OBJ-C. I would like to get this to work in swift or understand why it does not work in swift.
This is the code for the connection
let manager = NEVPNManager.sharedManager()
#IBAction func connectToVpn(sender: AnyObject) {
println("in call vpn")
manager.loadFromPreferencesWithCompletionHandler { (error) -> Void in
if((error) != nil) {
println("VPN Preferences error: 1")
}
else {
var p = NEVPNProtocolIPSec()
p.username = "billy"
p.serverAddress = "xxx.xxx.xxx.xxx"
p.passwordReference = self.loadkeychain("vpnpassword")
println(p.passwordReference)
p.authenticationMethod = NEVPNIKEAuthenticationMethod.SharedSecret
p.sharedSecretReference = self.loadkeychain("sharedSecret")
println(p.sharedSecretReference)
p.localIdentifier = "vpn"
p.remoteIdentifier = "vpn"
p.disconnectOnSleep = false
println("everything is set")
self.manager.`protocol` = p
self.manager.onDemandEnabled = true
self.manager.localizedDescription = "VPN"
self.manager.saveToPreferencesWithCompletionHandler({ (error) -> Void in
if((error) != nil) {
println("VPN Preferences error: 2")
println(error)
}
else {
var startError: NSError?
self.manager.connection.startVPNTunnelAndReturnError(&startError)
if((startError) != nil) {
println("VPN Preferences error: 3")
println(startError)}
else {
println("Start VPN")
}
}
})
}
}
}
This is the code to save and retrieve from keychain
func savekeychain(key: String, value: String) -> Bool {
let valueData = value.dataUsingEncoding(NSUTF8StringEncoding,
allowLossyConversion: false)
let service = NSBundle.mainBundle().bundleIdentifier!
let secItem = [
kSecClass as! String :
kSecClassGenericPassword as! String,
kSecAttrService as! String : service,
kSecAttrAccount as! String : key,
kSecValueData as! String : valueData!,
]
var result: Unmanaged<AnyObject>? = nil
let status = Int(SecItemAdd(secItem, &result))
switch status{
case Int(errSecSuccess):
println("Successfully stored the value")
case Int(errSecDuplicateItem):
println("This item is already saved. Cannot duplicate it")
default:
println("An error occurred with code \(status)")
}
return true
}
func loadkeychain(keyToSearchFor: String) -> NSData
let service = NSBundle.mainBundle().bundleIdentifier!
let query = [
kSecClass as! String :
kSecClassGenericPassword as! String,
kSecAttrService as! String : service,
kSecAttrAccount as! String : keyToSearchFor,
kSecReturnData as! String : kCFBooleanTrue,
]
var data: NSData!
var returnedData: Unmanaged<AnyObject>? = nil
let results = Int(SecItemCopyMatching(query, &returnedData))
if results == Int(errSecSuccess){
data = returnedData!.takeRetainedValue() as! NSData
let value = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Value = \(value)")
println("DATA = \(data)")
} else {
println("Error happened with code: \(results)")
}
return data
}
Ended up changing my functions that save and retrieve data from the keychain to OBJ-C methods as suggested by the referenced post and this did resolve the issues. Some testing indicated that both the swift and OBJ-C methods returned the same values, so I'm not sure why the swift methods cause the stated behavior. One other thing I noticed is that saving values to the keychain seems a little flaky, if you delete a key and then re-add it with a different value it seems to not work, requiring a reset of the keychain to the default. I still would like to figure out why the swift methods do not seem to work correctly.
I know i am late but it might help someone we need shared secret reference in secItemCopyMatchig you need add kSecReturnPersistentRef and set to true.
Below block helps you may be.
enum VPNKeychain {
/// Returns a persistent reference for a generic password keychain item, adding it to
/// (or updating it in) the keychain if necessary.
///
/// This delegates the work to two helper routines depending on whether the item already
/// exists in the keychain or not.
///
/// - Parameters:
/// - service: The service name for the item.
/// - account: The account for the item.
/// - password: The desired password.
/// - Returns: A persistent reference to the item.
/// - Throws: Any error returned by the Security framework.
static func persistentReferenceFor(service: String, account: String, password: Data) throws -> Data {
var copyResult: CFTypeRef? = nil
let err = SecItemCopyMatching([
kSecClass: kSecClassGenericPassword,
kSecAttrService: service,
kSecAttrAccount: account,
kSecReturnPersistentRef: true,
kSecReturnData: true
] as NSDictionary, &copyResult)
switch err {
case errSecSuccess:
return try self.persistentReferenceByUpdating(copyResult: copyResult!, service: service, account: account, password: password)
case errSecItemNotFound:
return try self.persistentReferenceByAdding(service: service, account:account, password: password)
default:
try throwOSStatus(err)
// `throwOSStatus(_:)` only returns in the `errSecSuccess` case. We know we're
// not in that case but the compiler can't figure that out, alas.
fatalError()
}
}
/// Returns a persistent reference for a generic password keychain item by updating it
/// in the keychain if necessary.
///
/// - Parameters:
/// - copyResult: The result from the `SecItemCopyMatching` done by `persistentReferenceFor(service:account:password:)`.
/// - service: The service name for the item.
/// - account: The account for the item.
/// - password: The desired password.
/// - Returns: A persistent reference to the item.
/// - Throws: Any error returned by the Security framework.
private static func persistentReferenceByUpdating(copyResult: CFTypeRef, service: String, account: String, password: Data) throws -> Data {
let copyResult = copyResult as! [String:Any]
let persistentRef = copyResult[kSecValuePersistentRef as String] as! NSData as Data
let currentPassword = copyResult[kSecValueData as String] as! NSData as Data
if password != currentPassword {
let err = SecItemUpdate([
kSecClass: kSecClassGenericPassword,
kSecAttrService: service,
kSecAttrAccount: account,
] as NSDictionary, [
kSecValueData: password
] as NSDictionary)
try throwOSStatus(err)
}
return persistentRef
}
/// Returns a persistent reference for a generic password keychain item by adding it to
/// the keychain.
///
/// - Parameters:
/// - service: The service name for the item.
/// - account: The account for the item.
/// - password: The desired password.
/// - Returns: A persistent reference to the item.
/// - Throws: Any error returned by the Security framework.
private static func persistentReferenceByAdding(service: String, account: String, password: Data) throws -> Data {
var addResult: CFTypeRef? = nil
let err = SecItemAdd([
kSecClass: kSecClassGenericPassword,
kSecAttrService: service,
kSecAttrAccount: account,
kSecValueData: password,
kSecReturnPersistentRef: true,
] as NSDictionary, &addResult)
try throwOSStatus(err)
return addResult! as! NSData as Data
}
/// Throws an error if a Security framework call has failed.
///
/// - Parameter err: The error to check.
private static func throwOSStatus(_ err: OSStatus) throws {
guard err == errSecSuccess else {
throw NSError(domain: NSOSStatusErrorDomain, code: Int(err), userInfo: nil)
}
}
}

Resources