swift keychain add, delete, get working, update not working - swift

I'm troubleshooting a problem with Keychain updates. I have SecItemAdd, SecItemCopyMatching, and SecItemDelete working. But I'm stumped on SecItemUpdate. I always get a -50 fail.
I've put a public MacOS keychainTest project on Github at:
https://github.com/darrellroot/keychainTest/blob/master/README.md
FYI this almost identical question/answer should help me, but it's not:
Swift 4 Keychain SecItemUpdate Error status code -50
Here's relevant code snippets:
let keychainTest = "Keychain Test"
let serverHostname = "mail.nowhere.com"
let keychainService = "KeychainService"
AddQuery works:
let addQuery: [String: Any] = [kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: keychainService,
kSecAttrAccount as String: serverHostname,
kSecValueData as String: inputTextOutlet.stringValue]
let status = SecItemAdd(addQuery as CFDictionary, nil)
GetQuery works:
let getQuery: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: keychainService,
kSecAttrAccount as String: serverHostname,
kSecMatchLimit as String: kSecMatchLimitOne,
kSecReturnData as String: true]
var rawResult: AnyObject?
let status = SecItemCopyMatching(getQuery as CFDictionary, &rawResult)
statusLabel.stringValue = status.description
guard let retrievedData = rawResult as? Data else { return }
guard let pass = String(data: retrievedData, encoding: String.Encoding.utf8) else { return }
DeleteQuery works:
let deleteQuery: [String: Any] = [kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: keychainService,
kSecAttrAccount as String: serverHostname]
let status = SecItemDelete(deleteQuery as CFDictionary)
statusLabel.stringValue = status.description
But for this updateQuery I always get a -50 OSStatus message:
let updateQuery: [String: Any] = [kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: keychainService,
kSecAttrAccount as String: serverHostname]
let newAttributes: [String: Any] = [kSecValueData as String: inputTextOutlet.stringValue]
let status = SecItemUpdate(updateQuery as CFDictionary, newAttributes as CFDictionary)
per osstatus.com, -50 is "One or more parameters passed to the function were not valid."

Related

Could not cast value of type __NSCFString

I am trying out FCM messaging service. I have setup everything perfecting. When I receive message from FCM I get the following error. I am not sure what is wrong here:
AnyHashable("google.c.a.c_id"): 1586592282379086000, AnyHashable("gcm.message_id"): 0:1515418580276498%f4373656f4373656]
Could not cast value of type '__NSCFString' (0x1b4c70040) to 'NSDictionary' (0x1b4c70b80).
2018-01-08 19:06:21.198548+0530 Ozone[1067:540436] Could not cast value of type '__NSCFString' (0x1b4c70040) to 'NSDictionary' (0x1b4c70b80).
The strange part is I created a seperate Push Notification App and put the same code, it is working there. What could be wrong here?
Here is the piece code: I am getting the error in let d : [String : Any].....line
UNNotificationPresentationOptions) -> Void) {
print("Handle push from foreground\(notification.request.content.userInfo)")
let dict = notification.request.content.userInfo["aps"] as! NSDictionary
let d : [String : Any] = dict["alert"] as! [String : Any]
let body : String = d["body"] as! String
let title : String = d["title"] as! String
print("Title:\(title) + body:\(body)")
self.showAlertAppDelegate(title: title,message:body,buttonTitle:"ok",window:self.window!)
}
Can some one help me with this? I know it is very general error but not sure why this is coming as it is working fine in another app.
Thanks!
alert key can be string or dictionary (depends on your server). You can try this.
if let dict = notification.request.content.userInfo["aps"] as? [String : Any] {
if let d = dict["alert"] as? [String : Any],
let body = d["body"] as? String,
let title = d["title"] as? String {
print("Title:\(title) + body:\(body)")
} else if let body = dict["alert"] as? String {
print("body:\(body)")
}
}
And also you should avoid force casting and don't use NSDictionary in swift.

Read item from keychain right after creating

I'm working with custom keychain in my application and I have problems with reading keychain item right after adding new one. This is code example:
let path = "/tmp/testkeychain_48"
let password = "password"
let serviceName = "service"
let account = "account"
let data = "data".data(using: .utf8)
var keychain: SecKeychain? = nil
var status = SecKeychainCreate(path, UInt32(password.characters.count), password, false, nil, &keychain)
assert(status == errSecSuccess)
var query: [String: AnyObject] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: serviceName as AnyObject,
kSecAttrAccount as String: account as AnyObject,
kSecValueData as String: data as AnyObject,
kSecUseKeychain as String: keychain as AnyObject,
]
var item: CFTypeRef? = nil
status = SecItemAdd(query as CFDictionary, &item)
assert(status == errSecSuccess)
assert(item != nil)
query = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: serviceName as AnyObject,
kSecAttrAccount as String: account as AnyObject,
kSecMatchLimit as String: kSecMatchLimitAll as AnyObject,
kSecUseKeychain as String: keychain as AnyObject,
]
status = SecItemCopyMatching(query as CFDictionary, &item)
assert(status == errSecSuccess)
assert(item != nil)
try? FileManager.default.removeItem(atPath: path)
SecItemAdd(_:_) returns success but SecItemCopyMatching(_:_) fails with error The specified item could not be found in the keychain. With default keychain all works correctly.

How to read Double from AnyObject in Swift 3?

I had it working on previous Swift versions like this:
let dictionary = responseObject as! NSDictionary
let result = dictionary.objectForKey("result")!
let geometry = result.objectForKey("geometry")!
let location = geometry.objectForKey("location")!
let lat: Double = location.objectForKey("lat")!.doubleValue
As I understand, there is no doubleValue anymore, so I replaced it like this:
let dictionary = responseObject as! NSDictionary
let result: AnyObject = dictionary.object(forKey: "result") as AnyObject!
let geometry: AnyObject = result.object(forKey: "geometry") as AnyObject!
let location: AnyObject = geometry.object(forKey: "location") as AnyObject!
let lat: Double = location.double(forKey: "lat")
And it crashes:
-[__NSCFDictionary doubleForKey:]: unrecognized selector sent to instance 0x1584aba10
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary doubleForKey:]: unrecognized selector sent to instance 0x1584aba10'
You just need to cast it from Any to [String: Any] or to another type you need to get from it:
let dictionary = responseObject as? [String: Any] ?? [:]
let result = dictionary["result"] as? [String: Any] ?? [:]
let location = result["location"] as? [String: Any] ?? [:]
let lat = location["lat"] as? Double ?? 0

Swift 2: How can i assign a dictionary to AnyObject?

I was using swift 1.2 and everything was going fine. after upgrading my Xcode to 7 . I faced some weird problems.
My code was :
let postData : AnyObject = ["username":username , "password":password] ;
I need this variable to be AnyObject, because
let jsonObject : AnyObject = postData ;
let jsonString = JSONStringify(jsonObject)
let data1 = jsonString.dataUsingEncoding(NSUTF8StringEncoding)
let task1 = NSURLSession.sharedSession().uploadTaskWithRequest(request, fromData: data1) {
(Data, Response, Error) -> Void in
needs a Anyobject for post Data header.
The error is
Value of type '[String : String?]' does not conform to specified type 'AnyObject'
can any one help me?
The problem is your password variable is an Optional<String>. This means the conversion from Swift dictionary to AnyObject (I think it tries to convert it to an NSDictionary) will fail.
If you do
let postData : AnyObject = ["username":username , "password":password!]
It should work unless the password is nil (check that before creating the dictionary)
If you want to be able to have null passwords in the output, you can do this in your dictionary
let postData : [String : AnyObject] = ["username":username , "password":password ?? NSNull()]
The following works
let pw: String? = "pw"
let pw2: String? = nil
var foo: [String : AnyObject] = ["bar" : pw ?? NSNull(), "baz" : pw2 ?? NSNull()]
let data = try NSJSONSerialization.dataWithJSONObject(foo, options: NSJSONWritingOptions.PrettyPrinted)
let str = NSString(data: data, encoding: NSUTF8StringEncoding)!
print(str)
And prints
{
"baz" : null,
"bar" : "pw"
}
I assume you are passing parameters to a request which require key as String and value can be AnyObject. Try this:
let postData: [String: AnyObject] = ["username":username , "password":password]
Also make sure username and password are not optional, and in that case, use ! to unwrap them if you are sure values wil be there.
let postData: [String: AnyObject] = ["username":username!, "password":password!]
or you can use
let postData: [String: AnyObject] = ["username":username ?? "", "password":password ?? ""]

convert string unicode 8 swift

i was a nsdata from json
when i put in string i get "#1495;#1493;#1507; #1492;#1510;#1493;#1511; +& Before each tag
i need it in Hebrew
the code is
let json_url = NSURL(string: "http://itaypincas7.ipage.com/WigiTech-DB/createJSON.php")
let jsonData = NSData(contentsOfURL: json_url!)
do {
let json = try NSJSONSerialization.JSONObjectWithData(jsonData!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
for (_, subJson) in json {
let id = Int(subJson["id"] as! String)
let name: String = subJson["name"] as! String
let area: String = subJson["area"] as! String
let latitude = CLLocationDegrees(CGFloat(Float(subJson["latitude"] as! String)!))
let longitude = CLLocationDegrees(CGFloat(Float(subJson["longitude"] as! String)!))
let beachNew = BeachNew(id: id!, name: name, area: area, latitude: latitude, longitude: longitude)
beachesList.append(beachNew)
}
You can use NSAttributedString to replace the HTML entities. Here's an example for decoding the name variable.
let name: String = subJson["name"] as! String
let nameData = name.dataUsingEncoding(NSUTF8StringEncoding)!
let options: [String: AnyObject] = [
NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: NSUTF8StringEncoding
]
let attributedName = try NSAttributedString(data: nameData, options: options, documentAttributes: nil)
let decodedName = attributedName.string
The value of decodedName will have all entities replaced with the Hebrew characters you're looking for.