@certchip/signer 0.1.11
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.
- package/README.md +587 -0
- package/bin/signer.js +19 -0
- package/bin/signercli.js +18 -0
- package/bin/win32-x64/Certchip.dll +0 -0
- package/bin/win32-x64/otpkey.dll +0 -0
- package/bin/win32-x64/signer.exe +0 -0
- package/bin/win32-x64/signercli.exe +0 -0
- package/lib/index.d.ts +122 -0
- package/lib/index.js +285 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,587 @@
|
|
|
1
|
+
# @certchip/signer
|
|
2
|
+
|
|
3
|
+
Cross-platform code and document signing CLI tool with SSH key authentication.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Cross-platform** - Windows, Linux, macOS (x64, arm64)
|
|
8
|
+
- **SSH Key Authentication** - Ed25519, ECDSA, RSA support
|
|
9
|
+
- **Code Signing** - PE executables (EXE, DLL, SYS, OCX), MSI, MSP, CAB
|
|
10
|
+
- **Document Signing** - PDF with visual signature (watermark, box, barcode, QR code)
|
|
11
|
+
- **Script Signing** - PowerShell, VBScript with Authenticode
|
|
12
|
+
- **Text/Source Signing** - JS, Python, Go, Rust, and more
|
|
13
|
+
- **Hash-based Signing** - Default mode: only hash sent to server, not the file
|
|
14
|
+
- **Windows KSP** - Native Windows crypto integration (Windows only)
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Global installation (recommended)
|
|
20
|
+
npm install -g @certchip/signer
|
|
21
|
+
|
|
22
|
+
# Or local installation
|
|
23
|
+
npm install @certchip/signer
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
### signercli (Cross-platform: Windows, Linux, macOS)
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# Login with SSH key authentication
|
|
32
|
+
signercli -login https://signer.example.com username
|
|
33
|
+
|
|
34
|
+
# Sign a file
|
|
35
|
+
signercli myapp.exe
|
|
36
|
+
|
|
37
|
+
# Verify signature
|
|
38
|
+
signercli -verify myapp.exe
|
|
39
|
+
|
|
40
|
+
# Logout
|
|
41
|
+
signercli -logout
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### signer (Windows only - KSP integration)
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Login (certificate is installed to Windows certificate store)
|
|
48
|
+
signer -login https://signer.example.com username
|
|
49
|
+
|
|
50
|
+
# Sign using Windows signtool.exe
|
|
51
|
+
signtool sign /n "Your Certificate CN" /fd sha256 /tr http://timestamp.digicert.com /td sha256 myapp.exe
|
|
52
|
+
|
|
53
|
+
# Or sign directly with signer
|
|
54
|
+
signer myapp.exe
|
|
55
|
+
|
|
56
|
+
# Logout (removes certificate from store)
|
|
57
|
+
signer -logout
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### With local installation (npx)
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# signercli (Cross-platform)
|
|
64
|
+
npx signercli -login https://signer.example.com username
|
|
65
|
+
npx signercli myapp.exe
|
|
66
|
+
|
|
67
|
+
# signer (Windows only)
|
|
68
|
+
npx signer -login https://signer.example.com username
|
|
69
|
+
npx signer myapp.exe
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## CLI Commands
|
|
73
|
+
|
|
74
|
+
This package provides two CLI tools with different purposes:
|
|
75
|
+
|
|
76
|
+
| | signercli | signer |
|
|
77
|
+
|---|-----------|--------|
|
|
78
|
+
| **Purpose** | Direct file signing | Windows signtool integration |
|
|
79
|
+
| **Platform** | Windows, Linux, macOS | Windows only |
|
|
80
|
+
| **How it works** | Signs files directly via server API | Provides certificates to Windows crypto system |
|
|
81
|
+
| **Best for** | CI/CD, cross-platform, simple signing | Windows developers using signtool.exe |
|
|
82
|
+
|
|
83
|
+
### When to use which tool?
|
|
84
|
+
|
|
85
|
+
| Scenario | Recommended |
|
|
86
|
+
|----------|-------------|
|
|
87
|
+
| CI/CD pipeline (any platform) | signercli |
|
|
88
|
+
| Linux/macOS development | signercli |
|
|
89
|
+
| Simple file signing | signercli |
|
|
90
|
+
| Using Windows signtool.exe | signer |
|
|
91
|
+
| Windows certificate store integration | signer |
|
|
92
|
+
| Visual Studio post-build signing | signercli or signer |
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
### signercli (Cross-platform)
|
|
97
|
+
|
|
98
|
+
The main CLI tool for code and document signing. Signs files directly by communicating with the signing server. Works on all platforms without any additional setup.
|
|
99
|
+
|
|
100
|
+
#### Authentication
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# Auto-detect authentication (SSH key if exists, otherwise password prompt)
|
|
104
|
+
signercli -login <url> [username]
|
|
105
|
+
|
|
106
|
+
# SSH Key Authentication (explicit)
|
|
107
|
+
signercli -login <url> -key ~/.ssh/id_ed25519
|
|
108
|
+
signercli -login <url> username -key ~/.ssh/id_rsa
|
|
109
|
+
|
|
110
|
+
# Password Authentication
|
|
111
|
+
signercli -login <url> -user <userid> # Password prompted interactively
|
|
112
|
+
signercli -login <url> -user <userid> -pw <password> # Password on command line
|
|
113
|
+
|
|
114
|
+
# Login Options
|
|
115
|
+
-profile <name> Use specific config profile
|
|
116
|
+
-expires <time> Token expiration (e.g., 24h, 7d, 1w)
|
|
117
|
+
-cert-id <id> Pre-specify certificate ID
|
|
118
|
+
-cert-serial <sn> Pre-specify certificate serial number
|
|
119
|
+
-include-chain Include certificate chain in token
|
|
120
|
+
|
|
121
|
+
# Logout
|
|
122
|
+
signercli -logout [url]
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
#### File Signing
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# Basic signing (default: hash-only mode)
|
|
129
|
+
signercli <file>
|
|
130
|
+
|
|
131
|
+
# Signing options
|
|
132
|
+
signercli <file> -o <output> # Specify output file
|
|
133
|
+
signercli <file> -save-signed # Save with _signed suffix (preserve original)
|
|
134
|
+
signercli <file> -hash-only # Hash-based signing (default)
|
|
135
|
+
signercli <file> -file-upload # Upload entire file to server
|
|
136
|
+
signercli <file> -hash-algorithm <alg> # sha256, sha384, sha512
|
|
137
|
+
signercli <file> -timestamp-url <url> # Timestamp server URL
|
|
138
|
+
signercli <file> -profile <name> # Use config profile
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
> **Note:** Hash-only signing is the default mode. Only the file hash is sent to the server, not the entire file.
|
|
142
|
+
|
|
143
|
+
#### Signature Verification
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
signercli -verify <file>
|
|
147
|
+
signercli -verify <file> -signature-id <id> # Verify specific signature
|
|
148
|
+
signercli -verify <file> -profile <name>
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
#### Certificate Management
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# List available certificates
|
|
155
|
+
signercli -codesign-list
|
|
156
|
+
|
|
157
|
+
# Get/Set certificate ID
|
|
158
|
+
signercli -codesign-id # Show current certificate ID
|
|
159
|
+
signercli -codesign-id <id> # Set certificate ID
|
|
160
|
+
|
|
161
|
+
# Get certificate PEM
|
|
162
|
+
signercli -codesign-cert # Fetch current certificate
|
|
163
|
+
signercli -codesign-cert -id <id> # Fetch specific certificate
|
|
164
|
+
signercli -codesign-cert -o cert.pem # Save to file
|
|
165
|
+
|
|
166
|
+
# Set private key password (for password-protected keys on server)
|
|
167
|
+
signercli -codesign-set <password>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
#### Configuration
|
|
171
|
+
|
|
172
|
+
Profiles store connection settings. The `default` profile is used when no profile is specified. Other profiles inherit missing settings from `default`.
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
# View configuration
|
|
176
|
+
signercli -config # Show config file
|
|
177
|
+
signercli -config list # List all profiles
|
|
178
|
+
signercli -config show <name> # Show profile details
|
|
179
|
+
|
|
180
|
+
# Create/Update profile
|
|
181
|
+
signercli -config set <name> [options]
|
|
182
|
+
|
|
183
|
+
# Delete profile
|
|
184
|
+
signercli -config delete <name>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**Profile Inheritance Example:**
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
# Set common settings in 'default' profile
|
|
191
|
+
signercli -config set default -host https://signer.example.com -username admin
|
|
192
|
+
|
|
193
|
+
# Create 'production' profile (inherits host and username from default)
|
|
194
|
+
signercli -config set production -cert-id prod-cert-001
|
|
195
|
+
|
|
196
|
+
# Create 'staging' profile with different host (overrides default)
|
|
197
|
+
signercli -config set staging -host https://staging.example.com -cert-id staging-cert
|
|
198
|
+
|
|
199
|
+
# Usage
|
|
200
|
+
signercli -login # Uses 'default' profile
|
|
201
|
+
signercli -login -profile production # Uses 'production' (inherits from default)
|
|
202
|
+
signercli -login -profile staging # Uses 'staging' (overrides host)
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**Profile Options:**
|
|
206
|
+
|
|
207
|
+
| Option | Description |
|
|
208
|
+
|--------|-------------|
|
|
209
|
+
| `-host <url>` | Server URL |
|
|
210
|
+
| `-ssh-key-path <path>` | SSH private key path |
|
|
211
|
+
| `-username <name>` | SSH username |
|
|
212
|
+
| `-user <id>` | Password auth user ID |
|
|
213
|
+
| `-cert-id <id>` | Default certificate ID |
|
|
214
|
+
| `-cert-serial <sn>` | Certificate serial number |
|
|
215
|
+
| `-expires <time>` | Token expiration (24h, 7d, 1w) |
|
|
216
|
+
| `-include-chain` | Include certificate chain |
|
|
217
|
+
| `-timestamp-url <url>` | Timestamp server URL |
|
|
218
|
+
| `-hash-algorithm <alg>` | Default hash algorithm |
|
|
219
|
+
|
|
220
|
+
**Document Signing Options:**
|
|
221
|
+
|
|
222
|
+
| Option | Description |
|
|
223
|
+
|--------|-------------|
|
|
224
|
+
| `-doc-style <style>` | watermark, box, barcode, qrcode |
|
|
225
|
+
| `-doc-position <pos>` | bottom-right, bottom-left, top-right, top-left, center |
|
|
226
|
+
| `-doc-sig-position <pos>` | left, center, right (for barcode/qrcode) |
|
|
227
|
+
| `-doc-font-size <size>` | Font size for signature |
|
|
228
|
+
| `-doc-opacity <value>` | Opacity (0.0-1.0 or 0-100) |
|
|
229
|
+
|
|
230
|
+
#### Windows DLL Installation
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
# Install DLLs to System32 (auto-requests UAC elevation)
|
|
234
|
+
signercli -install
|
|
235
|
+
|
|
236
|
+
# Remove DLLs from System32
|
|
237
|
+
signercli -uninstall
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
#### Help & Debugging
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
signercli -help
|
|
244
|
+
signercli -version
|
|
245
|
+
|
|
246
|
+
# Log levels (append to any command for debugging)
|
|
247
|
+
signercli <file> LOG_DBG # Debug output
|
|
248
|
+
signercli <file> LOG_INF # Info output
|
|
249
|
+
# Available: LOG_NON, LOG_ERR, LOG_WRN, LOG_DBG, LOG_INF
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
### signer (Windows only)
|
|
255
|
+
|
|
256
|
+
Windows-specific tool that integrates with the Windows cryptographic system via KSP (Key Storage Provider). Instead of signing files directly, it registers certificates in the Windows certificate store, allowing you to use standard Windows tools like `signtool.exe`.
|
|
257
|
+
|
|
258
|
+
**How it works:**
|
|
259
|
+
1. Login fetches your certificate from the server
|
|
260
|
+
2. Certificate is registered in Windows certificate store
|
|
261
|
+
3. KSP provider enables private key operations via the server
|
|
262
|
+
4. Use `signtool.exe` or other Windows signing tools normally
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
# Authentication (fetches certificate to Windows store)
|
|
266
|
+
signer -login <url> [username] # Login and register certificate
|
|
267
|
+
signer -logout # Logout and remove certificate
|
|
268
|
+
signer -list # List available certificates
|
|
269
|
+
|
|
270
|
+
# KSP Provider Management
|
|
271
|
+
signer -register # Register Certchip KSP provider
|
|
272
|
+
signer -unregister # Unregister KSP provider
|
|
273
|
+
signer -enum # List all crypto providers
|
|
274
|
+
signer -container # List key containers
|
|
275
|
+
|
|
276
|
+
# DLL Installation (auto-requests UAC elevation)
|
|
277
|
+
signer -install # Install DLLs to System32
|
|
278
|
+
signer -uninstall # Remove DLLs from System32
|
|
279
|
+
|
|
280
|
+
# After login, use standard Windows signing tools
|
|
281
|
+
signtool sign /n "Certificate Name" /fd sha256 myapp.exe
|
|
282
|
+
signtool sign /sha1 <thumbprint> /fd sha256 /tr http://timestamp.digicert.com myapp.exe
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
### DLL System Installation (Windows)
|
|
288
|
+
|
|
289
|
+
For system-wide DLL access (required for signtool integration), install DLLs to System32:
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
# Both tools auto-request UAC elevation when needed
|
|
293
|
+
signercli -install
|
|
294
|
+
signer -install
|
|
295
|
+
|
|
296
|
+
# To remove DLLs from System32
|
|
297
|
+
signercli -uninstall
|
|
298
|
+
signer -uninstall
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
**What gets installed:**
|
|
302
|
+
- `otpkey.dll` → `C:\Windows\System32\otpkey.dll`
|
|
303
|
+
- `Certchip.dll` → `C:\Windows\System32\Certchip.dll`
|
|
304
|
+
|
|
305
|
+
**When to use:**
|
|
306
|
+
- When using `signtool.exe` with the Certchip KSP provider
|
|
307
|
+
- When other applications need to access the DLLs
|
|
308
|
+
- For system-wide certificate store integration
|
|
309
|
+
|
|
310
|
+
## Node.js API
|
|
311
|
+
|
|
312
|
+
```javascript
|
|
313
|
+
const signer = require('@certchip/signer');
|
|
314
|
+
|
|
315
|
+
// Login
|
|
316
|
+
await signer.login('https://signer.example.com', 'username', {
|
|
317
|
+
keyPath: '~/.ssh/id_ed25519',
|
|
318
|
+
expires: '24h',
|
|
319
|
+
certId: 'abc123',
|
|
320
|
+
includeChain: true
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
// Sign a file
|
|
324
|
+
await signer.sign('myapp.exe', {
|
|
325
|
+
output: 'myapp_signed.exe',
|
|
326
|
+
hashAlgorithm: 'sha256',
|
|
327
|
+
timestampUrl: 'http://timestamp.digicert.com'
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
// Verify signature
|
|
331
|
+
const result = await signer.verify('myapp_signed.exe');
|
|
332
|
+
console.log(result.valid ? 'Valid' : 'Invalid');
|
|
333
|
+
|
|
334
|
+
// Configuration
|
|
335
|
+
await signer.config('set', 'production', {
|
|
336
|
+
host: 'https://signer.example.com',
|
|
337
|
+
username: 'john',
|
|
338
|
+
expires: '12h'
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
// List certificates
|
|
342
|
+
const certs = await signer.listCertificates();
|
|
343
|
+
|
|
344
|
+
// Logout
|
|
345
|
+
await signer.logout();
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
## Configuration Profiles
|
|
349
|
+
|
|
350
|
+
Create reusable signing profiles:
|
|
351
|
+
|
|
352
|
+
```bash
|
|
353
|
+
# Create a code signing profile
|
|
354
|
+
signercli -config set production \
|
|
355
|
+
-host https://signer.example.com \
|
|
356
|
+
-username john \
|
|
357
|
+
-ssh-key-path ~/.ssh/id_ed25519 \
|
|
358
|
+
-expires 24h \
|
|
359
|
+
-cert-id abc123 \
|
|
360
|
+
-include-chain \
|
|
361
|
+
-timestamp-url http://timestamp.digicert.com \
|
|
362
|
+
-hash-algorithm sha256
|
|
363
|
+
|
|
364
|
+
# Create a document signing profile with visual signature
|
|
365
|
+
signercli -config set pdf-signing \
|
|
366
|
+
-host https://signer.example.com \
|
|
367
|
+
-username john \
|
|
368
|
+
-doc-style qrcode \
|
|
369
|
+
-doc-position bottom-right \
|
|
370
|
+
-doc-sig-position center \
|
|
371
|
+
-doc-font-size 12 \
|
|
372
|
+
-doc-opacity 0.8
|
|
373
|
+
|
|
374
|
+
# Use the profile
|
|
375
|
+
signercli -login -profile production
|
|
376
|
+
signercli myapp.exe -profile production
|
|
377
|
+
signercli document.pdf -profile pdf-signing
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
## Supported File Types
|
|
381
|
+
|
|
382
|
+
| Type | Extensions | Method |
|
|
383
|
+
|------|------------|--------|
|
|
384
|
+
| **Code** | .exe, .dll, .sys, .ocx, .msi, .msp, .cab | Authenticode |
|
|
385
|
+
| **Document** | .pdf | Server-based with visual signature |
|
|
386
|
+
| **Script** | .ps1, .vbs | Authenticode |
|
|
387
|
+
| **Java** | .jar | JAR signing |
|
|
388
|
+
| **Text/Source** | .js, .ts, .py, .java, .c, .cpp, .go, .rs, .sh, .yml, .json, .xml, .html, .sql, .md, .txt | Embedded signature |
|
|
389
|
+
|
|
390
|
+
## Package Contents
|
|
391
|
+
|
|
392
|
+
```
|
|
393
|
+
@certchip/signer/
|
|
394
|
+
├── lib/
|
|
395
|
+
│ ├── index.js # Node.js API
|
|
396
|
+
│ └── index.d.ts # TypeScript definitions
|
|
397
|
+
└── bin/
|
|
398
|
+
├── signercli.js # Cross-platform wrapper
|
|
399
|
+
├── signer.js # Windows KSP wrapper
|
|
400
|
+
└── win32-x64/
|
|
401
|
+
├── signercli.exe # 9.3 MB (static build)
|
|
402
|
+
├── signer.exe # 420 KB (static build)
|
|
403
|
+
├── otpkey.dll # 6.2 MB (static linked)
|
|
404
|
+
└── Certchip.dll # 700 KB (KSP provider)
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### Binary Comparison
|
|
408
|
+
|
|
409
|
+
| | signercli | signer |
|
|
410
|
+
|---|-----------|--------|
|
|
411
|
+
| **Platform** | Windows, Linux, macOS | Windows only |
|
|
412
|
+
| **Dependencies** | None (static build) | otpkey.dll, Certchip.dll |
|
|
413
|
+
| **Size** | 9.3 MB | 420 KB + 6.9 MB DLLs |
|
|
414
|
+
| **Signing method** | Direct (via server API) | Indirect (via Windows crypto) |
|
|
415
|
+
| **Windows KSP** | No | Yes |
|
|
416
|
+
| **signtool compatible** | No | Yes |
|
|
417
|
+
| **UAC auto-elevation** | Yes | Yes |
|
|
418
|
+
| **Use case** | CI/CD, cross-platform | Windows developers, signtool |
|
|
419
|
+
|
|
420
|
+
## Examples
|
|
421
|
+
|
|
422
|
+
### CI/CD Pipeline
|
|
423
|
+
|
|
424
|
+
```bash
|
|
425
|
+
#!/bin/bash
|
|
426
|
+
set -e
|
|
427
|
+
|
|
428
|
+
# Login
|
|
429
|
+
signercli -login "$SIGNER_URL" "$SIGNER_USER" -key "$SSH_KEY_PATH"
|
|
430
|
+
|
|
431
|
+
# Sign all executables
|
|
432
|
+
for exe in dist/*.exe; do
|
|
433
|
+
signercli "$exe"
|
|
434
|
+
done
|
|
435
|
+
|
|
436
|
+
# Logout
|
|
437
|
+
signercli -logout
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
### TypeScript Usage
|
|
441
|
+
|
|
442
|
+
```typescript
|
|
443
|
+
import * as signer from '@certchip/signer';
|
|
444
|
+
|
|
445
|
+
async function signRelease() {
|
|
446
|
+
await signer.login('https://signer.example.com', 'username');
|
|
447
|
+
|
|
448
|
+
const result = await signer.sign('app.exe', {
|
|
449
|
+
output: 'app_signed.exe',
|
|
450
|
+
hashAlgorithm: 'sha256'
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
if (result.success) {
|
|
454
|
+
console.log('Signed:', result.outputPath);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
await signer.logout();
|
|
458
|
+
}
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
### Document Signing with Visual Signature
|
|
462
|
+
|
|
463
|
+
```bash
|
|
464
|
+
# Login
|
|
465
|
+
signercli -login https://signer.example.com username
|
|
466
|
+
|
|
467
|
+
# Sign PDF with QR code signature
|
|
468
|
+
signercli document.pdf \
|
|
469
|
+
-doc-style qrcode \
|
|
470
|
+
-doc-position bottom-right \
|
|
471
|
+
-o document_signed.pdf
|
|
472
|
+
|
|
473
|
+
# Sign PDF with watermark
|
|
474
|
+
signercli contract.pdf \
|
|
475
|
+
-doc-style watermark \
|
|
476
|
+
-doc-position center \
|
|
477
|
+
-doc-opacity 0.3
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
### Windows KSP with signtool
|
|
481
|
+
|
|
482
|
+
```batch
|
|
483
|
+
REM First-time setup (run as Administrator):
|
|
484
|
+
REM 1. Install DLLs to System32
|
|
485
|
+
signercli -install
|
|
486
|
+
|
|
487
|
+
REM 2. Register KSP provider
|
|
488
|
+
signer -register
|
|
489
|
+
|
|
490
|
+
REM Daily usage:
|
|
491
|
+
REM Login to get certificate
|
|
492
|
+
signer -login https://signer.example.com username
|
|
493
|
+
|
|
494
|
+
REM Sign with signtool
|
|
495
|
+
signtool sign /n "Your Certificate" /fd sha256 /tr http://timestamp.digicert.com myapp.exe
|
|
496
|
+
|
|
497
|
+
REM Verify
|
|
498
|
+
signtool verify /pa myapp.exe
|
|
499
|
+
|
|
500
|
+
REM Logout
|
|
501
|
+
signer -logout
|
|
502
|
+
|
|
503
|
+
REM To uninstall:
|
|
504
|
+
signer -unregister
|
|
505
|
+
signercli -uninstall
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
## Authentication
|
|
509
|
+
|
|
510
|
+
### SSH Key (Recommended)
|
|
511
|
+
|
|
512
|
+
```bash
|
|
513
|
+
# Generate Ed25519 key (if needed)
|
|
514
|
+
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519
|
|
515
|
+
|
|
516
|
+
# Login with default key
|
|
517
|
+
signercli -login https://server.com username
|
|
518
|
+
|
|
519
|
+
# Login with specific key
|
|
520
|
+
signercli -login https://server.com username -key ~/.ssh/id_rsa
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
### Password
|
|
524
|
+
|
|
525
|
+
```bash
|
|
526
|
+
signercli -login https://server.com -user admin -pw password
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
## Environment Variables
|
|
530
|
+
|
|
531
|
+
| Variable | Description |
|
|
532
|
+
|----------|-------------|
|
|
533
|
+
| `SIGNER_URL` | Default server URL |
|
|
534
|
+
| `SIGNER_USER` | Default username |
|
|
535
|
+
| `SIGNER_KEY_PATH` | Default SSH key path |
|
|
536
|
+
| `SIGNER_CERT_ID` | Default certificate ID |
|
|
537
|
+
|
|
538
|
+
## Troubleshooting
|
|
539
|
+
|
|
540
|
+
### "signer command is only available on Windows"
|
|
541
|
+
|
|
542
|
+
The `signer` command requires Windows KSP integration. Use `signercli` for cross-platform signing.
|
|
543
|
+
|
|
544
|
+
### "DLL not found"
|
|
545
|
+
|
|
546
|
+
The `signer.exe` requires `otpkey.dll` and `Certchip.dll`. These are automatically included when installed via npm. No additional MSYS2 or system DLLs are required.
|
|
547
|
+
|
|
548
|
+
For signtool integration or system-wide access, install DLLs to System32:
|
|
549
|
+
```bash
|
|
550
|
+
signercli -install
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
### "Access denied" during installation
|
|
554
|
+
|
|
555
|
+
The `-install` command requires Administrator privileges. Both `signercli` and `signer` will automatically request UAC elevation. If the UAC prompt is cancelled, run the command prompt as Administrator.
|
|
556
|
+
|
|
557
|
+
### "Token expired"
|
|
558
|
+
|
|
559
|
+
Login again:
|
|
560
|
+
```bash
|
|
561
|
+
signercli -login https://server.com username
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
### "Permission denied"
|
|
565
|
+
|
|
566
|
+
On Linux/macOS, ensure the binary is executable:
|
|
567
|
+
```bash
|
|
568
|
+
chmod +x node_modules/@certchip/signer/bin/*/signercli
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
## Requirements
|
|
572
|
+
|
|
573
|
+
- **Node.js** >= 14.0.0
|
|
574
|
+
- **Platforms**: Windows x64 (Linux x64/arm64, macOS x64/arm64 coming soon)
|
|
575
|
+
- **Server**: Certchip Signer API compatible server
|
|
576
|
+
|
|
577
|
+
> **Note:** The current npm package includes Windows x64 binaries only. Linux and macOS binaries will be added in a future release.
|
|
578
|
+
|
|
579
|
+
## License
|
|
580
|
+
|
|
581
|
+
Copyright (c) 2025 Certchip. All rights reserved.
|
|
582
|
+
|
|
583
|
+
## Links
|
|
584
|
+
|
|
585
|
+
- [Homepage](https://certchip.com/signer)
|
|
586
|
+
- [Documentation](https://certchip.com/signer/help)
|
|
587
|
+
- [Issues](https://github.com/certchip/signer-cli/issues)
|
package/bin/signer.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const { spawn } = require('child_process');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
|
|
6
|
+
function getBinaryPath(name) {
|
|
7
|
+
const platform = os.platform();
|
|
8
|
+
if (platform !== 'win32') {
|
|
9
|
+
console.error('signer command is only available on Windows (Windows KSP integration)');
|
|
10
|
+
console.error('Use signercli for cross-platform code signing');
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
return path.join(__dirname, 'win32-x64', name + '.exe');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const binary = getBinaryPath('signer');
|
|
17
|
+
const child = spawn(binary, process.argv.slice(2), { stdio: 'inherit', windowsHide: true });
|
|
18
|
+
child.on('close', code => process.exit(code || 0));
|
|
19
|
+
child.on('error', err => { console.error(err.message); process.exit(1); });
|
package/bin/signercli.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const { spawn } = require('child_process');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
|
|
6
|
+
function getBinaryPath(name) {
|
|
7
|
+
const platform = os.platform();
|
|
8
|
+
const arch = os.arch();
|
|
9
|
+
let platformId = platform === 'win32' ? 'win32' : platform === 'darwin' ? 'darwin' : 'linux';
|
|
10
|
+
let archId = arch === 'x64' || arch === 'x86_64' ? 'x64' : 'arm64';
|
|
11
|
+
const ext = platform === 'win32' ? '.exe' : '';
|
|
12
|
+
return path.join(__dirname, platformId + '-' + archId, name + ext);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const binary = getBinaryPath('signercli');
|
|
16
|
+
const child = spawn(binary, process.argv.slice(2), { stdio: 'inherit', windowsHide: true });
|
|
17
|
+
child.on('close', code => process.exit(code || 0));
|
|
18
|
+
child.on('error', err => { console.error(err.message); process.exit(1); });
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @certchip/signer - TypeScript definitions
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface ExecResult {
|
|
6
|
+
stdout: string;
|
|
7
|
+
stderr: string;
|
|
8
|
+
code: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface LoginOptions {
|
|
12
|
+
keyPath?: string;
|
|
13
|
+
expires?: string;
|
|
14
|
+
certId?: string;
|
|
15
|
+
certSerial?: string;
|
|
16
|
+
includeChain?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface LoginResult {
|
|
20
|
+
success: boolean;
|
|
21
|
+
message: string;
|
|
22
|
+
code: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface LogoutResult {
|
|
26
|
+
success: boolean;
|
|
27
|
+
message: string;
|
|
28
|
+
code: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface SignOptions {
|
|
32
|
+
output?: string;
|
|
33
|
+
profile?: string;
|
|
34
|
+
hashAlgorithm?: string;
|
|
35
|
+
timestampUrl?: string;
|
|
36
|
+
hashOnly?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface SignResult {
|
|
40
|
+
success: boolean;
|
|
41
|
+
message: string;
|
|
42
|
+
code: number;
|
|
43
|
+
outputPath?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface VerifyOptions {
|
|
47
|
+
signatureId?: string;
|
|
48
|
+
profile?: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface VerifyResult {
|
|
52
|
+
valid: boolean;
|
|
53
|
+
message: string;
|
|
54
|
+
code: number;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface ConfigOptions {
|
|
58
|
+
host?: string;
|
|
59
|
+
username?: string;
|
|
60
|
+
keyPath?: string;
|
|
61
|
+
expires?: string;
|
|
62
|
+
certId?: string;
|
|
63
|
+
timestampUrl?: string;
|
|
64
|
+
includeChain?: boolean;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface ConfigResult {
|
|
68
|
+
success: boolean;
|
|
69
|
+
message: string;
|
|
70
|
+
code: number;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface ListCertificatesResult {
|
|
74
|
+
success: boolean;
|
|
75
|
+
message: string;
|
|
76
|
+
code: number;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Execute signer command with raw arguments
|
|
81
|
+
*/
|
|
82
|
+
export function exec(args: string[]): Promise<ExecResult>;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Login to signing server
|
|
86
|
+
*/
|
|
87
|
+
export function login(serverUrl: string, username?: string, options?: LoginOptions): Promise<LoginResult>;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Logout from signing server
|
|
91
|
+
*/
|
|
92
|
+
export function logout(serverUrl?: string): Promise<LogoutResult>;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Sign a file
|
|
96
|
+
*/
|
|
97
|
+
export function sign(filePath: string, options?: SignOptions): Promise<SignResult>;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Verify signature on a file
|
|
101
|
+
*/
|
|
102
|
+
export function verify(filePath: string, options?: VerifyOptions): Promise<VerifyResult>;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Get or set configuration
|
|
106
|
+
*/
|
|
107
|
+
export function config(action?: string, profile?: string, options?: ConfigOptions): Promise<ConfigResult>;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* List available certificates
|
|
111
|
+
*/
|
|
112
|
+
export function listCertificates(): Promise<ListCertificatesResult>;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Get version information
|
|
116
|
+
*/
|
|
117
|
+
export function version(): Promise<string>;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Get the path to the signer binary
|
|
121
|
+
*/
|
|
122
|
+
export function getBinaryPath(): string;
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @certchip/signercli - Node.js API
|
|
3
|
+
*
|
|
4
|
+
* Provides programmatic access to the signercli CLI functionality.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* const signercli = require('@certchip/signercli');
|
|
8
|
+
*
|
|
9
|
+
* // Login with SSH key
|
|
10
|
+
* await signercli.login('https://server.com', 'username');
|
|
11
|
+
*
|
|
12
|
+
* // Sign a file
|
|
13
|
+
* await signercli.sign('myapp.exe');
|
|
14
|
+
*
|
|
15
|
+
* // Verify signature
|
|
16
|
+
* const result = await signercli.verify('myapp.exe');
|
|
17
|
+
*
|
|
18
|
+
* // Logout
|
|
19
|
+
* await signercli.logout();
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
'use strict';
|
|
23
|
+
|
|
24
|
+
const { spawn } = require('child_process');
|
|
25
|
+
const path = require('path');
|
|
26
|
+
const os = require('os');
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Get the path to the signer binary
|
|
30
|
+
*/
|
|
31
|
+
function getBinaryPath() {
|
|
32
|
+
const platform = os.platform();
|
|
33
|
+
const arch = os.arch();
|
|
34
|
+
|
|
35
|
+
let platformId;
|
|
36
|
+
switch (platform) {
|
|
37
|
+
case 'win32': platformId = 'win32'; break;
|
|
38
|
+
case 'linux': platformId = 'linux'; break;
|
|
39
|
+
case 'darwin': platformId = 'darwin'; break;
|
|
40
|
+
default: throw new Error(`Unsupported platform: ${platform}`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let archId;
|
|
44
|
+
switch (arch) {
|
|
45
|
+
case 'x64':
|
|
46
|
+
case 'x86_64':
|
|
47
|
+
archId = 'x64';
|
|
48
|
+
break;
|
|
49
|
+
case 'arm64':
|
|
50
|
+
case 'aarch64':
|
|
51
|
+
archId = 'arm64';
|
|
52
|
+
break;
|
|
53
|
+
default:
|
|
54
|
+
throw new Error(`Unsupported architecture: ${arch}`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const binaryName = platform === 'win32' ? 'signercli.exe' : 'signercli';
|
|
58
|
+
return path.join(__dirname, '..', 'bin', `${platformId}-${archId}`, binaryName);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Execute signer command
|
|
63
|
+
* @param {string[]} args - Command line arguments
|
|
64
|
+
* @returns {Promise<{stdout: string, stderr: string, code: number}>}
|
|
65
|
+
*/
|
|
66
|
+
function exec(args) {
|
|
67
|
+
return new Promise((resolve, reject) => {
|
|
68
|
+
const binary = getBinaryPath();
|
|
69
|
+
const proc = spawn(binary, args, {
|
|
70
|
+
stdio: ['inherit', 'pipe', 'pipe'],
|
|
71
|
+
windowsHide: true
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
let stdout = '';
|
|
75
|
+
let stderr = '';
|
|
76
|
+
|
|
77
|
+
proc.stdout.on('data', (data) => {
|
|
78
|
+
stdout += data.toString();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
proc.stderr.on('data', (data) => {
|
|
82
|
+
stderr += data.toString();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
proc.on('close', (code) => {
|
|
86
|
+
resolve({ stdout, stderr, code: code || 0 });
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
proc.on('error', (error) => {
|
|
90
|
+
reject(error);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Login to signing server
|
|
97
|
+
* @param {string} serverUrl - Server URL
|
|
98
|
+
* @param {string} [username] - SSH username (optional for keyless mode)
|
|
99
|
+
* @param {Object} [options] - Login options
|
|
100
|
+
* @param {string} [options.keyPath] - SSH key path
|
|
101
|
+
* @param {string} [options.expires] - Token expiration (e.g., "24h")
|
|
102
|
+
* @param {string} [options.certId] - Certificate ID
|
|
103
|
+
* @param {boolean} [options.includeChain] - Include certificate chain
|
|
104
|
+
* @returns {Promise<{success: boolean, message: string}>}
|
|
105
|
+
*/
|
|
106
|
+
async function login(serverUrl, username, options = {}) {
|
|
107
|
+
const args = ['-login', serverUrl];
|
|
108
|
+
|
|
109
|
+
if (username) {
|
|
110
|
+
args.push(username);
|
|
111
|
+
}
|
|
112
|
+
if (options.keyPath) {
|
|
113
|
+
args.push('-key', options.keyPath);
|
|
114
|
+
}
|
|
115
|
+
if (options.expires) {
|
|
116
|
+
args.push('-expires', options.expires);
|
|
117
|
+
}
|
|
118
|
+
if (options.certId) {
|
|
119
|
+
args.push('-cert-id', options.certId);
|
|
120
|
+
}
|
|
121
|
+
if (options.includeChain) {
|
|
122
|
+
args.push('-include-chain');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const result = await exec(args);
|
|
126
|
+
return {
|
|
127
|
+
success: result.code === 0,
|
|
128
|
+
message: result.stdout || result.stderr,
|
|
129
|
+
code: result.code
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Logout from signing server
|
|
135
|
+
* @param {string} [serverUrl] - Server URL (optional)
|
|
136
|
+
* @returns {Promise<{success: boolean, message: string}>}
|
|
137
|
+
*/
|
|
138
|
+
async function logout(serverUrl) {
|
|
139
|
+
const args = ['-logout'];
|
|
140
|
+
if (serverUrl) {
|
|
141
|
+
args.push(serverUrl);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const result = await exec(args);
|
|
145
|
+
return {
|
|
146
|
+
success: result.code === 0,
|
|
147
|
+
message: result.stdout || result.stderr,
|
|
148
|
+
code: result.code
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Sign a file
|
|
154
|
+
* @param {string} filePath - Path to file to sign
|
|
155
|
+
* @param {Object} [options] - Signing options
|
|
156
|
+
* @param {string} [options.output] - Output file path
|
|
157
|
+
* @param {string} [options.profile] - Config profile name
|
|
158
|
+
* @param {string} [options.hashAlgorithm] - Hash algorithm
|
|
159
|
+
* @param {string} [options.timestampUrl] - Timestamp server URL
|
|
160
|
+
* @param {boolean} [options.hashOnly] - Only compute hash
|
|
161
|
+
* @returns {Promise<{success: boolean, message: string, outputPath?: string}>}
|
|
162
|
+
*/
|
|
163
|
+
async function sign(filePath, options = {}) {
|
|
164
|
+
const args = [filePath];
|
|
165
|
+
|
|
166
|
+
if (options.output) {
|
|
167
|
+
args.push('-o', options.output);
|
|
168
|
+
}
|
|
169
|
+
if (options.profile) {
|
|
170
|
+
args.push('-profile', options.profile);
|
|
171
|
+
}
|
|
172
|
+
if (options.hashAlgorithm) {
|
|
173
|
+
args.push('-hash-algorithm', options.hashAlgorithm);
|
|
174
|
+
}
|
|
175
|
+
if (options.timestampUrl) {
|
|
176
|
+
args.push('-timestamp-url', options.timestampUrl);
|
|
177
|
+
}
|
|
178
|
+
if (options.hashOnly) {
|
|
179
|
+
args.push('-hash-only');
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const result = await exec(args);
|
|
183
|
+
return {
|
|
184
|
+
success: result.code === 0,
|
|
185
|
+
message: result.stdout || result.stderr,
|
|
186
|
+
code: result.code,
|
|
187
|
+
outputPath: options.output
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Verify signature on a file
|
|
193
|
+
* @param {string} filePath - Path to file to verify
|
|
194
|
+
* @param {Object} [options] - Verification options
|
|
195
|
+
* @param {string} [options.signatureId] - Specific signature ID
|
|
196
|
+
* @param {string} [options.profile] - Config profile name
|
|
197
|
+
* @returns {Promise<{valid: boolean, message: string, details?: Object}>}
|
|
198
|
+
*/
|
|
199
|
+
async function verify(filePath, options = {}) {
|
|
200
|
+
const args = ['-verify', filePath];
|
|
201
|
+
|
|
202
|
+
if (options.signatureId) {
|
|
203
|
+
args.push('-signature-id', options.signatureId);
|
|
204
|
+
}
|
|
205
|
+
if (options.profile) {
|
|
206
|
+
args.push('-profile', options.profile);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const result = await exec(args);
|
|
210
|
+
return {
|
|
211
|
+
valid: result.code === 0,
|
|
212
|
+
message: result.stdout || result.stderr,
|
|
213
|
+
code: result.code
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Get or set configuration
|
|
219
|
+
* @param {string} [action] - Config action (list, show, set, delete)
|
|
220
|
+
* @param {string} [profile] - Profile name
|
|
221
|
+
* @param {Object} [options] - Config options for set action
|
|
222
|
+
* @returns {Promise<{success: boolean, message: string}>}
|
|
223
|
+
*/
|
|
224
|
+
async function config(action, profile, options = {}) {
|
|
225
|
+
const args = ['-config'];
|
|
226
|
+
|
|
227
|
+
if (action) {
|
|
228
|
+
args.push(action);
|
|
229
|
+
}
|
|
230
|
+
if (profile) {
|
|
231
|
+
args.push(profile);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Add options for 'set' action
|
|
235
|
+
if (action === 'set' && options) {
|
|
236
|
+
if (options.host) args.push('-host', options.host);
|
|
237
|
+
if (options.username) args.push('-username', options.username);
|
|
238
|
+
if (options.keyPath) args.push('-ssh-key-path', options.keyPath);
|
|
239
|
+
if (options.expires) args.push('-expires', options.expires);
|
|
240
|
+
if (options.certId) args.push('-cert-id', options.certId);
|
|
241
|
+
if (options.timestampUrl) args.push('-timestamp-url', options.timestampUrl);
|
|
242
|
+
if (options.includeChain) args.push('-include-chain');
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const result = await exec(args);
|
|
246
|
+
return {
|
|
247
|
+
success: result.code === 0,
|
|
248
|
+
message: result.stdout || result.stderr,
|
|
249
|
+
code: result.code
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* List available certificates
|
|
255
|
+
* @returns {Promise<{success: boolean, certificates: Array}>}
|
|
256
|
+
*/
|
|
257
|
+
async function listCertificates() {
|
|
258
|
+
const result = await exec(['-codesign-list']);
|
|
259
|
+
return {
|
|
260
|
+
success: result.code === 0,
|
|
261
|
+
message: result.stdout || result.stderr,
|
|
262
|
+
code: result.code
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Get version information
|
|
268
|
+
* @returns {Promise<string>}
|
|
269
|
+
*/
|
|
270
|
+
async function version() {
|
|
271
|
+
const result = await exec(['-version']);
|
|
272
|
+
return result.stdout.trim();
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
module.exports = {
|
|
276
|
+
exec,
|
|
277
|
+
login,
|
|
278
|
+
logout,
|
|
279
|
+
sign,
|
|
280
|
+
verify,
|
|
281
|
+
config,
|
|
282
|
+
listCertificates,
|
|
283
|
+
version,
|
|
284
|
+
getBinaryPath
|
|
285
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@certchip/signer",
|
|
3
|
+
"version": "0.1.11",
|
|
4
|
+
"description": "Cross-platform code and document signing CLI tool",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"types": "lib/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"signercli": "./bin/signercli.js",
|
|
9
|
+
"signer": "./bin/signer.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
13
|
+
"version:generate": "node scripts/generate-version.js",
|
|
14
|
+
"prebuild": "npm run version:generate",
|
|
15
|
+
"prepack": "npm run version:generate"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"bin/",
|
|
19
|
+
"lib/",
|
|
20
|
+
"README.md"
|
|
21
|
+
],
|
|
22
|
+
"keywords": [
|
|
23
|
+
"code-signing",
|
|
24
|
+
"digital-signature",
|
|
25
|
+
"authenticode",
|
|
26
|
+
"pdf-signing",
|
|
27
|
+
"document-signing",
|
|
28
|
+
"cli",
|
|
29
|
+
"cross-platform"
|
|
30
|
+
],
|
|
31
|
+
"author": "Certchip <support@certchip.com>",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git+https://github.com/certchip/signer-cli.git"
|
|
36
|
+
},
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/certchip/signer-cli/issues"
|
|
39
|
+
},
|
|
40
|
+
"homepage": "https://certchip.com/signer",
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=14.0.0"
|
|
43
|
+
},
|
|
44
|
+
"os": [
|
|
45
|
+
"win32",
|
|
46
|
+
"linux",
|
|
47
|
+
"darwin"
|
|
48
|
+
],
|
|
49
|
+
"cpu": [
|
|
50
|
+
"x64",
|
|
51
|
+
"arm64"
|
|
52
|
+
]
|
|
53
|
+
}
|