|
7 | 7 | racket/system |
8 | 8 | glaze/build |
9 | 9 | glaze/license |
| 10 | + glaze/signing |
10 | 11 | glaze-cli/pkg) |
11 | 12 |
|
12 | 13 | (define (init-project name) |
|
178 | 179 | (displayln " dev Run this project's native Glaze desktop app") |
179 | 180 | (displayln " build Build a distributable (raco exe + raco distribute)") |
180 | 181 | (displayln " keygen Create an RSA keypair for license signing") |
| 182 | + (displayln " updater-keygen Create an Ed25519 keypair for update signing") |
| 183 | + (displayln " update-sign Sign an update artifact (Ed25519 over its sha256)") |
| 184 | + (displayln " update-verify Verify an update artifact signature") |
181 | 185 | (displayln " license Sign or verify offline license files") |
182 | 186 | (displayln " install Pin the glaze package to a revision and link it") |
183 | 187 | (displayln " doctor Diagnose glaze package links (--fix removes broken ones)") |
|
312 | 316 | (displayln " [--expiry YYYY-MM-DD] [--machine-id | --machine-id <hex>] --out <file>") |
313 | 317 | (displayln " verify: --pub <public.pem> --product <name> <file.license>")])) |
314 | 318 |
|
| 319 | +;; ---- updater artifact signing (Ed25519) ------------------------------------- |
| 320 | + |
| 321 | +(define (updater-sign-command rest) |
| 322 | + (let loop ([args rest] [artifact #f] [key #f] [password #f] [out #f]) |
| 323 | + (cond |
| 324 | + [(null? args) |
| 325 | + (unless (and artifact key out) |
| 326 | + (error 'update-sign "usage: raco glaze update-sign --artifact <file> --key <private.pem> --out <signature.txt> [--password <pw>]")) |
| 327 | + (define sig (sign-file artifact |
| 328 | + #:private-key key |
| 329 | + #:password password)) |
| 330 | + (with-output-to-file out |
| 331 | + (lambda () (displayln sig)) |
| 332 | + #:exists 'replace) |
| 333 | + (printf "signed ~a -> ~a\n" artifact out)] |
| 334 | + [(equal? (car args) "--artifact") (loop (cdr args) (cadr args) key password out)] |
| 335 | + [(equal? (car args) "--key") (loop (cdr args) artifact (cadr args) password out)] |
| 336 | + [(equal? (car args) "--password") (loop (cdr args) artifact key (cadr args) out)] |
| 337 | + [(equal? (car args) "--out") (loop (cdr args) artifact key password (cadr args))] |
| 338 | + [else (loop (cdr args) (or artifact (car args)) key password out)]))) |
| 339 | + |
| 340 | +(define (updater-verify-command rest) |
| 341 | + (let loop ([args rest] [artifact #f] [pub #f] [signature #f] [sha256 #f]) |
| 342 | + (cond |
| 343 | + [(null? args) |
| 344 | + (unless (and artifact pub signature) |
| 345 | + (error 'update-verify "usage: raco glaze update-verify --artifact <file> --pub <public.pem> --signature <signature.txt|base64> [--sha256 <hex>]")) |
| 346 | + (define sig-text |
| 347 | + (if (file-exists? signature) |
| 348 | + (string-trim (file->string signature)) |
| 349 | + signature)) |
| 350 | + (printf "Verifying ~a...\n" artifact) |
| 351 | + (if (verify-signature artifact |
| 352 | + #:public-key pub |
| 353 | + #:signature sig-text |
| 354 | + #:expected-sha256 sha256) |
| 355 | + (begin (printf "VALID\n") |
| 356 | + (exit 0)) |
| 357 | + (begin (printf "INVALID\n") (exit 1)))] |
| 358 | + [(equal? (car args) "--artifact") (loop (cdr args) (cadr args) pub signature sha256)] |
| 359 | + [(equal? (car args) "--pub") (loop (cdr args) artifact (cadr args) signature sha256)] |
| 360 | + [(equal? (car args) "--signature") (loop (cdr args) artifact pub (cadr args) sha256)] |
| 361 | + [(equal? (car args) "--sha256") (loop (cdr args) artifact pub signature (cadr args))] |
| 362 | + [else (loop (cdr args) (or artifact (car args)) pub signature sha256)]))) |
| 363 | + |
| 364 | +(define (updater-keygen-command rest) |
| 365 | + (let loop ([args rest] [out "updater-keys"] [password #f]) |
| 366 | + (cond |
| 367 | + [(null? args) |
| 368 | + (make-directory* out) |
| 369 | + (define-values (priv pub) |
| 370 | + (signing-keygen #:private-key (build-path out "private.pem") |
| 371 | + #:public-key (build-path out "public.pem") |
| 372 | + #:password password)) |
| 373 | + (printf "Updater Ed25519 keypair written:\n private: ~a (keep secret — signs update artifacts)\n public: ~a (pin inside the app — verifies update artifacts)\n" |
| 374 | + priv pub) |
| 375 | + (printf "public key fingerprint: ~a\n" (public-key-fingerprint pub))] |
| 376 | + [(equal? (car args) "--out") (loop (cdr args) (cadr args) password)] |
| 377 | + [(equal? (car args) "--password") (loop (cdr args) out (cadr args))] |
| 378 | + [else (loop (cdr args) out password)]))) |
| 379 | + |
315 | 380 | ;; Dispatch CLI commands |
316 | 381 | (define args (vector->list (current-command-line-arguments))) |
317 | 382 | (cond |
|
328 | 393 | ["build" (build-command rest)] |
329 | 394 | ["keygen" (keygen-command rest)] |
330 | 395 | ["license" (license-command rest)] |
| 396 | + ["updater-keygen" (updater-keygen-command rest)] |
| 397 | + ["update-sign" (updater-sign-command rest)] |
| 398 | + ["update-verify" (updater-verify-command rest)] |
331 | 399 | ["install" (install-command rest)] |
332 | 400 | ["doctor" (doctor-command rest)] |
333 | 401 | ["help" (print-help)] |
|
0 commit comments