ds-01 1.0.11 → 1.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,206 @@
1
+ import Foundation
2
+ import Security
3
+
4
+ let keyTag = "com.ds01.cli.device-key"
5
+
6
+ func fail(_ message: String) -> Never {
7
+ fputs(message + "\n", stderr)
8
+ exit(1)
9
+ }
10
+
11
+ func getAccessControl() -> SecAccessControl {
12
+ var error: Unmanaged<CFError>?
13
+
14
+ guard let access = SecAccessControlCreateWithFlags(
15
+ nil,
16
+ kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
17
+ .privateKeyUsage,
18
+ &error
19
+ ) else {
20
+ if let error {
21
+ fail(error.takeRetainedValue().localizedDescription)
22
+ }
23
+
24
+ fail("Unable to create Secure Enclave access control.")
25
+ }
26
+
27
+ return access
28
+ }
29
+
30
+ func findPrivateKey() -> SecKey? {
31
+ let query: [String: Any] = [
32
+ kSecClass as String: kSecClassKey,
33
+ kSecAttrApplicationTag as String: keyTag.data(using: .utf8)!,
34
+ kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
35
+ kSecReturnRef as String: true
36
+ ]
37
+
38
+ var result: CFTypeRef?
39
+
40
+ let status = SecItemCopyMatching(
41
+ query as CFDictionary,
42
+ &result
43
+ )
44
+
45
+ guard status == errSecSuccess else {
46
+ return nil
47
+ }
48
+
49
+ return (result as! SecKey)
50
+ }
51
+
52
+ func createKey() {
53
+ if findPrivateKey() != nil {
54
+ print("EXISTS")
55
+ return
56
+ }
57
+
58
+ let access = getAccessControl()
59
+
60
+ let attributes: [String: Any] = [
61
+ kSecAttrKeyType as String:
62
+ kSecAttrKeyTypeECSECPrimeRandom,
63
+
64
+ kSecAttrKeySizeInBits as String:
65
+ 256,
66
+
67
+ kSecAttrTokenID as String:
68
+ kSecAttrTokenIDSecureEnclave,
69
+
70
+ kSecPrivateKeyAttrs as String: [
71
+ kSecAttrIsPermanent as String:
72
+ true,
73
+
74
+ kSecAttrApplicationTag as String:
75
+ keyTag.data(using: .utf8)!,
76
+
77
+ kSecAttrAccessControl as String:
78
+ access
79
+ ]
80
+ ]
81
+
82
+ var error: Unmanaged<CFError>?
83
+
84
+ guard SecKeyCreateRandomKey(
85
+ attributes as CFDictionary,
86
+ &error
87
+ ) != nil else {
88
+ if let error {
89
+ fail(error.takeRetainedValue().localizedDescription)
90
+ }
91
+
92
+ fail("Unable to create Secure Enclave key.")
93
+ }
94
+
95
+ print("CREATED")
96
+ }
97
+
98
+ func publicKey() {
99
+ guard let privateKey = findPrivateKey() else {
100
+ fail("DS01 Secure Enclave key not found.")
101
+ }
102
+
103
+ guard let publicKey = SecKeyCopyPublicKey(privateKey) else {
104
+ fail("Unable to obtain public key.")
105
+ }
106
+
107
+ var error: Unmanaged<CFError>?
108
+
109
+ guard let data = SecKeyCopyExternalRepresentation(
110
+ publicKey,
111
+ &error
112
+ ) else {
113
+ if let error {
114
+ fail(error.takeRetainedValue().localizedDescription)
115
+ }
116
+
117
+ fail("Unable to export public key.")
118
+ }
119
+
120
+ let base64 = (data as Data).base64EncodedString()
121
+
122
+ print(base64)
123
+ }
124
+
125
+ func sign(_ base64Data: String) {
126
+ guard let privateKey = findPrivateKey() else {
127
+ fail("DS01 Secure Enclave key not found.")
128
+ }
129
+
130
+ guard let data = Data(base64Encoded: base64Data) else {
131
+ fail("Invalid input data.")
132
+ }
133
+
134
+ let algorithm = SecKeyAlgorithm.ecdsaSignatureMessageX962SHA256
135
+
136
+ guard SecKeyIsAlgorithmSupported(
137
+ privateKey,
138
+ .sign,
139
+ algorithm
140
+ ) else {
141
+ fail("Secure Enclave key does not support signing.")
142
+ }
143
+
144
+ var error: Unmanaged<CFError>?
145
+
146
+ guard let signature = SecKeyCreateSignature(
147
+ privateKey,
148
+ algorithm,
149
+ data as CFData,
150
+ &error
151
+ ) else {
152
+ if let error {
153
+ fail(error.takeRetainedValue().localizedDescription)
154
+ }
155
+
156
+ fail("Secure Enclave signing failed.")
157
+ }
158
+
159
+ print((signature as Data).base64EncodedString())
160
+ }
161
+
162
+ func deleteKey() {
163
+ let query: [String: Any] = [
164
+ kSecClass as String: kSecClassKey,
165
+ kSecAttrApplicationTag as String:
166
+ keyTag.data(using: .utf8)!,
167
+ kSecAttrKeyType as String:
168
+ kSecAttrKeyTypeECSECPrimeRandom
169
+ ]
170
+
171
+ let status = SecItemDelete(
172
+ query as CFDictionary
173
+ )
174
+
175
+ if status != errSecSuccess &&
176
+ status != errSecItemNotFound {
177
+ fail("Unable to delete DS01 Secure Enclave key.")
178
+ }
179
+
180
+ print("DELETED")
181
+ }
182
+
183
+ guard CommandLine.arguments.count >= 2 else {
184
+ fail("Missing operation.")
185
+ }
186
+
187
+ switch CommandLine.arguments[1] {
188
+ case "create":
189
+ createKey()
190
+
191
+ case "public":
192
+ publicKey()
193
+
194
+ case "sign":
195
+ guard CommandLine.arguments.count >= 3 else {
196
+ fail("Missing data to sign.")
197
+ }
198
+
199
+ sign(CommandLine.arguments[2])
200
+
201
+ case "delete":
202
+ deleteKey()
203
+
204
+ default:
205
+ fail("Unknown operation.")
206
+ }
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "ds-01",
3
- "version": "1.0.11",
3
+ "version": "1.0.12",
4
4
  "description": "Make your site best with DS01",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "ds01": "dist/index.js"
8
8
  },
9
9
  "scripts": {
10
- "build": "tsc"
10
+ "build": "tsc && node scripts/copy-native.js"
11
11
  },
12
12
  "publishConfig": {
13
13
  "access": "public"
@@ -0,0 +1,15 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+
4
+ const source = path.resolve("src/native/macos-key-helper.swift");
5
+ const destinationDir = path.resolve("dist/native");
6
+ const destination = path.join(
7
+ destinationDir,
8
+ "macos-key-helper.swift",
9
+ );
10
+
11
+ fs.mkdirSync(destinationDir, { recursive: true });
12
+
13
+ fs.copyFileSync(source, destination);
14
+
15
+ console.log("✅ Copied macOS native helper.");