KeychainAccessTests.swift 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386
  1. //
  2. // KeychainAccessTests.swift
  3. // KeychainAccessTests
  4. //
  5. // Created by kishikawa katsumi on 2014/12/24.
  6. // Copyright (c) 2014 kishikawa katsumi. All rights reserved.
  7. //
  8. import Foundation
  9. import XCTest
  10. import KeychainAccess
  11. class KeychainAccessTests: XCTestCase {
  12. override func setUp() {
  13. super.setUp()
  14. do { try Keychain(service: "Twitter", accessGroup: "12ABCD3E4F.shared").removeAll() } catch {}
  15. do { try Keychain(service: "Twitter").removeAll() } catch {}
  16. do { try Keychain(server: NSURL(string: "https://example.com")!, protocolType: .HTTPS).removeAll() } catch {}
  17. do { try Keychain(server: NSURL(string: "https://example.com:443")!, protocolType: .HTTPS).removeAll() } catch {}
  18. do { try Keychain().removeAll() } catch {}
  19. }
  20. override func tearDown() {
  21. super.tearDown()
  22. }
  23. // MARK:
  24. func testGenericPassword() {
  25. do {
  26. // Add Keychain items
  27. let keychain = Keychain(service: "Twitter")
  28. do { try keychain.set("kishikawa_katsumi", key: "username") } catch {}
  29. do { try keychain.set("password_1234", key: "password") } catch {}
  30. let username = try! keychain.get("username")
  31. XCTAssertEqual(username, "kishikawa_katsumi")
  32. let password = try! keychain.get("password")
  33. XCTAssertEqual(password, "password_1234")
  34. }
  35. do {
  36. // Update Keychain items
  37. let keychain = Keychain(service: "Twitter")
  38. do { try keychain.set("katsumi_kishikawa", key: "username") } catch {}
  39. do { try keychain.set("1234_password", key: "password") } catch {}
  40. let username = try! keychain.get("username")
  41. XCTAssertEqual(username, "katsumi_kishikawa")
  42. let password = try! keychain.get("password")
  43. XCTAssertEqual(password, "1234_password")
  44. }
  45. do {
  46. // Remove Keychain items
  47. let keychain = Keychain(service: "Twitter")
  48. do { try keychain.remove("username") } catch {}
  49. do { try keychain.remove("password") } catch {}
  50. XCTAssertNil(try! keychain.get("username"))
  51. XCTAssertNil(try! keychain.get("password"))
  52. }
  53. }
  54. func testGenericPasswordSubscripting() {
  55. do {
  56. // Add Keychain items
  57. let keychain = Keychain(service: "Twitter", accessGroup: "12ABCD3E4F.shared")
  58. keychain["username"] = "kishikawa_katsumi"
  59. keychain["password"] = "password_1234"
  60. let username = keychain["username"]
  61. XCTAssertEqual(username, "kishikawa_katsumi")
  62. let password = keychain["password"]
  63. XCTAssertEqual(password, "password_1234")
  64. }
  65. do {
  66. // Update Keychain items
  67. let keychain = Keychain(service: "Twitter", accessGroup: "12ABCD3E4F.shared")
  68. keychain["username"] = "katsumi_kishikawa"
  69. keychain["password"] = "1234_password"
  70. let username = keychain["username"]
  71. XCTAssertEqual(username, "katsumi_kishikawa")
  72. let password = keychain["password"]
  73. XCTAssertEqual(password, "1234_password")
  74. }
  75. do {
  76. // Remove Keychain items
  77. let keychain = Keychain(service: "Twitter", accessGroup: "12ABCD3E4F.shared")
  78. keychain["username"] = nil
  79. keychain["password"] = nil
  80. XCTAssertNil(keychain["username"])
  81. XCTAssertNil(keychain["password"])
  82. }
  83. }
  84. // MARK:
  85. func testInternetPassword() {
  86. do {
  87. // Add Keychain items
  88. let keychain = Keychain(server: NSURL(string: "https://kishikawakatsumi.com")!, protocolType: .HTTPS)
  89. do { try keychain.set("kishikawa_katsumi", key: "username") } catch {}
  90. do { try keychain.set("password_1234", key: "password") } catch {}
  91. let username = try! keychain.get("username")
  92. XCTAssertEqual(username, "kishikawa_katsumi")
  93. let password = try! keychain.get("password")
  94. XCTAssertEqual(password, "password_1234")
  95. }
  96. do {
  97. // Update Keychain items
  98. let keychain = Keychain(server: NSURL(string: "https://kishikawakatsumi.com")!, protocolType: .HTTPS)
  99. do { try keychain.set("katsumi_kishikawa", key: "username") } catch {}
  100. do { try keychain.set("1234_password", key: "password") } catch {}
  101. let username = try! keychain.get("username")
  102. XCTAssertEqual(username, "katsumi_kishikawa")
  103. let password = try! keychain.get("password")
  104. XCTAssertEqual(password, "1234_password")
  105. }
  106. do {
  107. // Remove Keychain items
  108. let keychain = Keychain(server: NSURL(string: "https://kishikawakatsumi.com")!, protocolType: .HTTPS)
  109. do { try keychain.remove("username") } catch {}
  110. do { try keychain.remove("password") } catch {}
  111. XCTAssertNil(try! keychain.get("username"))
  112. XCTAssertNil(try! keychain.get("password"))
  113. }
  114. }
  115. func testInternetPasswordSubscripting() {
  116. do {
  117. // Add Keychain items
  118. let keychain = Keychain(server: NSURL(string: "https://kishikawakatsumi.com")!, protocolType: .HTTPS)
  119. keychain["username"] = "kishikawa_katsumi"
  120. keychain["password"] = "password_1234"
  121. let username = keychain["username"]
  122. XCTAssertEqual(username, "kishikawa_katsumi")
  123. let password = keychain["password"]
  124. XCTAssertEqual(password, "password_1234")
  125. }
  126. do {
  127. // Update Keychain items
  128. let keychain = Keychain(server: NSURL(string: "https://kishikawakatsumi.com")!, protocolType: .HTTPS)
  129. keychain["username"] = "katsumi_kishikawa"
  130. keychain["password"] = "1234_password"
  131. let username = keychain["username"]
  132. XCTAssertEqual(username, "katsumi_kishikawa")
  133. let password = keychain["password"]
  134. XCTAssertEqual(password, "1234_password")
  135. }
  136. do {
  137. // Remove Keychain items
  138. let keychain = Keychain(server: NSURL(string: "https://kishikawakatsumi.com")!, protocolType: .HTTPS)
  139. keychain["username"] = nil
  140. keychain["password"] = nil
  141. XCTAssertNil(keychain["username"])
  142. XCTAssertNil(keychain["password"])
  143. }
  144. }
  145. // MARK:
  146. func testDefaultInitializer() {
  147. let keychain = Keychain()
  148. XCTAssertEqual(keychain.service, "")
  149. XCTAssertNil(keychain.accessGroup)
  150. }
  151. func testInitializerWithService() {
  152. let keychain = Keychain(service: "com.example.github-token")
  153. XCTAssertEqual(keychain.service, "com.example.github-token")
  154. XCTAssertNil(keychain.accessGroup)
  155. }
  156. func testInitializerWithAccessGroup() {
  157. let keychain = Keychain(accessGroup: "12ABCD3E4F.shared")
  158. XCTAssertEqual(keychain.service, "")
  159. XCTAssertEqual(keychain.accessGroup, "12ABCD3E4F.shared")
  160. }
  161. func testInitializerWithServiceAndAccessGroup() {
  162. let keychain = Keychain(service: "com.example.github-token", accessGroup: "12ABCD3E4F.shared")
  163. XCTAssertEqual(keychain.service, "com.example.github-token")
  164. XCTAssertEqual(keychain.accessGroup, "12ABCD3E4F.shared")
  165. }
  166. func testInitializerWithServer() {
  167. let server = "https://kishikawakatsumi.com"
  168. let URL = NSURL(string: server)!
  169. do {
  170. let keychain = Keychain(server: server, protocolType: .HTTPS)
  171. XCTAssertEqual(keychain.server, URL)
  172. XCTAssertEqual(keychain.protocolType, ProtocolType.HTTPS)
  173. XCTAssertEqual(keychain.authenticationType, AuthenticationType.Default)
  174. }
  175. do {
  176. let keychain = Keychain(server: URL, protocolType: .HTTPS)
  177. XCTAssertEqual(keychain.server, URL)
  178. XCTAssertEqual(keychain.protocolType, ProtocolType.HTTPS)
  179. XCTAssertEqual(keychain.authenticationType, AuthenticationType.Default)
  180. }
  181. }
  182. func testInitializerWithServerAndAuthenticationType() {
  183. let server = "https://kishikawakatsumi.com"
  184. let URL = NSURL(string: server)!
  185. do {
  186. let keychain = Keychain(server: server, protocolType: .HTTPS, authenticationType: .HTMLForm)
  187. XCTAssertEqual(keychain.server, URL)
  188. XCTAssertEqual(keychain.protocolType, ProtocolType.HTTPS)
  189. XCTAssertEqual(keychain.authenticationType, AuthenticationType.HTMLForm)
  190. }
  191. do {
  192. let keychain = Keychain(server: URL, protocolType: .HTTPS, authenticationType: .HTMLForm)
  193. XCTAssertEqual(keychain.server, URL)
  194. XCTAssertEqual(keychain.protocolType, ProtocolType.HTTPS)
  195. XCTAssertEqual(keychain.authenticationType, AuthenticationType.HTMLForm)
  196. }
  197. }
  198. // MARK:
  199. func testContains() {
  200. let keychain = Keychain(service: "Twitter")
  201. XCTAssertFalse(try! keychain.contains("username"), "not stored username")
  202. XCTAssertFalse(try! keychain.contains("password"), "not stored password")
  203. do { try keychain.set("kishikawakatsumi", key: "username") } catch {}
  204. XCTAssertTrue(try! keychain.contains("username"), "stored username")
  205. XCTAssertFalse(try! keychain.contains("password"), "not stored password")
  206. do { try keychain.set("password1234", key: "password") } catch {}
  207. XCTAssertTrue(try! keychain.contains("username"), "stored username")
  208. XCTAssertTrue(try! keychain.contains("password"), "stored password")
  209. }
  210. // MARK:
  211. func testSetString() {
  212. let keychain = Keychain(service: "Twitter")
  213. XCTAssertNil(try! keychain.get("username"), "not stored username")
  214. XCTAssertNil(try! keychain.get("password"), "not stored password")
  215. do { try keychain.set("kishikawakatsumi", key: "username") } catch {}
  216. XCTAssertEqual(try! keychain.get("username"), "kishikawakatsumi", "stored username")
  217. XCTAssertNil(try! keychain.get("password"), "not stored password")
  218. do { try keychain.set("password1234", key: "password") } catch {}
  219. XCTAssertEqual(try! keychain.get("username"), "kishikawakatsumi", "stored username")
  220. XCTAssertEqual(try! keychain.get("password"), "password1234", "stored password")
  221. }
  222. func testSetStringWithLabel() {
  223. let keychain = Keychain(service: "Twitter")
  224. .label("Twitter Account")
  225. XCTAssertNil(keychain["kishikawakatsumi"], "not stored password")
  226. do {
  227. let label = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
  228. return attributes?.label
  229. }
  230. XCTAssertNil(label)
  231. } catch {
  232. XCTFail("error occurred")
  233. }
  234. keychain["kishikawakatsumi"] = "password1234"
  235. XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
  236. do {
  237. let label = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
  238. return attributes?.label
  239. }
  240. XCTAssertEqual(label, "Twitter Account")
  241. } catch {
  242. XCTFail("error occurred")
  243. }
  244. }
  245. func testSetStringWithComment() {
  246. let keychain = Keychain(service: "Twitter")
  247. .comment("Kishikawa Katsumi")
  248. XCTAssertNil(keychain["kishikawakatsumi"], "not stored password")
  249. do {
  250. let comment = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
  251. return attributes?.comment
  252. }
  253. XCTAssertNil(comment)
  254. } catch {
  255. XCTFail("error occurred")
  256. }
  257. keychain["kishikawakatsumi"] = "password1234"
  258. XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
  259. do {
  260. let comment = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
  261. return attributes?.comment
  262. }
  263. XCTAssertEqual(comment, "Kishikawa Katsumi")
  264. } catch {
  265. XCTFail("error occurred")
  266. }
  267. }
  268. func testSetStringWithLabelAndComment() {
  269. let keychain = Keychain(service: "Twitter")
  270. .label("Twitter Account")
  271. .comment("Kishikawa Katsumi")
  272. XCTAssertNil(keychain["kishikawakatsumi"], "not stored password")
  273. do {
  274. let label = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
  275. return attributes?.label
  276. }
  277. XCTAssertNil(label)
  278. let comment = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
  279. return attributes?.comment
  280. }
  281. XCTAssertNil(comment)
  282. } catch {
  283. XCTFail("error occurred")
  284. }
  285. keychain["kishikawakatsumi"] = "password1234"
  286. XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
  287. do {
  288. let label = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
  289. return attributes?.label
  290. }
  291. XCTAssertEqual(label, "Twitter Account")
  292. let comment = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
  293. return attributes?.comment
  294. }
  295. XCTAssertEqual(comment, "Kishikawa Katsumi")
  296. } catch {
  297. XCTFail("error occurred")
  298. }
  299. }
  300. func testSetData() {
  301. let JSONObject = ["username": "kishikawakatsumi", "password": "password1234"]
  302. let JSONData = try! NSJSONSerialization.dataWithJSONObject(JSONObject, options: [])
  303. let keychain = Keychain(service: "Twitter")
  304. XCTAssertNil(try! keychain.getData("JSONData"), "not stored JSON data")
  305. do { try keychain.set(JSONData, key: "JSONData") } catch {}
  306. XCTAssertEqual(try! keychain.getData("JSONData"), JSONData, "stored JSON data")
  307. }
  308. func testStringConversionError() {
  309. let keychain = Keychain(service: "Twitter")
  310. let length = 256
  311. let data = NSMutableData(length: length)!
  312. SecRandomCopyBytes(kSecRandomDefault, length, UnsafeMutablePointer<UInt8>(data.mutableBytes))
  313. do {
  314. try keychain.set(data, key: "RandomData")
  315. let _ = try keychain.getString("RandomData")
  316. } catch let error as NSError {
  317. XCTAssertEqual(error.domain, KeychainAccessErrorDomain)
  318. XCTAssertEqual(error.code, Int(Status.ConversionError.rawValue))
  319. }
  320. }
  321. func testGetPersistentRef() {
  322. let keychain = Keychain(service: "Twitter")
  323. XCTAssertNil(keychain["kishikawakatsumi"], "not stored password")
  324. do {
  325. let persistentRef = try keychain.get("kishikawakatsumi") { $0?.persistentRef }
  326. XCTAssertNil(persistentRef)
  327. } catch {
  328. XCTFail("error occurred")
  329. }
  330. keychain["kishikawakatsumi"] = "password1234"
  331. XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
  332. do {
  333. let persistentRef = try keychain.get("kishikawakatsumi") { $0?.persistentRef }
  334. XCTAssertNotNil(persistentRef)
  335. } catch {
  336. XCTFail("error occurred")
  337. }
  338. }
  339. #if os(iOS) || os(tvOS)
  340. func testSetAttributes() {
  341. do {
  342. var attributes = [String: AnyObject]()
  343. attributes[String(kSecAttrDescription)] = "Description Test"
  344. attributes[String(kSecAttrComment)] = "Comment Test"
  345. attributes[String(kSecAttrCreator)] = "Creator Test"
  346. attributes[String(kSecAttrType)] = "Type Test"
  347. attributes[String(kSecAttrLabel)] = "Label Test"
  348. attributes[String(kSecAttrIsInvisible)] = true
  349. attributes[String(kSecAttrIsNegative)] = true
  350. let keychain = Keychain(service: "Twitter")
  351. .attributes(attributes)
  352. .accessibility(.WhenPasscodeSetThisDeviceOnly, authenticationPolicy: .UserPresence)
  353. XCTAssertNil(keychain["kishikawakatsumi"], "not stored password")
  354. do {
  355. let attributes = try keychain.get("kishikawakatsumi") { $0 }
  356. XCTAssertNil(attributes)
  357. } catch {
  358. XCTFail("error occurred")
  359. }
  360. keychain["kishikawakatsumi"] = "password1234"
  361. XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
  362. do {
  363. let attributes = try keychain.get("kishikawakatsumi") { $0 }
  364. XCTAssertEqual(attributes?.`class`, ItemClass.GenericPassword.rawValue)
  365. XCTAssertEqual(attributes?.data, "password1234".dataUsingEncoding(NSUTF8StringEncoding))
  366. XCTAssertNil(attributes?.ref)
  367. XCTAssertNotNil(attributes?.persistentRef)
  368. XCTAssertEqual(attributes?.accessible, Accessibility.WhenPasscodeSetThisDeviceOnly.rawValue)
  369. XCTAssertNotNil(attributes?.accessControl)
  370. XCTAssertEqual(attributes?.accessGroup, "")
  371. XCTAssertNotNil(attributes?.synchronizable)
  372. XCTAssertNotNil(attributes?.creationDate)
  373. XCTAssertNotNil(attributes?.modificationDate)
  374. XCTAssertEqual(attributes?.attributeDescription, "Description Test")
  375. XCTAssertEqual(attributes?.comment, "Comment Test")
  376. XCTAssertEqual(attributes?.creator, "Creator Test")
  377. XCTAssertEqual(attributes?.type, "Type Test")
  378. XCTAssertEqual(attributes?.label, "Label Test")
  379. XCTAssertEqual(attributes?.isInvisible, true)
  380. XCTAssertEqual(attributes?.isNegative, true)
  381. XCTAssertEqual(attributes?.account, "kishikawakatsumi")
  382. XCTAssertEqual(attributes?.service, "Twitter")
  383. XCTAssertNil(attributes?.generic)
  384. XCTAssertNil(attributes?.securityDomain)
  385. XCTAssertNil(attributes?.server)
  386. XCTAssertNil(attributes?.`protocol`)
  387. XCTAssertNil(attributes?.authenticationType)
  388. XCTAssertNil(attributes?.port)
  389. XCTAssertNil(attributes?.path)
  390. XCTAssertEqual(attributes![String(kSecClass)] as? String, ItemClass.GenericPassword.rawValue)
  391. XCTAssertEqual(attributes![String(kSecValueData)] as? NSData, "password1234".dataUsingEncoding(NSUTF8StringEncoding))
  392. } catch {
  393. XCTFail("error occurred")
  394. }
  395. }
  396. do {
  397. var attributes = [String: AnyObject]()
  398. attributes[String(kSecAttrDescription)] = "Description Test"
  399. attributes[String(kSecAttrComment)] = "Comment Test"
  400. attributes[String(kSecAttrCreator)] = "Creator Test"
  401. attributes[String(kSecAttrType)] = "Type Test"
  402. attributes[String(kSecAttrLabel)] = "Label Test"
  403. attributes[String(kSecAttrIsInvisible)] = true
  404. attributes[String(kSecAttrIsNegative)] = true
  405. attributes[String(kSecAttrSecurityDomain)] = "securitydomain"
  406. let keychain = Keychain(server: NSURL(string: "https://example.com:443/api/login/")!, protocolType: .HTTPS)
  407. .attributes(attributes)
  408. XCTAssertNil(keychain["kishikawakatsumi"], "not stored password")
  409. do {
  410. let attributes = try keychain.get("kishikawakatsumi") { $0 }
  411. XCTAssertNil(attributes)
  412. } catch {
  413. XCTFail("error occurred")
  414. }
  415. do {
  416. keychain["kishikawakatsumi"] = "password1234"
  417. XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
  418. let attributes = try keychain.get("kishikawakatsumi") { $0 }
  419. XCTAssertEqual(attributes?.`class`, ItemClass.InternetPassword.rawValue)
  420. XCTAssertEqual(attributes?.data, "password1234".dataUsingEncoding(NSUTF8StringEncoding))
  421. XCTAssertNil(attributes?.ref)
  422. XCTAssertNotNil(attributes?.persistentRef)
  423. XCTAssertEqual(attributes?.accessible, Accessibility.AfterFirstUnlock.rawValue)
  424. XCTAssertNil(attributes?.accessControl)
  425. XCTAssertEqual(attributes?.accessGroup, "")
  426. XCTAssertNotNil(attributes?.synchronizable)
  427. XCTAssertNotNil(attributes?.creationDate)
  428. XCTAssertNotNil(attributes?.modificationDate)
  429. XCTAssertEqual(attributes?.attributeDescription, "Description Test")
  430. XCTAssertEqual(attributes?.comment, "Comment Test")
  431. XCTAssertEqual(attributes?.creator, "Creator Test")
  432. XCTAssertEqual(attributes?.type, "Type Test")
  433. XCTAssertEqual(attributes?.label, "Label Test")
  434. XCTAssertEqual(attributes?.isInvisible, true)
  435. XCTAssertEqual(attributes?.isNegative, true)
  436. XCTAssertEqual(attributes?.account, "kishikawakatsumi")
  437. XCTAssertNil(attributes?.service)
  438. XCTAssertNil(attributes?.generic)
  439. XCTAssertEqual(attributes?.securityDomain, "securitydomain")
  440. XCTAssertEqual(attributes?.server, "example.com")
  441. XCTAssertEqual(attributes?.`protocol`, ProtocolType.HTTPS.rawValue)
  442. XCTAssertEqual(attributes?.authenticationType, AuthenticationType.Default.rawValue)
  443. XCTAssertEqual(attributes?.port, 443)
  444. XCTAssertEqual(attributes?.path, "")
  445. } catch {
  446. XCTFail("error occurred")
  447. }
  448. do {
  449. let keychain = Keychain(server: NSURL(string: "https://example.com:443/api/login/")!, protocolType: .HTTPS)
  450. XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
  451. keychain["kishikawakatsumi"] = "1234password"
  452. XCTAssertEqual(keychain["kishikawakatsumi"], "1234password", "updated password")
  453. let attributes = try keychain.get("kishikawakatsumi") { $0 }
  454. XCTAssertEqual(attributes?.`class`, ItemClass.InternetPassword.rawValue)
  455. XCTAssertEqual(attributes?.data, "1234password".dataUsingEncoding(NSUTF8StringEncoding))
  456. XCTAssertNil(attributes?.ref)
  457. XCTAssertNotNil(attributes?.persistentRef)
  458. XCTAssertEqual(attributes?.accessible, Accessibility.AfterFirstUnlock.rawValue)
  459. XCTAssertNil(attributes?.accessControl)
  460. XCTAssertEqual(attributes?.accessGroup, "")
  461. XCTAssertNotNil(attributes?.synchronizable)
  462. XCTAssertNotNil(attributes?.creationDate)
  463. XCTAssertNotNil(attributes?.modificationDate)
  464. XCTAssertEqual(attributes?.attributeDescription, "Description Test")
  465. XCTAssertEqual(attributes?.comment, "Comment Test")
  466. XCTAssertEqual(attributes?.creator, "Creator Test")
  467. XCTAssertEqual(attributes?.type, "Type Test")
  468. XCTAssertEqual(attributes?.label, "Label Test")
  469. XCTAssertEqual(attributes?.isInvisible, true)
  470. XCTAssertEqual(attributes?.isNegative, true)
  471. XCTAssertEqual(attributes?.account, "kishikawakatsumi")
  472. XCTAssertNil(attributes?.service)
  473. XCTAssertNil(attributes?.generic)
  474. XCTAssertEqual(attributes?.securityDomain, "securitydomain")
  475. XCTAssertEqual(attributes?.server, "example.com")
  476. XCTAssertEqual(attributes?.`protocol`, ProtocolType.HTTPS.rawValue)
  477. XCTAssertEqual(attributes?.authenticationType, AuthenticationType.Default.rawValue)
  478. XCTAssertEqual(attributes?.port, 443)
  479. XCTAssertEqual(attributes?.path, "")
  480. } catch {
  481. XCTFail("error occurred")
  482. }
  483. do {
  484. let keychain = Keychain(server: NSURL(string: "https://example.com:443/api/login/")!, protocolType: .HTTPS)
  485. .attributes([String(kSecAttrDescription): "Updated Description"])
  486. XCTAssertEqual(keychain["kishikawakatsumi"], "1234password", "stored password")
  487. keychain["kishikawakatsumi"] = "password1234"
  488. XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "updated password")
  489. let attributes = keychain[attributes: "kishikawakatsumi"]
  490. XCTAssertEqual(attributes?.`class`, ItemClass.InternetPassword.rawValue)
  491. XCTAssertEqual(attributes?.data, "password1234".dataUsingEncoding(NSUTF8StringEncoding))
  492. XCTAssertNil(attributes?.ref)
  493. XCTAssertNotNil(attributes?.persistentRef)
  494. XCTAssertEqual(attributes?.accessible, Accessibility.AfterFirstUnlock.rawValue)
  495. XCTAssertNil(attributes?.accessControl)
  496. XCTAssertEqual(attributes?.accessGroup, "")
  497. XCTAssertNotNil(attributes?.synchronizable)
  498. XCTAssertNotNil(attributes?.creationDate)
  499. XCTAssertNotNil(attributes?.modificationDate)
  500. XCTAssertEqual(attributes?.attributeDescription, "Updated Description")
  501. XCTAssertEqual(attributes?.comment, "Comment Test")
  502. XCTAssertEqual(attributes?.creator, "Creator Test")
  503. XCTAssertEqual(attributes?.type, "Type Test")
  504. XCTAssertEqual(attributes?.label, "Label Test")
  505. XCTAssertEqual(attributes?.isInvisible, true)
  506. XCTAssertEqual(attributes?.isNegative, true)
  507. XCTAssertEqual(attributes?.account, "kishikawakatsumi")
  508. XCTAssertNil(attributes?.service)
  509. XCTAssertNil(attributes?.generic)
  510. XCTAssertEqual(attributes?.securityDomain, "securitydomain")
  511. XCTAssertEqual(attributes?.server, "example.com")
  512. XCTAssertEqual(attributes?.`protocol`, ProtocolType.HTTPS.rawValue)
  513. XCTAssertEqual(attributes?.authenticationType, AuthenticationType.Default.rawValue)
  514. XCTAssertEqual(attributes?.port, 443)
  515. XCTAssertEqual(attributes?.path, "")
  516. }
  517. }
  518. }
  519. #endif
  520. func testRemoveString() {
  521. let keychain = Keychain(service: "Twitter")
  522. XCTAssertNil(try! keychain.get("username"), "not stored username")
  523. XCTAssertNil(try! keychain.get("password"), "not stored password")
  524. do { try keychain.set("kishikawakatsumi", key: "username") } catch {}
  525. XCTAssertEqual(try! keychain.get("username"), "kishikawakatsumi", "stored username")
  526. do { try keychain.set("password1234", key: "password") } catch {}
  527. XCTAssertEqual(try! keychain.get("password"), "password1234", "stored password")
  528. do { try keychain.remove("username") } catch {}
  529. XCTAssertNil(try! keychain.get("username"), "removed username")
  530. XCTAssertEqual(try! keychain.get("password"), "password1234", "left password")
  531. do { try keychain.remove("password") } catch {}
  532. XCTAssertNil(try! keychain.get("username"), "removed username")
  533. XCTAssertNil(try! keychain.get("password"), "removed password")
  534. }
  535. func testRemoveData() {
  536. let JSONObject = ["username": "kishikawakatsumi", "password": "password1234"]
  537. let JSONData = try! NSJSONSerialization.dataWithJSONObject(JSONObject, options: [])
  538. let keychain = Keychain(service: "Twitter")
  539. XCTAssertNil(try! keychain.getData("JSONData"), "not stored JSON data")
  540. do { try keychain.set(JSONData, key: "JSONData") } catch {}
  541. XCTAssertEqual(try! keychain.getData("JSONData"), JSONData, "stored JSON data")
  542. do { try keychain.remove("JSONData") } catch {}
  543. XCTAssertNil(try! keychain.getData("JSONData"), "removed JSON data")
  544. }
  545. // MARK:
  546. func testSubscripting() {
  547. let keychain = Keychain(service: "Twitter")
  548. XCTAssertNil(keychain["username"], "not stored username")
  549. XCTAssertNil(keychain["password"], "not stored password")
  550. XCTAssertNil(keychain[string: "username"], "not stored username")
  551. XCTAssertNil(keychain[string: "password"], "not stored password")
  552. keychain["username"] = "kishikawakatsumi"
  553. XCTAssertEqual(keychain["username"], "kishikawakatsumi", "stored username")
  554. XCTAssertEqual(keychain[string: "username"], "kishikawakatsumi", "stored username")
  555. keychain["password"] = "password1234"
  556. XCTAssertEqual(keychain["password"], "password1234", "stored password")
  557. XCTAssertEqual(keychain[string: "password"], "password1234", "stored password")
  558. keychain[string: "username"] = nil
  559. XCTAssertNil(keychain["username"], "removed username")
  560. XCTAssertEqual(keychain["password"], "password1234", "left password")
  561. XCTAssertNil(keychain[string: "username"], "removed username")
  562. XCTAssertEqual(keychain[string: "password"], "password1234", "left password")
  563. keychain[string: "password"] = nil
  564. XCTAssertNil(keychain["username"], "removed username")
  565. XCTAssertNil(keychain["password"], "removed password")
  566. XCTAssertNil(keychain[string: "username"], "removed username")
  567. XCTAssertNil(keychain[string: "password"], "removed password")
  568. let JSONObject = ["username": "kishikawakatsumi", "password": "password1234"]
  569. let JSONData = try! NSJSONSerialization.dataWithJSONObject(JSONObject, options: [])
  570. XCTAssertNil(keychain[data:"JSONData"], "not stored JSON data")
  571. keychain[data: "JSONData"] = JSONData
  572. XCTAssertEqual(keychain[data: "JSONData"], JSONData, "stored JSON data")
  573. keychain[data: "JSONData"] = nil
  574. XCTAssertNil(keychain[data:"JSONData"], "removed JSON data")
  575. }
  576. // MARK:
  577. #if os(iOS)
  578. func testErrorHandling() {
  579. do {
  580. let keychain = Keychain(service: "Twitter", accessGroup: "12ABCD3E4F.shared")
  581. try keychain.removeAll()
  582. XCTAssertTrue(true, "no error occurred")
  583. } catch {
  584. XCTFail("error occurred")
  585. }
  586. do {
  587. let keychain = Keychain(service: "Twitter")
  588. try keychain.removeAll()
  589. XCTAssertTrue(true, "no error occurred")
  590. } catch {
  591. XCTFail("error occurred")
  592. }
  593. do {
  594. let keychain = Keychain(server: NSURL(string: "https://kishikawakatsumi.com")!, protocolType: .HTTPS)
  595. try keychain.removeAll()
  596. XCTAssertTrue(true, "no error occurred")
  597. } catch {
  598. XCTFail("error occurred")
  599. }
  600. do {
  601. let keychain = Keychain()
  602. try keychain.removeAll()
  603. XCTAssertTrue(true, "no error occurred")
  604. } catch {
  605. XCTFail("error occurred")
  606. }
  607. do {
  608. // Add Keychain items
  609. let keychain = Keychain(service: "Twitter")
  610. do {
  611. try keychain.set("kishikawa_katsumi", key: "username")
  612. XCTAssertTrue(true, "no error occurred")
  613. } catch {
  614. XCTFail("error occurred")
  615. }
  616. do {
  617. try keychain.set("password_1234", key: "password")
  618. XCTAssertTrue(true, "no error occurred")
  619. } catch {
  620. XCTFail("error occurred")
  621. }
  622. do {
  623. let username = try keychain.get("username")
  624. XCTAssertEqual(username, "kishikawa_katsumi")
  625. } catch {
  626. XCTFail("error occurred")
  627. }
  628. do {
  629. let password = try keychain.get("password")
  630. XCTAssertEqual(password, "password_1234")
  631. } catch {
  632. XCTFail("error occurred")
  633. }
  634. }
  635. do {
  636. // Update Keychain items
  637. let keychain = Keychain(service: "Twitter")
  638. do {
  639. try keychain.set("katsumi_kishikawa", key: "username")
  640. XCTAssertTrue(true, "no error occurred")
  641. } catch {
  642. XCTFail("error occurred")
  643. }
  644. do {
  645. try keychain.set("1234_password", key: "password")
  646. XCTAssertTrue(true, "no error occurred")
  647. } catch {
  648. XCTFail("error occurred")
  649. }
  650. do {
  651. let username = try keychain.get("username")
  652. XCTAssertEqual(username, "katsumi_kishikawa")
  653. } catch {
  654. XCTFail("error occurred")
  655. }
  656. do {
  657. let password = try keychain.get("password")
  658. XCTAssertEqual(password, "1234_password")
  659. } catch {
  660. XCTFail("error occurred")
  661. }
  662. }
  663. do {
  664. // Remove Keychain items
  665. let keychain = Keychain(service: "Twitter")
  666. do {
  667. try keychain.remove("username")
  668. XCTAssertNil(try! keychain.get("username"))
  669. } catch {
  670. XCTFail("error occurred")
  671. }
  672. do {
  673. try keychain.remove("password")
  674. XCTAssertNil(try! keychain.get("username"))
  675. } catch {
  676. XCTFail("error occurred")
  677. }
  678. }
  679. }
  680. #endif
  681. // MARK:
  682. func testSetStringWithCustomService() {
  683. let username_1 = "kishikawakatsumi"
  684. let password_1 = "password1234"
  685. let username_2 = "kishikawa_katsumi"
  686. let password_2 = "password_1234"
  687. let username_3 = "k_katsumi"
  688. let password_3 = "12341234"
  689. let service_1 = ""
  690. let service_2 = "com.kishikawakatsumi.KeychainAccess"
  691. let service_3 = "example.com"
  692. do { try Keychain().removeAll() } catch {}
  693. do { try Keychain(service: service_1).removeAll() } catch {}
  694. do { try Keychain(service: service_2).removeAll() } catch {}
  695. do { try Keychain(service: service_3).removeAll() } catch {}
  696. XCTAssertNil(try! Keychain().get("username"), "not stored username")
  697. XCTAssertNil(try! Keychain().get("password"), "not stored password")
  698. XCTAssertNil(try! Keychain(service: service_1).get("username"), "not stored username")
  699. XCTAssertNil(try! Keychain(service: service_1).get("password"), "not stored password")
  700. XCTAssertNil(try! Keychain(service: service_2).get("username"), "not stored username")
  701. XCTAssertNil(try! Keychain(service: service_2).get("password"), "not stored password")
  702. XCTAssertNil(try! Keychain(service: service_3).get("username"), "not stored username")
  703. XCTAssertNil(try! Keychain(service: service_3).get("password"), "not stored password")
  704. do { try Keychain().set(username_1, key: "username") } catch {}
  705. XCTAssertEqual(try! Keychain().get("username"), username_1, "stored username")
  706. XCTAssertEqual(try! Keychain(service: service_1).get("username"), username_1, "stored username")
  707. XCTAssertNil(try! Keychain(service: service_2).get("username"), "not stored username")
  708. XCTAssertNil(try! Keychain(service: service_3).get("username"), "not stored username")
  709. do { try Keychain(service: service_1).set(username_1, key: "username") } catch {}
  710. XCTAssertEqual(try! Keychain().get("username"), username_1, "stored username")
  711. XCTAssertEqual(try! Keychain(service: service_1).get("username"), username_1, "stored username")
  712. XCTAssertNil(try! Keychain(service: service_2).get("username"), "not stored username")
  713. XCTAssertNil(try! Keychain(service: service_3).get("username"), "not stored username")
  714. do { try Keychain(service: service_2).set(username_2, key: "username") } catch {}
  715. XCTAssertEqual(try! Keychain().get("username"), username_1, "stored username")
  716. XCTAssertEqual(try! Keychain(service: service_1).get("username"), username_1, "stored username")
  717. XCTAssertEqual(try! Keychain(service: service_2).get("username"), username_2, "stored username")
  718. XCTAssertNil(try! Keychain(service: service_3).get("username"), "not stored username")
  719. do { try Keychain(service: service_3).set(username_3, key: "username") } catch {}
  720. XCTAssertEqual(try! Keychain().get("username"), username_1, "stored username")
  721. XCTAssertEqual(try! Keychain(service: service_1).get("username"), username_1, "stored username")
  722. XCTAssertEqual(try! Keychain(service: service_2).get("username"), username_2, "stored username")
  723. XCTAssertEqual(try! Keychain(service: service_3).get("username"), username_3, "stored username")
  724. do { try Keychain().set(password_1, key: "password") } catch {}
  725. XCTAssertEqual(try! Keychain().get("password"), password_1, "stored password")
  726. XCTAssertEqual(try! Keychain(service: service_1).get("password"), password_1, "stored password")
  727. XCTAssertNil(try! Keychain(service: service_2).get("password"), "not stored password")
  728. XCTAssertNil(try! Keychain(service: service_3).get("password"), "not stored password")
  729. do { try Keychain(service: service_1).set(password_1, key: "password") } catch {}
  730. XCTAssertEqual(try! Keychain().get("password"), password_1, "stored password")
  731. XCTAssertEqual(try! Keychain(service: service_1).get("password"), password_1, "stored password")
  732. XCTAssertNil(try! Keychain(service: service_2).get("password"), "not stored password")
  733. XCTAssertNil(try! Keychain(service: service_3).get("password"), "not stored password")
  734. do { try Keychain(service: service_2).set(password_2, key: "password") } catch {}
  735. XCTAssertEqual(try! Keychain().get("password"), password_1, "stored password")
  736. XCTAssertEqual(try! Keychain(service: service_1).get("password"), password_1, "stored password")
  737. XCTAssertEqual(try! Keychain(service: service_2).get("password"), password_2, "stored password")
  738. XCTAssertNil(try! Keychain(service: service_3).get("password"), "not stored password")
  739. do { try Keychain(service: service_3).set(password_3, key: "password") } catch {}
  740. XCTAssertEqual(try! Keychain().get("password"), password_1, "stored password")
  741. XCTAssertEqual(try! Keychain(service: service_1).get("password"), password_1, "stored password")
  742. XCTAssertEqual(try! Keychain(service: service_2).get("password"), password_2, "stored password")
  743. XCTAssertEqual(try! Keychain(service: service_3).get("password"), password_3, "stored password")
  744. do { try Keychain().remove("username") } catch {}
  745. XCTAssertNil(try! Keychain().get("username"), "removed username")
  746. XCTAssertNil(try! Keychain(service: service_1).get("username"), "removed username")
  747. XCTAssertEqual(try! Keychain(service: service_2).get("username"), username_2, "left username")
  748. XCTAssertEqual(try! Keychain(service: service_3).get("username"), username_3, "left username")
  749. do { try Keychain(service: service_1).remove("username") } catch {}
  750. XCTAssertNil(try! Keychain().get("username"), "removed username")
  751. XCTAssertNil(try! Keychain(service: service_1).get("username"), "removed username")
  752. XCTAssertEqual(try! Keychain(service: service_2).get("username"), username_2, "left username")
  753. XCTAssertEqual(try! Keychain(service: service_3).get("username"), username_3, "left username")
  754. do { try Keychain(service: service_2).remove("username") } catch {}
  755. XCTAssertNil(try! Keychain().get("username"), "removed username")
  756. XCTAssertNil(try! Keychain(service: service_1).get("username"), "removed username")
  757. XCTAssertNil(try! Keychain(service: service_2).get("username"), "removed username")
  758. XCTAssertEqual(try! Keychain(service: service_3).get("username"), username_3, "left username")
  759. do { try Keychain(service: service_3).remove("username") } catch {}
  760. XCTAssertNil(try! Keychain().get("username"), "removed username")
  761. XCTAssertNil(try! Keychain(service: service_1).get("username"), "removed username")
  762. XCTAssertNil(try! Keychain(service: service_2).get("username"), "removed username")
  763. XCTAssertNil(try! Keychain(service: service_3).get("username"), "removed username")
  764. do { try Keychain().remove("password") } catch {}
  765. XCTAssertNil(try! Keychain().get("password"), "removed password")
  766. XCTAssertNil(try! Keychain(service: service_1).get("password"), "removed password")
  767. XCTAssertEqual(try! Keychain(service: service_2).get("password"), password_2, "left password")
  768. XCTAssertEqual(try! Keychain(service: service_3).get("password"), password_3, "left password")
  769. do { try Keychain(service: service_1).remove("password") } catch {}
  770. XCTAssertNil(try! Keychain().get("password"), "removed password")
  771. XCTAssertNil(try! Keychain(service: service_1).get("password"), "removed password")
  772. XCTAssertEqual(try! Keychain(service: service_2).get("password"), password_2, "left password")
  773. XCTAssertEqual(try! Keychain(service: service_3).get("password"), password_3, "left password")
  774. do { try Keychain(service: service_2).remove("password") } catch {}
  775. XCTAssertNil(try! Keychain().get("password"), "removed password")
  776. XCTAssertNil(try! Keychain(service: service_1).get("password"), "removed password")
  777. XCTAssertNil(try! Keychain(service: service_2).get("password"), "removed password")
  778. XCTAssertEqual(try! Keychain(service: service_3).get("password"), password_3, "left password")
  779. do { try Keychain(service: service_3).remove("password") } catch {}
  780. XCTAssertNil(try! Keychain().get("password"), "removed password")
  781. XCTAssertNil(try! Keychain(service: service_2).get("password"), "removed password")
  782. XCTAssertNil(try! Keychain(service: service_2).get("password"), "removed password")
  783. XCTAssertNil(try! Keychain(service: service_2).get("password"), "removed password")
  784. }
  785. // MARK:
  786. func testProperties() {
  787. guard #available(OSX 10.10, *) else {
  788. return
  789. }
  790. let keychain = Keychain()
  791. XCTAssertEqual(keychain.synchronizable, false)
  792. XCTAssertEqual(keychain.synchronizable(true).synchronizable, true)
  793. XCTAssertEqual(keychain.synchronizable(false).synchronizable, false)
  794. XCTAssertEqual(keychain.accessibility(.AfterFirstUnlock).accessibility, Accessibility.AfterFirstUnlock)
  795. XCTAssertEqual(keychain.accessibility(.WhenPasscodeSetThisDeviceOnly, authenticationPolicy: .UserPresence).accessibility, Accessibility.WhenPasscodeSetThisDeviceOnly)
  796. XCTAssertEqual(keychain.accessibility(.WhenPasscodeSetThisDeviceOnly, authenticationPolicy: .UserPresence).authenticationPolicy, AuthenticationPolicy.UserPresence)
  797. XCTAssertNil(keychain.label)
  798. XCTAssertEqual(keychain.label("Label").label, "Label")
  799. XCTAssertNil(keychain.comment)
  800. XCTAssertEqual(keychain.comment("Comment").comment, "Comment")
  801. XCTAssertEqual(keychain.authenticationPrompt("Prompt").authenticationPrompt, "Prompt")
  802. }
  803. // MARK:
  804. #if os(iOS)
  805. func testAllKeys() {
  806. do {
  807. let keychain = Keychain()
  808. keychain["key1"] = "value1"
  809. keychain["key2"] = "value2"
  810. keychain["key3"] = "value3"
  811. let allKeys = keychain.allKeys()
  812. XCTAssertEqual(allKeys.count, 3)
  813. XCTAssertEqual(allKeys.sort(), ["key1", "key2", "key3"])
  814. let allItems = keychain.allItems()
  815. XCTAssertEqual(allItems.count, 3)
  816. let sortedItems = allItems.sort { (item1, item2) -> Bool in
  817. let value1 = item1["value"] as! String
  818. let value2 = item2["value"] as! String
  819. return value1.compare(value2) == NSComparisonResult.OrderedAscending || value1.compare(value2) == NSComparisonResult.OrderedSame
  820. }
  821. XCTAssertEqual(sortedItems[0]["accessGroup"] as? String, "")
  822. XCTAssertEqual(sortedItems[0]["synchronizable"] as? String, "false")
  823. XCTAssertEqual(sortedItems[0]["service"] as? String, "")
  824. XCTAssertEqual(sortedItems[0]["value"] as? String, "value1")
  825. XCTAssertEqual(sortedItems[0]["key"] as? String, "key1")
  826. XCTAssertEqual(sortedItems[0]["class"] as? String, "GenericPassword")
  827. XCTAssertEqual(sortedItems[0]["accessibility"] as? String, "AfterFirstUnlock")
  828. XCTAssertEqual(sortedItems[1]["accessGroup"] as? String, "")
  829. XCTAssertEqual(sortedItems[1]["synchronizable"] as? String, "false")
  830. XCTAssertEqual(sortedItems[1]["service"] as? String, "")
  831. XCTAssertEqual(sortedItems[1]["value"] as? String, "value2")
  832. XCTAssertEqual(sortedItems[1]["key"] as? String, "key2")
  833. XCTAssertEqual(sortedItems[1]["class"] as? String, "GenericPassword")
  834. XCTAssertEqual(sortedItems[1]["accessibility"] as? String, "AfterFirstUnlock")
  835. XCTAssertEqual(sortedItems[2]["accessGroup"] as? String, "")
  836. XCTAssertEqual(sortedItems[2]["synchronizable"] as? String, "false")
  837. XCTAssertEqual(sortedItems[2]["service"] as? String, "")
  838. XCTAssertEqual(sortedItems[2]["value"] as? String, "value3")
  839. XCTAssertEqual(sortedItems[2]["key"] as? String, "key3")
  840. XCTAssertEqual(sortedItems[2]["class"] as? String, "GenericPassword")
  841. XCTAssertEqual(sortedItems[2]["accessibility"] as? String, "AfterFirstUnlock")
  842. }
  843. do {
  844. let keychain = Keychain(service: "service1")
  845. try! keychain
  846. .synchronizable(true)
  847. .accessibility(.WhenUnlockedThisDeviceOnly)
  848. .set("service1_value1", key: "service1_key1")
  849. try! keychain
  850. .synchronizable(false)
  851. .accessibility(.AfterFirstUnlockThisDeviceOnly)
  852. .set("service1_value2", key: "service1_key2")
  853. let allKeys = keychain.allKeys()
  854. XCTAssertEqual(allKeys.count, 2)
  855. XCTAssertEqual(allKeys.sort(), ["service1_key1", "service1_key2"])
  856. let allItems = keychain.allItems()
  857. XCTAssertEqual(allItems.count, 2)
  858. let sortedItems = allItems.sort { (item1, item2) -> Bool in
  859. let value1 = item1["value"] as! String
  860. let value2 = item2["value"] as! String
  861. return value1.compare(value2) == NSComparisonResult.OrderedAscending || value1.compare(value2) == NSComparisonResult.OrderedSame
  862. }
  863. XCTAssertEqual(sortedItems[0]["accessGroup"] as? String, "")
  864. XCTAssertEqual(sortedItems[0]["synchronizable"] as? String, "true")
  865. XCTAssertEqual(sortedItems[0]["service"] as? String, "service1")
  866. XCTAssertEqual(sortedItems[0]["value"] as? String, "service1_value1")
  867. XCTAssertEqual(sortedItems[0]["key"] as? String, "service1_key1")
  868. XCTAssertEqual(sortedItems[0]["class"] as? String, "GenericPassword")
  869. XCTAssertEqual(sortedItems[0]["accessibility"] as? String, "WhenUnlockedThisDeviceOnly")
  870. XCTAssertEqual(sortedItems[1]["accessGroup"] as? String, "")
  871. XCTAssertEqual(sortedItems[1]["synchronizable"] as? String, "false")
  872. XCTAssertEqual(sortedItems[1]["service"] as? String, "service1")
  873. XCTAssertEqual(sortedItems[1]["value"] as? String, "service1_value2")
  874. XCTAssertEqual(sortedItems[1]["key"] as? String, "service1_key2")
  875. XCTAssertEqual(sortedItems[1]["class"] as? String, "GenericPassword")
  876. XCTAssertEqual(sortedItems[1]["accessibility"] as? String, "AfterFirstUnlockThisDeviceOnly")
  877. }
  878. do {
  879. let keychain = Keychain(server: "https://google.com", protocolType: .HTTPS)
  880. try! keychain
  881. .synchronizable(false)
  882. .accessibility(.AlwaysThisDeviceOnly)
  883. .set("google.com_value1", key: "google.com_key1")
  884. try! keychain
  885. .synchronizable(true)
  886. .accessibility(.Always)
  887. .set("google.com_value2", key: "google.com_key2")
  888. let allKeys = keychain.allKeys()
  889. XCTAssertEqual(allKeys.count, 2)
  890. XCTAssertEqual(allKeys.sort(), ["google.com_key1", "google.com_key2"])
  891. let allItems = keychain.allItems()
  892. XCTAssertEqual(allItems.count, 2)
  893. let sortedItems = allItems.sort { (item1, item2) -> Bool in
  894. let value1 = item1["value"] as! String
  895. let value2 = item2["value"] as! String
  896. return value1.compare(value2) == NSComparisonResult.OrderedAscending || value1.compare(value2) == NSComparisonResult.OrderedSame
  897. }
  898. XCTAssertEqual(sortedItems[0]["synchronizable"] as? String, "false")
  899. XCTAssertEqual(sortedItems[0]["value"] as? String, "google.com_value1")
  900. XCTAssertEqual(sortedItems[0]["key"] as? String, "google.com_key1")
  901. XCTAssertEqual(sortedItems[0]["server"] as? String, "google.com")
  902. XCTAssertEqual(sortedItems[0]["class"] as? String, "InternetPassword")
  903. XCTAssertEqual(sortedItems[0]["authenticationType"] as? String, "Default")
  904. XCTAssertEqual(sortedItems[0]["protocol"] as? String, "HTTPS")
  905. XCTAssertEqual(sortedItems[0]["accessibility"] as? String, "AlwaysThisDeviceOnly")
  906. XCTAssertEqual(sortedItems[1]["synchronizable"] as? String, "true")
  907. XCTAssertEqual(sortedItems[1]["value"] as? String, "google.com_value2")
  908. XCTAssertEqual(sortedItems[1]["key"] as? String, "google.com_key2")
  909. XCTAssertEqual(sortedItems[1]["server"] as? String, "google.com")
  910. XCTAssertEqual(sortedItems[1]["class"] as? String, "InternetPassword")
  911. XCTAssertEqual(sortedItems[1]["authenticationType"] as? String, "Default")
  912. XCTAssertEqual(sortedItems[1]["protocol"] as? String, "HTTPS")
  913. XCTAssertEqual(sortedItems[1]["accessibility"] as? String, "Always")
  914. }
  915. do {
  916. let allKeys = Keychain.allKeys(.GenericPassword)
  917. XCTAssertEqual(allKeys.count, 5)
  918. let sortedKeys = allKeys.sort { (key1, key2) -> Bool in
  919. return key1.1.compare(key2.1) == NSComparisonResult.OrderedAscending || key1.1.compare(key2.1) == NSComparisonResult.OrderedSame
  920. }
  921. XCTAssertEqual(sortedKeys[0].0, "")
  922. XCTAssertEqual(sortedKeys[0].1, "key1")
  923. XCTAssertEqual(sortedKeys[1].0, "")
  924. XCTAssertEqual(sortedKeys[1].1, "key2")
  925. XCTAssertEqual(sortedKeys[2].0, "")
  926. XCTAssertEqual(sortedKeys[2].1, "key3")
  927. XCTAssertEqual(sortedKeys[3].0, "service1")
  928. XCTAssertEqual(sortedKeys[3].1, "service1_key1")
  929. XCTAssertEqual(sortedKeys[4].0, "service1")
  930. XCTAssertEqual(sortedKeys[4].1, "service1_key2")
  931. }
  932. do {
  933. let allKeys = Keychain.allKeys(.InternetPassword)
  934. XCTAssertEqual(allKeys.count, 2)
  935. let sortedKeys = allKeys.sort { (key1, key2) -> Bool in
  936. return key1.1.compare(key2.1) == NSComparisonResult.OrderedAscending || key1.1.compare(key2.1) == NSComparisonResult.OrderedSame
  937. }
  938. XCTAssertEqual(sortedKeys[0].0, "google.com")
  939. XCTAssertEqual(sortedKeys[0].1, "google.com_key1")
  940. XCTAssertEqual(sortedKeys[1].0, "google.com")
  941. XCTAssertEqual(sortedKeys[1].1, "google.com_key2")
  942. }
  943. }
  944. func testDescription() {
  945. do {
  946. let keychain = Keychain()
  947. XCTAssertEqual(keychain.description, "[]")
  948. XCTAssertEqual(keychain.debugDescription, "[]")
  949. }
  950. }
  951. #endif
  952. // MARK:
  953. func testAuthenticationPolicy() {
  954. guard #available(iOS 9.0, OSX 10.11, *) else {
  955. return
  956. }
  957. do {
  958. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  959. let policy: AuthenticationPolicy = [.UserPresence]
  960. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  961. var error: Unmanaged<CFError>?
  962. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  963. XCTAssertNil(error)
  964. XCTAssertNotNil(accessControl)
  965. }
  966. #if os(iOS)
  967. do {
  968. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  969. let policy: AuthenticationPolicy = [.UserPresence, .ApplicationPassword]
  970. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  971. var error: Unmanaged<CFError>?
  972. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  973. XCTAssertNil(error)
  974. XCTAssertNotNil(accessControl)
  975. }
  976. do {
  977. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  978. let policy: AuthenticationPolicy = [.UserPresence, .ApplicationPassword, .PrivateKeyUsage]
  979. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  980. var error: Unmanaged<CFError>?
  981. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  982. XCTAssertNil(error)
  983. XCTAssertNotNil(accessControl)
  984. }
  985. do {
  986. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  987. let policy: AuthenticationPolicy = [.ApplicationPassword]
  988. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  989. var error: Unmanaged<CFError>?
  990. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  991. XCTAssertNil(error)
  992. XCTAssertNotNil(accessControl)
  993. }
  994. do {
  995. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  996. let policy: AuthenticationPolicy = [.ApplicationPassword, .PrivateKeyUsage]
  997. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  998. var error: Unmanaged<CFError>?
  999. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1000. XCTAssertNil(error)
  1001. XCTAssertNotNil(accessControl)
  1002. }
  1003. do {
  1004. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1005. let policy: AuthenticationPolicy = [.PrivateKeyUsage]
  1006. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1007. var error: Unmanaged<CFError>?
  1008. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1009. XCTAssertNil(error)
  1010. XCTAssertNotNil(accessControl)
  1011. }
  1012. do {
  1013. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1014. let policy: AuthenticationPolicy = [.TouchIDAny]
  1015. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1016. var error: Unmanaged<CFError>?
  1017. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1018. XCTAssertNil(error)
  1019. XCTAssertNotNil(accessControl)
  1020. }
  1021. do {
  1022. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1023. let policy: AuthenticationPolicy = [.TouchIDAny, .DevicePasscode]
  1024. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1025. var error: Unmanaged<CFError>?
  1026. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1027. XCTAssertNil(error)
  1028. XCTAssertNotNil(accessControl)
  1029. }
  1030. do {
  1031. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1032. let policy: AuthenticationPolicy = [.TouchIDAny, .ApplicationPassword]
  1033. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1034. var error: Unmanaged<CFError>?
  1035. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1036. XCTAssertNil(error)
  1037. XCTAssertNotNil(accessControl)
  1038. }
  1039. do {
  1040. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1041. let policy: AuthenticationPolicy = [.TouchIDAny, .ApplicationPassword, .PrivateKeyUsage]
  1042. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1043. var error: Unmanaged<CFError>?
  1044. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1045. XCTAssertNil(error)
  1046. XCTAssertNotNil(accessControl)
  1047. }
  1048. do {
  1049. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1050. let policy: AuthenticationPolicy = [.TouchIDCurrentSet]
  1051. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1052. var error: Unmanaged<CFError>?
  1053. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1054. XCTAssertNil(error)
  1055. XCTAssertNotNil(accessControl)
  1056. }
  1057. do {
  1058. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1059. let policy: AuthenticationPolicy = [.TouchIDCurrentSet, .DevicePasscode]
  1060. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1061. var error: Unmanaged<CFError>?
  1062. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1063. XCTAssertNil(error)
  1064. XCTAssertNotNil(accessControl)
  1065. }
  1066. do {
  1067. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1068. let policy: AuthenticationPolicy = [.TouchIDCurrentSet, .ApplicationPassword]
  1069. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1070. var error: Unmanaged<CFError>?
  1071. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1072. XCTAssertNil(error)
  1073. XCTAssertNotNil(accessControl)
  1074. }
  1075. do {
  1076. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1077. let policy: AuthenticationPolicy = [.TouchIDCurrentSet, .ApplicationPassword, .PrivateKeyUsage]
  1078. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1079. var error: Unmanaged<CFError>?
  1080. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1081. XCTAssertNil(error)
  1082. XCTAssertNotNil(accessControl)
  1083. }
  1084. do {
  1085. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1086. let policy: AuthenticationPolicy = [.TouchIDAny, .Or, .DevicePasscode]
  1087. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1088. var error: Unmanaged<CFError>?
  1089. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1090. XCTAssertNil(error)
  1091. XCTAssertNotNil(accessControl)
  1092. }
  1093. do {
  1094. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1095. let policy: AuthenticationPolicy = [.TouchIDAny, .And, .DevicePasscode]
  1096. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1097. var error: Unmanaged<CFError>?
  1098. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1099. XCTAssertNil(error)
  1100. XCTAssertNotNil(accessControl)
  1101. }
  1102. #endif
  1103. #if os(OSX)
  1104. do {
  1105. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1106. let policy: AuthenticationPolicy = [.UserPresence]
  1107. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1108. var error: Unmanaged<CFError>?
  1109. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1110. XCTAssertNil(error)
  1111. XCTAssertNotNil(accessControl)
  1112. }
  1113. do {
  1114. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1115. let policy: AuthenticationPolicy = [.DevicePasscode]
  1116. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1117. var error: Unmanaged<CFError>?
  1118. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1119. XCTAssertNil(error)
  1120. XCTAssertNotNil(accessControl)
  1121. }
  1122. #endif
  1123. }
  1124. }