Skip to content

Commit b8a7fcf

Browse files
committed
Convert to Swift 3, fix build
1 parent 7d7ca17 commit b8a7fcf

29 files changed

+4030
-0
lines changed

swift3/CocoaFob.xcodeproj/project.pbxproj

Lines changed: 586 additions & 0 deletions
Large diffs are not rendered by default.

swift3/CocoaFob.xcodeproj/project.xcworkspace/contents.xcworkspacedata

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

swift3/CocoaFob/CFUtil.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//
2+
// CFUtil.swift
3+
// CocoaFob
4+
//
5+
// Created by Gleb Dolgich on 12/07/2015.
6+
// Copyright © 2015 PixelEspresso. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
func cfTry(_ err: CocoaFobError, cfBlock: (UnsafeMutablePointer<Unmanaged<CFError>?>) -> DarwinBoolean) throws {
12+
var cferr: Unmanaged<CFError>? = nil
13+
if !cfBlock(&cferr).boolValue {
14+
if let cferr = cferr?.takeRetainedValue() {
15+
throw cferr
16+
} else {
17+
throw err
18+
}
19+
}
20+
}
21+
22+
func cfTry<T>(_ err: CocoaFobError, cfBlock: (UnsafeMutablePointer<Unmanaged<CFError>?>) -> T!) throws -> T {
23+
var cferr: Unmanaged<CFError>? = nil
24+
if let result = cfBlock(&cferr) {
25+
return result
26+
}
27+
if let cferr = cferr?.takeRetainedValue() {
28+
throw cferr
29+
} else {
30+
throw err
31+
}
32+
}

swift3/CocoaFob/CocoaFob.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//
2+
// CocoaFob.h
3+
// CocoaFob
4+
//
5+
// Created by Gleb Dolgich on 05/07/2015.
6+
// Copyright © 2015 PixelEspresso. All rights reserved.
7+
//
8+
9+
#import <Cocoa/Cocoa.h>
10+
11+
//! Project version number for CocoaFob.
12+
FOUNDATION_EXPORT double CocoaFobVersionNumber;
13+
14+
//! Project version string for CocoaFob.
15+
FOUNDATION_EXPORT const unsigned char CocoaFobVersionString[];
16+
17+
// In this header, you should import all the public headers of your framework using statements like #import <CocoaFob/PublicHeader.h>
18+
19+

swift3/CocoaFob/CocoaFobError.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//
2+
// CocoaFobError.swift
3+
// CocoaFob
4+
//
5+
// Created by Gleb Dolgich on 05/07/2015.
6+
// Copyright © 2015 PixelEspresso. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
/**
12+
Custom error type:
13+
- Error: Unspecified error
14+
*/
15+
enum CocoaFobError: Error {
16+
case error
17+
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
//
2+
// CocoaFobKeyGenerator.swift
3+
// CocoaFob
4+
//
5+
// Created by Gleb Dolgich on 05/07/2015.
6+
// Copyright © 2015 PixelEspresso. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
/**
12+
Generates CocoaFob registration keys
13+
*/
14+
public struct CocoaFobLicGenerator {
15+
16+
var privKey: SecKey
17+
18+
// MARK: - Initialization
19+
20+
/**
21+
Initializes key generator with a private key in PEM format
22+
23+
- parameter privateKeyPEM: String containing PEM representation of the private key
24+
*/
25+
public init?(privateKeyPEM: String) {
26+
let emptyString = "" as NSString
27+
let password = Unmanaged.passUnretained(emptyString as AnyObject)
28+
var params = SecItemImportExportKeyParameters(
29+
version: UInt32(bitPattern: SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION),
30+
flags: SecKeyImportExportFlags.importOnlyOne,
31+
passphrase: password,
32+
alertTitle: Unmanaged.passUnretained(emptyString),
33+
alertPrompt: Unmanaged.passUnretained(emptyString),
34+
accessRef: nil,
35+
keyUsage: nil,
36+
keyAttributes: nil)
37+
var keyFormat = SecExternalFormat.formatPEMSequence
38+
var keyType = SecExternalItemType.itemTypePrivateKey
39+
if let keyData = privateKeyPEM.data(using: String.Encoding.utf8) {
40+
let keyBytes = unsafeBitCast((keyData as NSData).bytes, to: UnsafePointer<UInt8>.self)
41+
let keyDataCF = CFDataCreate(nil, keyBytes, keyData.count)!
42+
var importArray: CFArray? = nil
43+
let osStatus = withUnsafeMutablePointer(to: &keyFormat, {pKeyFormat -> OSStatus in
44+
return withUnsafeMutablePointer(to: &keyType, {pKeyType in
45+
return withUnsafeMutablePointer(to: &params, {pParams in
46+
return withUnsafeMutablePointer(to: &importArray, {pImportArray in
47+
return SecItemImport(keyDataCF, nil, pKeyFormat, pKeyType, SecItemImportExportFlags(rawValue: 0), pParams, nil, pImportArray)
48+
})
49+
})
50+
})
51+
})
52+
if osStatus != errSecSuccess || importArray == nil {
53+
return nil
54+
}
55+
let items = importArray! as NSArray
56+
if items.count >= 1 {
57+
self.privKey = items[0] as! SecKey
58+
} else {
59+
return nil
60+
}
61+
} else {
62+
return nil
63+
}
64+
}
65+
66+
// MARK: - Key generation
67+
68+
/**
69+
Generates registration key for a user name
70+
71+
- parameter userName: User name for which to generate a registration key
72+
- returns: Registration key
73+
*/
74+
public func generate(_ name: String) throws -> String {
75+
guard name != "" else { throw CocoaFobError.error }
76+
if let nameData = getNameData(name), let signer = getSigner(nameData), let encoder = getEncoder(), let group = connectTransforms(signer, encoder: encoder) {
77+
let regData = try cfTry(CocoaFobError.error) { return SecTransformExecute(group, $0) }
78+
if let reg = NSString(data: regData as! Data, encoding: String.Encoding.utf8.rawValue) {
79+
return String(reg).cocoaFobToReadableKey()
80+
} else {
81+
throw CocoaFobError.error
82+
}
83+
}
84+
throw CocoaFobError.error
85+
}
86+
87+
// MARK: - Utility functions
88+
89+
fileprivate func connectTransforms(_ signer: SecTransform, encoder: SecTransform) -> SecGroupTransform? {
90+
if let groupTransform = getGroupTransform() {
91+
return SecTransformConnectTransforms(signer, kSecTransformOutputAttributeName, encoder, kSecTransformInputAttributeName, groupTransform, nil)
92+
}
93+
return nil
94+
}
95+
96+
fileprivate func getGroupTransform() -> SecGroupTransform? {
97+
return SecTransformCreateGroupTransform()
98+
}
99+
100+
func getNameData(_ name: String) -> Data? {
101+
return name.data(using: String.Encoding.utf8)
102+
}
103+
104+
func getSigner(_ nameData: Data) -> SecTransform? {
105+
do {
106+
let signer = try cfTry(.error) { return SecSignTransformCreate(self.privKey, $0) }
107+
let _ = try cfTry(.error) { return SecTransformSetAttribute(signer, kSecTransformInputAttributeName, nameData as CFTypeRef, $0) }
108+
let _ = try cfTry(.error) { return SecTransformSetAttribute(signer, kSecDigestTypeAttribute, kSecDigestSHA1, $0) }
109+
return signer
110+
} catch {
111+
return nil
112+
}
113+
}
114+
115+
fileprivate func getEncoder() -> SecTransform? {
116+
do {
117+
let encoder = try cfTry(.error) { return SecEncodeTransformCreate(kSecBase32Encoding, $0) }
118+
return encoder
119+
} catch {
120+
return nil
121+
}
122+
}
123+
124+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
//
2+
// CocoaFobLicVerifier.swift
3+
// CocoaFob
4+
//
5+
// Created by Gleb Dolgich on 12/07/2015.
6+
// Copyright © 2015 PixelEspresso. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
/**
12+
Verifies CocoaFob registration keys
13+
*/
14+
public struct CocoaFobLicVerifier {
15+
16+
var pubKey: SecKey
17+
18+
// MARK: - Initialization
19+
20+
/**
21+
Initializes key verifier with a public key in PEM format
22+
23+
- parameter publicKeyPEM: String containing PEM representation of the public key
24+
*/
25+
public init?(publicKeyPEM: String) {
26+
let emptyString = "" as NSString
27+
let password = Unmanaged.passUnretained(emptyString as AnyObject)
28+
var params = SecItemImportExportKeyParameters(
29+
version: UInt32(bitPattern: SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION),
30+
flags: SecKeyImportExportFlags.importOnlyOne,
31+
passphrase: password,
32+
alertTitle: Unmanaged.passUnretained(emptyString),
33+
alertPrompt: Unmanaged.passUnretained(emptyString),
34+
accessRef: nil,
35+
keyUsage: nil,
36+
keyAttributes: nil)
37+
var keyFormat = SecExternalFormat.formatPEMSequence
38+
var keyType = SecExternalItemType.itemTypePublicKey
39+
if let keyData = publicKeyPEM.data(using: String.Encoding.utf8) {
40+
let keyBytes = unsafeBitCast((keyData as NSData).bytes, to: UnsafePointer<UInt8>.self)
41+
let keyDataCF = CFDataCreate(nil, keyBytes, keyData.count)!
42+
var importArray: CFArray? = nil
43+
let osStatus = withUnsafeMutablePointers(&keyFormat, &keyType) { (pKeyFormat, pKeyType) -> OSStatus in
44+
SecItemImport(keyDataCF, nil, pKeyFormat, pKeyType, SecItemImportExportFlags(rawValue: 0), &params, nil, &importArray)
45+
}
46+
if osStatus != errSecSuccess || importArray == nil {
47+
return nil
48+
}
49+
let items = importArray! as NSArray
50+
if items.count >= 1 {
51+
self.pubKey = items[0] as! SecKey
52+
} else {
53+
return nil
54+
}
55+
} else {
56+
return nil
57+
}
58+
}
59+
60+
/**
61+
Verifies registration key against registered name. Doesn't throw since you are most likely not interested in the reason registration verification failed.
62+
63+
- parameter regKey: Registration key string
64+
- parameter name: Registered name string
65+
- returns: `true` if the registration key is valid for the given name, `false` if not
66+
*/
67+
public func verify(_ regKey: String, forName name: String) -> Bool {
68+
do {
69+
if let keyData = regKey.cocoaFobFromReadableKey().data(using: String.Encoding.utf8), let nameData = name.data(using: String.Encoding.utf8) {
70+
let decoder = try getDecoder(keyData)
71+
let signature = try cfTry(.error) { SecTransformExecute(decoder, $0) }
72+
let verifier = try getVerifier(self.pubKey, signature: signature as! Data, nameData: nameData)
73+
let result = try cfTry(.error) { SecTransformExecute(verifier, $0) }
74+
let boolResult = result as! CFBooleanRef
75+
return Bool(boolResult)
76+
} else {
77+
return false
78+
}
79+
} catch {
80+
return false
81+
}
82+
}
83+
84+
// MARK: - Helper functions
85+
86+
fileprivate func getDecoder(_ keyData: Data) throws -> SecTransform {
87+
let decoder = try cfTry(.error) { return SecDecodeTransformCreate(kSecBase32Encoding, $0) }
88+
try cfTry(.error) { return SecTransformSetAttribute(decoder, kSecTransformInputAttributeName, keyData, $0) }
89+
return decoder
90+
}
91+
92+
fileprivate func getVerifier(_ publicKey: SecKey, signature: Data, nameData: Data) throws -> SecTransform {
93+
let verifier = try cfTry(.error) { return SecVerifyTransformCreate(publicKey, signature as CFData?, $0) }
94+
try cfTry(.error) { return SecTransformSetAttribute(verifier, kSecTransformInputAttributeName, nameData, $0) }
95+
try cfTry(.error) { return SecTransformSetAttribute(verifier, kSecDigestTypeAttribute, kSecDigestSHA1, $0) }
96+
return verifier
97+
}
98+
99+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//
2+
// CocoaFobStringExt.swift
3+
// CocoaFob
4+
//
5+
// Created by Gleb Dolgich on 12/07/2015.
6+
// Copyright © 2015 PixelEspresso. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
extension String {
12+
13+
/**
14+
Converts generated CocoaFob key to its human-readable form:
15+
- replaces Os with 8s and Is with 9s
16+
- trims padding characters at the end
17+
- inserts dashes every 5 characters
18+
19+
- returns: Human-readable registration key
20+
*/
21+
func cocoaFobToReadableKey() -> String {
22+
let replacedOwith8 = self.replacingOccurrences(of: "O", with: "8")
23+
let replacedIwith9 = replacedOwith8.replacingOccurrences(of: "I", with: "9")
24+
var key = replacedIwith9.replacingOccurrences(of: "=", with: "")
25+
26+
var index = 5
27+
while index < key.utf8.count {
28+
key.insert(contentsOf: ["-"], at: key.index(key.startIndex, offsetBy: index))
29+
index += 6
30+
}
31+
32+
return key
33+
}
34+
35+
/**
36+
Reverses readability changes to a supplied key:
37+
- removes dashes
38+
- replaces 9s with Is and 8s with Os
39+
40+
- returns: Compacted key ready for verification
41+
*/
42+
func cocoaFobFromReadableKey() -> String {
43+
let replaced9withI = self.replacingOccurrences(of: "9", with: "I")
44+
let replaced8withO = replaced9withI.replacingOccurrences(of: "8", with: "O")
45+
let key = replaced8withO.replacingOccurrences(of: "-", with: "")
46+
return key
47+
}
48+
49+
}

swift3/CocoaFob/Info.plist

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>CFBundleDevelopmentRegion</key>
6+
<string>en</string>
7+
<key>CFBundleExecutable</key>
8+
<string>$(EXECUTABLE_NAME)</string>
9+
<key>CFBundleIdentifier</key>
10+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11+
<key>CFBundleInfoDictionaryVersion</key>
12+
<string>6.0</string>
13+
<key>CFBundleName</key>
14+
<string>$(PRODUCT_NAME)</string>
15+
<key>CFBundlePackageType</key>
16+
<string>FMWK</string>
17+
<key>CFBundleShortVersionString</key>
18+
<string>1.0</string>
19+
<key>CFBundleSignature</key>
20+
<string>????</string>
21+
<key>CFBundleVersion</key>
22+
<string>$(CURRENT_PROJECT_VERSION)</string>
23+
<key>NSHumanReadableCopyright</key>
24+
<string>Copyright © 2015 PixelEspresso. All rights reserved.</string>
25+
<key>NSPrincipalClass</key>
26+
<string></string>
27+
</dict>
28+
</plist>

0 commit comments

Comments
 (0)