-
Notifications
You must be signed in to change notification settings - Fork 3
/
UserDefaults+Orangered.swift
120 lines (102 loc) · 3.82 KB
/
UserDefaults+Orangered.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//
// UserDefaults+Orangered.swift
// Orangered
//
// Created by Alan Westbrook on 6/13/16.
// Copyright © 2016 Rockwood Software. All rights reserved.
//
import Foundation
import Cocoa
private let kUserNameKey = "username"
private let kLoggedInKey = "logged in"
private let kServiceName = "Orangered!"
extension UserDefaults {
var username:String? {
get {
return string(forKey: kUserNameKey)
}
set {
set(newValue, forKey: kUserNameKey)
}
}
var password:String? {
get {
let pass = getPassword()
UserDefaults.keychainItem = nil
return pass
}
set {
setPassword(newValue!)
}
}
var loggedIn:Bool {
get {
return bool(forKey: kLoggedInKey)
}
set {
set(newValue, forKey: kLoggedInKey)
}
}
// C APIs are *the worst*
static private var keychainItem:SecKeychainItem? = nil
private func getPassword() -> String? {
guard let uname = username else {
print("no user name set")
return nil
}
var passwordLength:UInt32 = 0
var passwordData:UnsafeMutablePointer<Void>? = nil
let err = SecKeychainFindGenericPassword(nil,
UInt32(kServiceName.characters.count),
kServiceName,
UInt32(uname.characters.count),
uname,
&passwordLength,
&passwordData,
&UserDefaults.keychainItem)
if let pass = passwordData, err == errSecSuccess {
let password = String(bytesNoCopy: pass, length: Int(passwordLength), encoding: String.Encoding.utf8, freeWhenDone: true)
return password
}
else {
print("Error grabbing password: \(err)")
}
return nil
}
private func setPassword(_ pass:String) {
guard let uname = username else {
print("No username")
return
}
if let _ = getPassword() {
// have to update instead of setting
updatePassword(pass)
return
}
let result = SecKeychainAddGenericPassword(nil,
UInt32(kServiceName.characters.count),
kServiceName,
UInt32(uname.characters.count),
uname,
UInt32(pass.characters.count),
pass,
nil)
if result != errSecSuccess {
print("error setting key: \(result)")
}
}
private func updatePassword(_ password:String) {
guard let itemActual = UserDefaults.keychainItem else {
print("Must grab a password to init the item before updatint it, bleah")
return
}
let result = SecKeychainItemModifyAttributesAndData(itemActual,
nil,
UInt32(password.characters.count),
password)
if result != errSecSuccess {
print("error updating the keychain: \(result)")
}
UserDefaults.keychainItem = nil
}
}