Skip to content

Commit

Permalink
Initial Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
kimar committed Jan 25, 2022
0 parents commit fcd267c
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
28 changes: 28 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// swift-tools-version:5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "KeychainWrapper",
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "KeychainWrapper",
targets: ["KeychainWrapper"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "KeychainWrapper",
dependencies: []),
.testTarget(
name: "KeychainWrapperTests",
dependencies: ["KeychainWrapper"]),
]
)
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# KeychainWrapper

A description of this package.
80 changes: 80 additions & 0 deletions Sources/KeychainWrapper/KeychainWrapper.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import Foundation

public typealias KeychainService = String
public typealias KeychainKey = String

public class KeychainWrapper {
private let service: String

public init(service: String) {
self.service = service
}

private func keychainQuery(withService service: KeychainService, forKey key: KeychainKey) -> [String: Any] {
return [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: key,
kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlock,
kSecAttrSynchronizable as String: kCFBooleanTrue!
]
}

@discardableResult
public func set(_ string: String, forKey key: KeychainKey) -> Bool {
var query = keychainQuery(withService: service, forKey: key)

guard let data = string.data(using: .utf8) else {
return false
}

guard SecItemCopyMatching(query as CFDictionary, nil) == noErr else {
query[kSecValueData as String] = data
let status = SecItemAdd(query as CFDictionary, nil)
return status == errSecSuccess
}

return SecItemUpdate(
query as CFDictionary,
NSDictionary(dictionary: [kSecValueData: data])
) == errSecSuccess
}

public func get(stringForKey key: KeychainKey) -> String? {
var query = keychainQuery(withService: service, forKey: key)
query[kSecReturnData as String] = kCFBooleanTrue
query[kSecReturnAttributes as String] = kCFBooleanTrue

var result: CFTypeRef?
guard SecItemCopyMatching(query as CFDictionary, &result) == noErr else {
return nil
}

guard
let dictionary = result as? [String: Any],
let data = dictionary[kSecValueData as String] as? Data
else {
return nil
}

return String(data: data, encoding: .utf8)
}

@discardableResult
public func remove(valueForKey key: KeychainKey) -> Bool {
let query = keychainQuery(withService: service, forKey: key)
return SecItemDelete(query as CFDictionary) == noErr
}

public subscript(key: KeychainKey) -> String? {
get {
return get(stringForKey: key)
} set {
guard let value = newValue else {
remove(valueForKey: key)
return
}
set(value, forKey: key)
}
}
}
17 changes: 17 additions & 0 deletions Tests/KeychainWrapperTests/KeychainWrapperTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import XCTest
@testable import KeychainWrapper

final class KeychainWrapperTests: XCTestCase {

private var sut: KeychainWrapper!

override func setUp() {
super.setUp()
sut = KeychainWrapper(service: "unitTests")
}

override func tearDown() {
sut = nil
super.tearDown()
}
}

0 comments on commit fcd267c

Please sign in to comment.