ds-01 1.0.8 → 1.0.10

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.
@@ -1 +1 @@
1
- {"version":3,"file":"secureKeyStore.d.ts","sourceRoot":"","sources":["../../src/utils/secureKeyStore.ts"],"names":[],"mappings":"AAwTA;;;;GAIG;AAEH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CASrD;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAQ1D;AAED,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,UAAU,CAAC,CAQrB;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CASrD"}
1
+ {"version":3,"file":"secureKeyStore.d.ts","sourceRoot":"","sources":["../../src/utils/secureKeyStore.ts"],"names":[],"mappings":"AA2WA;;;;GAIG;AAEH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CASrD;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAQ1D;AAED,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,UAAU,CAAC,CAQrB;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CASrD"}
@@ -9,8 +9,6 @@ const KEY_NAME = "DS01-CLI-Device-Key";
9
9
  const __filename = fileURLToPath(import.meta.url);
10
10
  const __dirname = path.dirname(__filename);
11
11
  function getMacHelperPath() {
12
- // dist/utils/secureKeyStore.js
13
- // ../native/macos-key-helper.swift
14
12
  return path.resolve(__dirname, "../native/macos-key-helper.swift");
15
13
  }
16
14
  function ensureSupportedOS() {
@@ -28,13 +26,18 @@ async function createWindowsDeviceKey() {
28
26
  const script = `
29
27
  $ErrorActionPreference = "Stop"
30
28
 
31
- $existing = Get-ChildItem Cert:\\CurrentUser\\My |
29
+ $certificates = @(Get-ChildItem Cert:\\CurrentUser\\My |
32
30
  Where-Object {
33
- $_.Subject -eq "CN=${KEY_NAME}"
34
- } |
35
- Select-Object -First 1
31
+ $_.Subject -eq "CN=${KEY_NAME}" -and
32
+ $_.HasPrivateKey -and
33
+ $_.PublicKey.Oid.Value -eq "1.2.840.113549.1.1.1"
34
+ })
36
35
 
37
- if ($existing) {
36
+ if ($certificates.Count -gt 1) {
37
+ throw "Multiple valid DS01 device certificates found. Remove old DS01 device certificates before continuing."
38
+ }
39
+
40
+ if ($certificates.Count -eq 1) {
38
41
  Write-Output "EXISTS"
39
42
  exit 0
40
43
  }
@@ -58,7 +61,11 @@ $params = @{
58
61
  NotAfter = (Get-Date).AddYears(10)
59
62
  }
60
63
 
61
- New-SelfSignedCertificate @params | Out-Null
64
+ $certificate = New-SelfSignedCertificate @params
65
+
66
+ if (-not $certificate) {
67
+ throw "Windows failed to create the DS01 device certificate."
68
+ }
62
69
 
63
70
  Write-Output "CREATED"
64
71
  `;
@@ -77,20 +84,41 @@ Write-Output "CREATED"
77
84
  throw new Error("Failed to create Windows DS01 device key.");
78
85
  }
79
86
  }
80
- async function getWindowsPublicKey() {
81
- const script = `
82
- $ErrorActionPreference = "Stop"
83
-
84
- $cert = Get-ChildItem Cert:\\CurrentUser\\My |
87
+ /**
88
+ * Find exactly one valid DS01 certificate.
89
+ *
90
+ * We intentionally do not use Select-Object -First 1.
91
+ *
92
+ * 0 certificates -> error
93
+ * 1 certificate -> use it
94
+ * 2+ certificates -> error
95
+ */
96
+ function getWindowsCertificateLookup() {
97
+ return `
98
+ $certificates = @(Get-ChildItem Cert:\\CurrentUser\\My |
85
99
  Where-Object {
86
- $_.Subject -eq "CN=${KEY_NAME}"
87
- } |
88
- Select-Object -First 1
100
+ $_.Subject -eq "CN=${KEY_NAME}" -and
101
+ $_.HasPrivateKey -and
102
+ $_.PublicKey.Oid.Value -eq "1.2.840.113549.1.1.1"
103
+ })
89
104
 
90
- if (-not $cert) {
105
+ if ($certificates.Count -eq 0) {
91
106
  throw "DS01 device key not found."
92
107
  }
93
108
 
109
+ if ($certificates.Count -gt 1) {
110
+ throw "Multiple valid DS01 device certificates found."
111
+ }
112
+
113
+ $cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]$certificates[0]
114
+ `;
115
+ }
116
+ async function getWindowsPublicKey() {
117
+ const script = `
118
+ $ErrorActionPreference = "Stop"
119
+
120
+ ${getWindowsCertificateLookup()}
121
+
94
122
  [Convert]::ToBase64String($cert.RawData)
95
123
  `;
96
124
  const { stdout } = await execFileAsync("powershell.exe", [
@@ -114,21 +142,14 @@ async function signWindowsDeviceKey(data) {
114
142
  const script = `
115
143
  $ErrorActionPreference = "Stop"
116
144
 
117
- $cert = Get-ChildItem Cert:\\CurrentUser\\My |
118
- Where-Object {
119
- $_.Subject -eq "CN=${KEY_NAME}"
120
- } |
121
- Select-Object -First 1
122
-
123
- if (-not $cert) {
124
- throw "DS01 device key not found."
125
- }
145
+ ${getWindowsCertificateLookup()}
126
146
 
127
147
  if (-not $cert.HasPrivateKey) {
128
148
  throw "DS01 device certificate has no private key."
129
149
  }
130
150
 
131
- $rsa = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($cert)
151
+ $rsa =
152
+ [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($cert)
132
153
 
133
154
  if (-not $rsa) {
134
155
  throw "Unable to access DS01 private signing key."
@@ -169,15 +190,22 @@ async function deleteWindowsDeviceKey() {
169
190
  const script = `
170
191
  $ErrorActionPreference = "Stop"
171
192
 
172
- $cert = Get-ChildItem Cert:\\CurrentUser\\My |
193
+ $certificates = @(Get-ChildItem Cert:\\CurrentUser\\My |
173
194
  Where-Object {
174
- $_.Subject -eq "CN=${KEY_NAME}"
175
- } |
176
- Select-Object -First 1
195
+ $_.Subject -eq "CN=${KEY_NAME}" -and
196
+ $_.HasPrivateKey -and
197
+ $_.PublicKey.Oid.Value -eq "1.2.840.113549.1.1.1"
198
+ })
199
+
200
+ if ($certificates.Count -gt 1) {
201
+ throw "Multiple valid DS01 device certificates found."
202
+ }
177
203
 
178
- if ($cert) {
179
- Remove-Item $cert.PSPath
204
+ if ($certificates.Count -eq 1) {
205
+ Remove-Item $certificates[0].PSPath
180
206
  }
207
+
208
+ Write-Output "DELETED"
181
209
  `;
182
210
  await execFileAsync("powershell.exe", [
183
211
  "-NoProfile",
@@ -208,8 +236,10 @@ async function runMacHelper(operation, data) {
208
236
  }
209
237
  async function createMacDeviceKey() {
210
238
  const result = await runMacHelper("create");
211
- if (result !== "CREATED" && result !== "EXISTS") {
212
- throw new Error(result || "Failed to create macOS Secure Enclave device key.");
239
+ if (result !== "CREATED" &&
240
+ result !== "EXISTS") {
241
+ throw new Error(result ||
242
+ "Failed to create macOS Secure Enclave device key.");
213
243
  }
214
244
  }
215
245
  async function getMacPublicKey() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ds-01",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "Make your site best with DS01",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,15 +14,13 @@ const __filename = fileURLToPath(import.meta.url);
14
14
  const __dirname = path.dirname(__filename);
15
15
 
16
16
  function getMacHelperPath(): string {
17
- // dist/utils/secureKeyStore.js
18
- // ../native/macos-key-helper.swift
19
17
  return path.resolve(
20
18
  __dirname,
21
19
  "../native/macos-key-helper.swift",
22
20
  );
23
21
  }
24
22
 
25
- function ensureSupportedOS() {
23
+ function ensureSupportedOS(): void {
26
24
  const platform = os.platform();
27
25
 
28
26
  if (platform !== "win32" && platform !== "darwin") {
@@ -42,13 +40,18 @@ async function createWindowsDeviceKey(): Promise<void> {
42
40
  const script = `
43
41
  $ErrorActionPreference = "Stop"
44
42
 
45
- $existing = Get-ChildItem Cert:\\CurrentUser\\My |
43
+ $certificates = @(Get-ChildItem Cert:\\CurrentUser\\My |
46
44
  Where-Object {
47
- $_.Subject -eq "CN=${KEY_NAME}"
48
- } |
49
- Select-Object -First 1
45
+ $_.Subject -eq "CN=${KEY_NAME}" -and
46
+ $_.HasPrivateKey -and
47
+ $_.PublicKey.Oid.Value -eq "1.2.840.113549.1.1.1"
48
+ })
50
49
 
51
- if ($existing) {
50
+ if ($certificates.Count -gt 1) {
51
+ throw "Multiple valid DS01 device certificates found. Remove old DS01 device certificates before continuing."
52
+ }
53
+
54
+ if ($certificates.Count -eq 1) {
52
55
  Write-Output "EXISTS"
53
56
  exit 0
54
57
  }
@@ -72,7 +75,11 @@ $params = @{
72
75
  NotAfter = (Get-Date).AddYears(10)
73
76
  }
74
77
 
75
- New-SelfSignedCertificate @params | Out-Null
78
+ $certificate = New-SelfSignedCertificate @params
79
+
80
+ if (-not $certificate) {
81
+ throw "Windows failed to create the DS01 device certificate."
82
+ }
76
83
 
77
84
  Write-Output "CREATED"
78
85
  `;
@@ -95,24 +102,48 @@ Write-Output "CREATED"
95
102
  const result = stdout.trim();
96
103
 
97
104
  if (result !== "CREATED" && result !== "EXISTS") {
98
- throw new Error("Failed to create Windows DS01 device key.");
105
+ throw new Error(
106
+ "Failed to create Windows DS01 device key.",
107
+ );
99
108
  }
100
109
  }
101
110
 
102
- async function getWindowsPublicKey(): Promise<string> {
103
- const script = `
104
- $ErrorActionPreference = "Stop"
105
-
106
- $cert = Get-ChildItem Cert:\\CurrentUser\\My |
111
+ /**
112
+ * Find exactly one valid DS01 certificate.
113
+ *
114
+ * We intentionally do not use Select-Object -First 1.
115
+ *
116
+ * 0 certificates -> error
117
+ * 1 certificate -> use it
118
+ * 2+ certificates -> error
119
+ */
120
+ function getWindowsCertificateLookup(): string {
121
+ return `
122
+ $certificates = @(Get-ChildItem Cert:\\CurrentUser\\My |
107
123
  Where-Object {
108
- $_.Subject -eq "CN=${KEY_NAME}"
109
- } |
110
- Select-Object -First 1
124
+ $_.Subject -eq "CN=${KEY_NAME}" -and
125
+ $_.HasPrivateKey -and
126
+ $_.PublicKey.Oid.Value -eq "1.2.840.113549.1.1.1"
127
+ })
111
128
 
112
- if (-not $cert) {
129
+ if ($certificates.Count -eq 0) {
113
130
  throw "DS01 device key not found."
114
131
  }
115
132
 
133
+ if ($certificates.Count -gt 1) {
134
+ throw "Multiple valid DS01 device certificates found."
135
+ }
136
+
137
+ $cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]$certificates[0]
138
+ `;
139
+ }
140
+
141
+ async function getWindowsPublicKey(): Promise<string> {
142
+ const script = `
143
+ $ErrorActionPreference = "Stop"
144
+
145
+ ${getWindowsCertificateLookup()}
146
+
116
147
  [Convert]::ToBase64String($cert.RawData)
117
148
  `;
118
149
 
@@ -134,7 +165,9 @@ if (-not $cert) {
134
165
  const certificate = stdout.trim();
135
166
 
136
167
  if (!certificate) {
137
- throw new Error("Unable to read Windows DS01 public certificate.");
168
+ throw new Error(
169
+ "Unable to read Windows DS01 public certificate.",
170
+ );
138
171
  }
139
172
 
140
173
  return certificate;
@@ -143,26 +176,20 @@ if (-not $cert) {
143
176
  async function signWindowsDeviceKey(
144
177
  data: Uint8Array,
145
178
  ): Promise<Uint8Array> {
146
- const dataBase64 = Buffer.from(data).toString("base64");
179
+ const dataBase64 =
180
+ Buffer.from(data).toString("base64");
147
181
 
148
182
  const script = `
149
183
  $ErrorActionPreference = "Stop"
150
184
 
151
- $cert = Get-ChildItem Cert:\\CurrentUser\\My |
152
- Where-Object {
153
- $_.Subject -eq "CN=${KEY_NAME}"
154
- } |
155
- Select-Object -First 1
156
-
157
- if (-not $cert) {
158
- throw "DS01 device key not found."
159
- }
185
+ ${getWindowsCertificateLookup()}
160
186
 
161
187
  if (-not $cert.HasPrivateKey) {
162
188
  throw "DS01 device certificate has no private key."
163
189
  }
164
190
 
165
- $rsa = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($cert)
191
+ $rsa =
192
+ [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($cert)
166
193
 
167
194
  if (-not $rsa) {
168
195
  throw "Unable to access DS01 private signing key."
@@ -202,25 +229,36 @@ finally {
202
229
  const signature = stdout.trim();
203
230
 
204
231
  if (!signature) {
205
- throw new Error("Failed to sign data with Windows device key.");
232
+ throw new Error(
233
+ "Failed to sign data with Windows device key.",
234
+ );
206
235
  }
207
236
 
208
- return new Uint8Array(Buffer.from(signature, "base64"));
237
+ return new Uint8Array(
238
+ Buffer.from(signature, "base64"),
239
+ );
209
240
  }
210
241
 
211
242
  async function deleteWindowsDeviceKey(): Promise<void> {
212
243
  const script = `
213
244
  $ErrorActionPreference = "Stop"
214
245
 
215
- $cert = Get-ChildItem Cert:\\CurrentUser\\My |
246
+ $certificates = @(Get-ChildItem Cert:\\CurrentUser\\My |
216
247
  Where-Object {
217
- $_.Subject -eq "CN=${KEY_NAME}"
218
- } |
219
- Select-Object -First 1
248
+ $_.Subject -eq "CN=${KEY_NAME}" -and
249
+ $_.HasPrivateKey -and
250
+ $_.PublicKey.Oid.Value -eq "1.2.840.113549.1.1.1"
251
+ })
220
252
 
221
- if ($cert) {
222
- Remove-Item $cert.PSPath
253
+ if ($certificates.Count -gt 1) {
254
+ throw "Multiple valid DS01 device certificates found."
223
255
  }
256
+
257
+ if ($certificates.Count -eq 1) {
258
+ Remove-Item $certificates[0].PSPath
259
+ }
260
+
261
+ Write-Output "DELETED"
224
262
  `;
225
263
 
226
264
  await execFileAsync(
@@ -246,7 +284,11 @@ if ($cert) {
246
284
  */
247
285
 
248
286
  async function runMacHelper(
249
- operation: "create" | "public" | "sign" | "delete",
287
+ operation:
288
+ | "create"
289
+ | "public"
290
+ | "sign"
291
+ | "delete",
250
292
  data?: Uint8Array,
251
293
  ): Promise<string> {
252
294
  const helper = getMacHelperPath();
@@ -254,7 +296,9 @@ async function runMacHelper(
254
296
  const args = [helper, operation];
255
297
 
256
298
  if (data) {
257
- args.push(Buffer.from(data).toString("base64"));
299
+ args.push(
300
+ Buffer.from(data).toString("base64"),
301
+ );
258
302
  }
259
303
 
260
304
  const { stdout } = await execFileAsync(
@@ -269,17 +313,23 @@ async function runMacHelper(
269
313
  }
270
314
 
271
315
  async function createMacDeviceKey(): Promise<void> {
272
- const result = await runMacHelper("create");
316
+ const result =
317
+ await runMacHelper("create");
273
318
 
274
- if (result !== "CREATED" && result !== "EXISTS") {
319
+ if (
320
+ result !== "CREATED" &&
321
+ result !== "EXISTS"
322
+ ) {
275
323
  throw new Error(
276
- result || "Failed to create macOS Secure Enclave device key.",
324
+ result ||
325
+ "Failed to create macOS Secure Enclave device key.",
277
326
  );
278
327
  }
279
328
  }
280
329
 
281
330
  async function getMacPublicKey(): Promise<string> {
282
- const result = await runMacHelper("public");
331
+ const result =
332
+ await runMacHelper("public");
283
333
 
284
334
  if (!result) {
285
335
  throw new Error(
@@ -293,7 +343,8 @@ async function getMacPublicKey(): Promise<string> {
293
343
  async function signMacDeviceKey(
294
344
  data: Uint8Array,
295
345
  ): Promise<Uint8Array> {
296
- const result = await runMacHelper("sign", data);
346
+ const result =
347
+ await runMacHelper("sign", data);
297
348
 
298
349
  if (!result) {
299
350
  throw new Error(