@cloudflare/workers-auth 0.3.2 → 0.4.0
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/dist/index.d.mts +769 -7
- package/dist/index.mjs +2272 -30
- package/dist/metafile-esm.json +1 -1
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -1,14 +1,32 @@
|
|
|
1
1
|
import { ApiCredentials, ComplianceConfig } from '@cloudflare/workers-utils';
|
|
2
|
+
import { SpawnSyncReturns } from 'node:child_process';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
|
-
* Pluggable persistence for a typed config blob
|
|
5
|
+
* Pluggable persistence for a typed config blob.
|
|
6
|
+
*
|
|
5
7
|
*/
|
|
6
8
|
interface ConfigStorage<T> {
|
|
7
9
|
/**
|
|
8
10
|
* Read and parse the stored config.
|
|
9
|
-
*
|
|
11
|
+
*
|
|
12
|
+
* Consumers can treat a `read()` that resolves with `undefined` as
|
|
13
|
+
* "not logged in / no temporary account / etc.", and leave error handling
|
|
14
|
+
* for the surfaces that benefit from it.
|
|
15
|
+
*
|
|
16
|
+
* @returns `undefined` for the *empty* state — i.e. when the
|
|
17
|
+
* backing store does not exist yet, or when it exists but no longer
|
|
18
|
+
* contains usable data (e.g. encrypted-file present but the keyring entry
|
|
19
|
+
* is missing, ciphertext fails its auth tag, deserialised payload is not
|
|
20
|
+
* shaped like `T`). All of these collapse to "nothing usable stored
|
|
21
|
+
* here" from the consumer's perspective, so the default is to return
|
|
22
|
+
* `undefined` rather than throw.
|
|
23
|
+
*
|
|
24
|
+
* @throws *genuine* errors that the consumer needs to act on — typically
|
|
25
|
+
* filesystem or permission failures (`EACCES`, `EISDIR`, disk full).
|
|
26
|
+
* Those propagate so the user can see what's wrong, rather than silently
|
|
27
|
+
* behaving as "not logged in".
|
|
10
28
|
*/
|
|
11
|
-
read(): T;
|
|
29
|
+
read(): T | undefined;
|
|
12
30
|
/** Serialize and persist the config. */
|
|
13
31
|
write(config: T): void;
|
|
14
32
|
/** Remove the backing store; returns whether anything existed beforehand. */
|
|
@@ -168,9 +186,23 @@ interface OAuthFlowContext {
|
|
|
168
186
|
*/
|
|
169
187
|
redirectUri: string;
|
|
170
188
|
/**
|
|
171
|
-
*
|
|
189
|
+
* Factory that returns a persistence backend for the given auth profile.
|
|
190
|
+
*
|
|
191
|
+
* Called with the active profile name (e.g. `"default"`) on every storage
|
|
192
|
+
* access so the flow always reads/writes the correct backing store.
|
|
193
|
+
* The consumer is responsible for mapping profile names to concrete storage
|
|
194
|
+
* backends (e.g. wrangler maps each profile to a separate TOML file under
|
|
195
|
+
* the global config directory).
|
|
196
|
+
*
|
|
197
|
+
* Consumers that want OS-keyring-backed encryption pass the
|
|
198
|
+
* `storageFactory` from {@link createCredentialStorageContext} (in the
|
|
199
|
+
* `credential-store` module) — for each profile that adapter resolves
|
|
200
|
+
* between the plaintext TOML file and the encrypted-file-with-keyring-key
|
|
201
|
+
* implementation on every call, so runtime preference changes
|
|
202
|
+
* (`--use-keyring` / `CLOUDFLARE_AUTH_USE_KEYRING`) take effect without
|
|
203
|
+
* rebuilding the flow.
|
|
172
204
|
*/
|
|
173
|
-
|
|
205
|
+
storageFactory: (profile?: string) => AuthConfigStorage;
|
|
174
206
|
/**
|
|
175
207
|
* Whether the flow's credential resolvers (`getAPIToken` / `requireApiToken`)
|
|
176
208
|
* should honour the global API key + email pair in addition to scoped API
|
|
@@ -265,6 +297,20 @@ declare function getAccessHeaders(domain: string, options: {
|
|
|
265
297
|
* `WRANGLER_API_ENVIRONMENT=staging` environment variable instead.
|
|
266
298
|
*/
|
|
267
299
|
declare const getAuthUrlFromEnv: () => string;
|
|
300
|
+
/**
|
|
301
|
+
* `CLOUDFLARE_AUTH_USE_KEYRING` overrides where OAuth credentials are stored.
|
|
302
|
+
*
|
|
303
|
+
* - `true` — force-store credentials in the OS keychain. If the keychain
|
|
304
|
+
* cannot be reached, the resolver throws rather than silently
|
|
305
|
+
* falling back, so security-sensitive callers know their
|
|
306
|
+
* explicit opt-in did not take effect.
|
|
307
|
+
* - `false` — force-store credentials in the plaintext TOML file,
|
|
308
|
+
* even if the consumer's persistent `keyring_enabled` preference
|
|
309
|
+
* is set.
|
|
310
|
+
* - unset — fall back to the consumer's persistent preference (e.g. the
|
|
311
|
+
* one written by `wrangler login --use-keyring`).
|
|
312
|
+
*/
|
|
313
|
+
declare const getCloudflareAuthUseKeyringFromEnv: () => boolean | undefined;
|
|
268
314
|
|
|
269
315
|
/**
|
|
270
316
|
* Reason why {@link OAuthFlowAPI.loginOrRefreshIfRequired} could not
|
|
@@ -311,11 +357,25 @@ interface LoginProps {
|
|
|
311
357
|
callbackHost?: string;
|
|
312
358
|
/** Port the local callback server listens on. Defaults to `8976`. */
|
|
313
359
|
callbackPort?: number;
|
|
360
|
+
/**
|
|
361
|
+
* Named auth profile to store the token under. When omitted, the default
|
|
362
|
+
* profile (`default.toml`) is used.
|
|
363
|
+
* Only for use by 'auth create', not exposed to the user
|
|
364
|
+
*/
|
|
365
|
+
profile?: string;
|
|
314
366
|
}
|
|
315
367
|
/**
|
|
316
368
|
* Public surface returned by {@link createOAuthFlow}.
|
|
317
369
|
*/
|
|
318
370
|
interface OAuthFlowAPI {
|
|
371
|
+
/**
|
|
372
|
+
* Set the active auth profile for all subsequent storage lookups.
|
|
373
|
+
*
|
|
374
|
+
* Called once at top of command dispatch by the consumer after resolving the
|
|
375
|
+
* active profile. `"default"` if never called.
|
|
376
|
+
*/
|
|
377
|
+
setProfile(profile: string): void;
|
|
378
|
+
getActiveProfile(): string;
|
|
319
379
|
/**
|
|
320
380
|
* Open the authorize URL in the user's browser, wait for the callback to be
|
|
321
381
|
* hit on the local HTTP server, exchange the code for an access token, and
|
|
@@ -324,6 +384,9 @@ interface OAuthFlowAPI {
|
|
|
324
384
|
* Refuses to start when `ctx.hasEnvCredentials()` returns `true`.
|
|
325
385
|
* Refuses to start when the compliance region is `fedramp_high`.
|
|
326
386
|
*
|
|
387
|
+
* When `props.profile` is set, the token is stored under that profile
|
|
388
|
+
* instead of the active one. This is used by `auth create <name>`.
|
|
389
|
+
*
|
|
327
390
|
* @returns `true` on success, `false` when env credentials are present.
|
|
328
391
|
*/
|
|
329
392
|
login(props: LoginProps): Promise<boolean>;
|
|
@@ -333,8 +396,11 @@ interface OAuthFlowAPI {
|
|
|
333
396
|
*
|
|
334
397
|
* No-op when `ctx.hasEnvCredentials()` returns `true` (env credentials
|
|
335
398
|
* cannot be revoked).
|
|
399
|
+
*
|
|
400
|
+
* When `profile` is passed, operates on that profile instead of the
|
|
401
|
+
* active one. This is used by `auth delete <name>`.
|
|
336
402
|
*/
|
|
337
|
-
logout(): Promise<void>;
|
|
403
|
+
logout(profile?: string): Promise<void>;
|
|
338
404
|
/**
|
|
339
405
|
* If the user has no stored OAuth token, attempt an interactive login.
|
|
340
406
|
* If they have one but it is expired, attempt a refresh; if refresh fails,
|
|
@@ -371,6 +437,11 @@ interface OAuthFlowAPI {
|
|
|
371
437
|
* available.
|
|
372
438
|
*/
|
|
373
439
|
requireApiToken(): ApiCredentials;
|
|
440
|
+
/**
|
|
441
|
+
* Return the scopes granted to the stored OAuth token for the active
|
|
442
|
+
* profile, or `undefined` when no OAuth token is stored.
|
|
443
|
+
*/
|
|
444
|
+
getScopes(): string[] | undefined;
|
|
374
445
|
/**
|
|
375
446
|
* Establish whether `--temporary` is permitted for this invocation. Called
|
|
376
447
|
* once at command dispatch by the consumer. Also drops any temporary account
|
|
@@ -416,6 +487,43 @@ declare const TEMPORARY_TERMS_NOTICE: string;
|
|
|
416
487
|
*/
|
|
417
488
|
declare const PKCE_CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
|
|
418
489
|
|
|
490
|
+
interface ProfileConfigOperations {
|
|
491
|
+
exists(profile: string): boolean;
|
|
492
|
+
list(): string[];
|
|
493
|
+
delete(profile: string): void;
|
|
494
|
+
}
|
|
495
|
+
interface DirectoryBindingsStorage {
|
|
496
|
+
read(): Record<string, string>;
|
|
497
|
+
write(bindings: Record<string, string>): void;
|
|
498
|
+
}
|
|
499
|
+
interface DirectoryBindingOperations extends DirectoryBindingsStorage {
|
|
500
|
+
activate(profile: string, dir: string): void;
|
|
501
|
+
deactivate(dir: string): DeactivateDirectoryResult;
|
|
502
|
+
getProfileForDirectory(startDir: string): string | undefined;
|
|
503
|
+
getBindingsForProfile(profile: string): string[];
|
|
504
|
+
removeAllBindingsForProfile(profile: string): string[];
|
|
505
|
+
}
|
|
506
|
+
interface ProfileStore {
|
|
507
|
+
configs: ProfileConfigOperations;
|
|
508
|
+
bindings: DirectoryBindingOperations;
|
|
509
|
+
resolve(args: {
|
|
510
|
+
profile?: string;
|
|
511
|
+
cwd: string;
|
|
512
|
+
}): string;
|
|
513
|
+
}
|
|
514
|
+
interface DeactivateDirectoryResult {
|
|
515
|
+
removedProfile: string;
|
|
516
|
+
newResolution: {
|
|
517
|
+
profile: string | undefined;
|
|
518
|
+
source: string;
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
declare function createProfileStore(args: {
|
|
522
|
+
configs: ProfileConfigOperations;
|
|
523
|
+
bindings: DirectoryBindingsStorage;
|
|
524
|
+
}): ProfileStore;
|
|
525
|
+
declare function validateProfileName(name: string): void;
|
|
526
|
+
|
|
419
527
|
interface RefreshToken {
|
|
420
528
|
value: string;
|
|
421
529
|
}
|
|
@@ -460,4 +568,658 @@ declare function readStoredAuthState(options: {
|
|
|
460
568
|
storage: AuthConfigStorage;
|
|
461
569
|
}): StoredAuthState;
|
|
462
570
|
|
|
463
|
-
|
|
571
|
+
/**
|
|
572
|
+
* Pluggable backend for the persisted OAuth credentials.
|
|
573
|
+
*
|
|
574
|
+
* Concrete implementations:
|
|
575
|
+
* - {@link FileCredentialStore} — the plaintext TOML file at
|
|
576
|
+
* `<globalWranglerConfigPath>/config/<env>.toml`. Used by default and as
|
|
577
|
+
* a fallback when keyring storage is unavailable.
|
|
578
|
+
* - {@link EncryptedFileCredentialStore} — an AES-256-GCM-encrypted file at
|
|
579
|
+
* `<globalWranglerConfigPath>/config/<env>.enc`, with the encryption key
|
|
580
|
+
* stored in the OS keyring via a {@link KeyProvider}.
|
|
581
|
+
*
|
|
582
|
+
* Extends the consumer-facing {@link AuthConfigStorage} contract with two
|
|
583
|
+
* keyring-specific extras:
|
|
584
|
+
* - `kind`: discriminant so consumers can tell apart "plain file" and
|
|
585
|
+
* "encrypted file" stores without sniffing for methods.
|
|
586
|
+
* - `describe()`: human-readable, possibly multi-line description (e.g.
|
|
587
|
+
* `"Encrypted file (path) with key in macOS Keychain"`) for surfaces
|
|
588
|
+
* like `wrangler whoami` that want richer copy than the raw `path()`.
|
|
589
|
+
*
|
|
590
|
+
* The interface is synchronous so it can be plugged into existing
|
|
591
|
+
* `AuthConfigStorage` call sites without forcing every caller to become
|
|
592
|
+
* async. Under the hood, both implementations use synchronous primitives
|
|
593
|
+
* (subprocess `spawnSync`, `@napi-rs/keyring`'s sync `Entry` class,
|
|
594
|
+
* `node:crypto` sync APIs, synchronous filesystem calls).
|
|
595
|
+
*/
|
|
596
|
+
interface CredentialStore extends AuthConfigStorage {
|
|
597
|
+
readonly kind: "file" | "encrypted-file";
|
|
598
|
+
/**
|
|
599
|
+
* Human-readable description of where credentials are stored, suitable
|
|
600
|
+
* for consumers' `whoami`-style output. May be multi-line / richer
|
|
601
|
+
* than the raw `path()`.
|
|
602
|
+
*/
|
|
603
|
+
describe(): string;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* Absolute path to the plaintext TOML credentials file for the given auth
|
|
608
|
+
* profile (defaulting to the active Cloudflare API environment's default
|
|
609
|
+
* profile).
|
|
610
|
+
*
|
|
611
|
+
* `configPath` is the consumer's global config directory — the client (e.g.
|
|
612
|
+
* wrangler, or a future `cf` CLI) owns where its config lives, so it is passed
|
|
613
|
+
* in rather than resolved here. The environment is appended to the
|
|
614
|
+
* default-profile filename so callers running with
|
|
615
|
+
* `WRANGLER_API_ENVIRONMENT=staging` get a separate file from production; named
|
|
616
|
+
* profiles get `<profile>.toml`. The path stays exposed so the migration code,
|
|
617
|
+
* defensive scrubs on logout, and tests that assert against it can all point at
|
|
618
|
+
* the same location as the {@link FileCredentialStore}.
|
|
619
|
+
*/
|
|
620
|
+
declare function getAuthConfigFilePath(configPath: string, profile?: string): string;
|
|
621
|
+
/**
|
|
622
|
+
* The plaintext-TOML credentials store.
|
|
623
|
+
*
|
|
624
|
+
* Used as the default backend when the user hasn't opted into keyring
|
|
625
|
+
* storage, and as the soft-fallback when keyring storage is requested
|
|
626
|
+
* but a backend isn't available.
|
|
627
|
+
*/
|
|
628
|
+
declare class FileCredentialStore implements CredentialStore {
|
|
629
|
+
private readonly configPath;
|
|
630
|
+
private readonly profile?;
|
|
631
|
+
readonly kind: "file";
|
|
632
|
+
/**
|
|
633
|
+
* @param configPath consumer-provided global config directory (the CLI
|
|
634
|
+
* owns where its config lives, so workers-auth never resolves it itself).
|
|
635
|
+
* @param profile the auth profile (defaults to the active environment's
|
|
636
|
+
* default profile).
|
|
637
|
+
*/
|
|
638
|
+
constructor(configPath: string, profile?: string | undefined);
|
|
639
|
+
read(): UserAuthConfig | undefined;
|
|
640
|
+
write(config: UserAuthConfig): void;
|
|
641
|
+
clear(): boolean;
|
|
642
|
+
path(): string;
|
|
643
|
+
describe(): string;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* A small abstraction over OS keyring backends, scoped to "store/retrieve
|
|
648
|
+
* an arbitrary fixed-size key" rather than "store a credential blob".
|
|
649
|
+
*
|
|
650
|
+
* Keeping the responsibility this narrow means:
|
|
651
|
+
* - The 2.5 KB macOS Keychain item limit (and similar limits elsewhere)
|
|
652
|
+
* is never hit — we only ever store ~44 bytes of base64.
|
|
653
|
+
* - Per-platform code stays trivial; richer credential shapes can grow
|
|
654
|
+
* freely inside the encrypted file without touching the keyring.
|
|
655
|
+
* - The same `KeyProvider` is reusable for non-OAuth secrets in the
|
|
656
|
+
* future (e.g. account-scoped API tokens).
|
|
657
|
+
*
|
|
658
|
+
* Implementations are instantiated with the consumer's `serviceName`
|
|
659
|
+
* (e.g. "wrangler") so the same library can serve multiple Cloudflare
|
|
660
|
+
* CLIs without collisions.
|
|
661
|
+
*/
|
|
662
|
+
interface KeyProvider {
|
|
663
|
+
/**
|
|
664
|
+
* Return the previously-stored key, or `undefined` when nothing has
|
|
665
|
+
* been stored for this `(serviceName, accountName)` pair. Backend
|
|
666
|
+
* failures throw so callers can surface meaningful errors.
|
|
667
|
+
*/
|
|
668
|
+
getKey(): Uint8Array | undefined;
|
|
669
|
+
/** Persist the given key, overwriting any previous value. */
|
|
670
|
+
setKey(key: Uint8Array): void;
|
|
671
|
+
/** Remove the stored key. Idempotent — no-op when nothing is stored. */
|
|
672
|
+
deleteKey(): void;
|
|
673
|
+
/**
|
|
674
|
+
* Human-readable description of where the key is stored, surfaced via
|
|
675
|
+
* the {@link CredentialStore.describe} chain.
|
|
676
|
+
*/
|
|
677
|
+
describe(): string;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* Absolute path to the encrypted credentials file for the given auth profile
|
|
682
|
+
* (defaulting to the active Cloudflare API environment's default profile).
|
|
683
|
+
*
|
|
684
|
+
* `configPath` is the consumer's global config directory (see
|
|
685
|
+
* {@link getAuthConfigFilePath}). Sibling of the plaintext `<profile>.toml` so
|
|
686
|
+
* the migration code can non-destructively read the old file before writing the
|
|
687
|
+
* new one.
|
|
688
|
+
*/
|
|
689
|
+
declare function getEncryptedAuthConfigFilePath(configPath: string, profile?: string): string;
|
|
690
|
+
/**
|
|
691
|
+
* Result of a successful migration from a plaintext TOML file
|
|
692
|
+
* into an encrypted file backed by a `KeyProvider`. Surfaced so the
|
|
693
|
+
* resolver can log a one-line summary when migration runs.
|
|
694
|
+
*/
|
|
695
|
+
interface PlaintextMigrationResult {
|
|
696
|
+
plaintextPath: string;
|
|
697
|
+
encryptedPath: string;
|
|
698
|
+
keyProviderDescription: string;
|
|
699
|
+
}
|
|
700
|
+
/**
|
|
701
|
+
* Optional callback invoked by {@link EncryptedFileCredentialStore.read}
|
|
702
|
+
* when it transparently migrates a plaintext TOML file into the
|
|
703
|
+
* encrypted file on first read.
|
|
704
|
+
*
|
|
705
|
+
* The resolver wires this to its logger; left undefined when the store
|
|
706
|
+
* is constructed standalone (e.g. by tests).
|
|
707
|
+
*/
|
|
708
|
+
type OnPlaintextMigration = (result: PlaintextMigrationResult) => void;
|
|
709
|
+
/**
|
|
710
|
+
* Credentials store backed by an AES-256-GCM-encrypted file on disk and a
|
|
711
|
+
* 32-byte encryption key held in the OS keyring via a {@link KeyProvider}.
|
|
712
|
+
*
|
|
713
|
+
* The combination decouples credential payload size from any per-platform
|
|
714
|
+
* keyring item size limit (notably the ~2.5 KB macOS Keychain limit on
|
|
715
|
+
* generic-password items): the keyring entry is always small (~44 bytes
|
|
716
|
+
* of base64), while the credential blob lives in the encrypted file and
|
|
717
|
+
* is free to grow as the schema evolves.
|
|
718
|
+
*
|
|
719
|
+
* Threat model:
|
|
720
|
+
* - File leaked from a backup without the keyring entry: ciphertext is
|
|
721
|
+
* useless, GCM auth tag prevents tampering.
|
|
722
|
+
* - Keyring entry leaked without the file: a bare 32-byte key, useless
|
|
723
|
+
* without the ciphertext.
|
|
724
|
+
* - Attacker with full local user access: can decrypt (same as
|
|
725
|
+
* direct-keyring storage — both backends expose secrets to root /
|
|
726
|
+
* same-user processes).
|
|
727
|
+
*/
|
|
728
|
+
declare class EncryptedFileCredentialStore implements CredentialStore {
|
|
729
|
+
private readonly configPath;
|
|
730
|
+
private readonly keyProvider;
|
|
731
|
+
private readonly onPlaintextMigration?;
|
|
732
|
+
private readonly profile?;
|
|
733
|
+
readonly kind: "encrypted-file";
|
|
734
|
+
/**
|
|
735
|
+
* @param configPath consumer-provided global config directory (the CLI
|
|
736
|
+
* owns where its config lives, so workers-auth never resolves it itself).
|
|
737
|
+
* @param keyProvider the OS-keyring backend holding the encryption key.
|
|
738
|
+
* @param onPlaintextMigration optional callback invoked when a plaintext
|
|
739
|
+
* TOML file is migrated into the encrypted layout on first read.
|
|
740
|
+
* @param profile the auth profile (defaults to the active environment's
|
|
741
|
+
* default profile).
|
|
742
|
+
*/
|
|
743
|
+
constructor(configPath: string, keyProvider: KeyProvider, onPlaintextMigration?: OnPlaintextMigration | undefined, profile?: string | undefined);
|
|
744
|
+
read(): UserAuthConfig | undefined;
|
|
745
|
+
write(config: UserAuthConfig): void;
|
|
746
|
+
clear(): boolean;
|
|
747
|
+
path(): string;
|
|
748
|
+
describe(): string;
|
|
749
|
+
private readEncryptedFile;
|
|
750
|
+
private migrateFromPlaintext;
|
|
751
|
+
/**
|
|
752
|
+
* Return the existing encryption key, or generate + persist a fresh
|
|
753
|
+
* one when none exists yet. Called from `write()` so the first
|
|
754
|
+
* `wrangler login --use-keyring` is fully bootstrapping.
|
|
755
|
+
*/
|
|
756
|
+
private ensureKey;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
/**
|
|
760
|
+
* Per-consumer configuration for the credential-storage resolver.
|
|
761
|
+
*
|
|
762
|
+
* Captured by {@link createCredentialStorageContext} in a closure so the
|
|
763
|
+
* returned `storage` adapter and `getActiveStore` function can both
|
|
764
|
+
* re-resolve the active store on every call without re-reading shared
|
|
765
|
+
* mutable module state.
|
|
766
|
+
*/
|
|
767
|
+
interface CredentialStorageContext {
|
|
768
|
+
/**
|
|
769
|
+
* Keyring service identifier (e.g. `"wrangler"`). Becomes the `-s`
|
|
770
|
+
* argument to `/usr/bin/security`, the `service` attribute for
|
|
771
|
+
* `secret-tool`, and the `service` argument to `@napi-rs/keyring`'s
|
|
772
|
+
* `Entry`. Must be non-empty.
|
|
773
|
+
*/
|
|
774
|
+
serviceName: string;
|
|
775
|
+
/**
|
|
776
|
+
* The consumer's global config directory (e.g. wrangler's
|
|
777
|
+
* `~/.wrangler`), resolved lazily on every credential operation.
|
|
778
|
+
*
|
|
779
|
+
* The client owns where its config lives — `cf` uses a different global
|
|
780
|
+
* config path than wrangler — so `@cloudflare/workers-auth` never resolves
|
|
781
|
+
* it itself. A getter (rather than a captured string) is required because
|
|
782
|
+
* consumers create this context once at module load while tests re-stub
|
|
783
|
+
* `HOME` / `XDG_CONFIG_HOME` per case, so the path must be re-read on each
|
|
784
|
+
* call. The credential files (`.toml` / `.enc`) and the Windows keyring
|
|
785
|
+
* binding all live under this directory.
|
|
786
|
+
*/
|
|
787
|
+
getConfigPath: () => string;
|
|
788
|
+
/**
|
|
789
|
+
* Whether the user has opted into keyring storage. Consulted on every
|
|
790
|
+
* credential read/write so runtime preference changes (e.g. a user
|
|
791
|
+
* toggling the option mid-session) take effect.
|
|
792
|
+
*/
|
|
793
|
+
isKeyringEnabled: () => boolean;
|
|
794
|
+
/** Drop-in replacement for the consumer's logger singleton. */
|
|
795
|
+
logger: OAuthFlowLogger;
|
|
796
|
+
/** Whether the process should not prompt the user. */
|
|
797
|
+
isNonInteractiveOrCI: () => boolean;
|
|
798
|
+
/**
|
|
799
|
+
* Consumer's CLI name for error-message templating, e.g. `"wrangler"`.
|
|
800
|
+
* Used in hints like ``Run `<cliName> login --use-keyring` …``.
|
|
801
|
+
* Defaults to `"your CLI"` when omitted.
|
|
802
|
+
*/
|
|
803
|
+
cliName?: string;
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* Bundle returned by {@link createCredentialStorageContext}.
|
|
807
|
+
*
|
|
808
|
+
* - `storageFactory`: maps an auth profile to an {@link AuthConfigStorage}
|
|
809
|
+
* adapter that delegates to that profile's active {@link CredentialStore}
|
|
810
|
+
* on every method call. Pass this as `ctx.storageFactory` to
|
|
811
|
+
* {@link createOAuthFlow}, which calls it with the active profile on every
|
|
812
|
+
* credential access.
|
|
813
|
+
* - `getActiveStore`: the live `CredentialStore` lookup for a given profile,
|
|
814
|
+
* suitable for `whoami`-style consumers that want to call `describe()`.
|
|
815
|
+
*
|
|
816
|
+
* Both surfaces are wired against the same closure, so a runtime preference
|
|
817
|
+
* flip (e.g. `wrangler login --no-use-keyring`) is observable through both
|
|
818
|
+
* on the very next call. The profile argument selects which profile's files
|
|
819
|
+
* / keyring entry the resolved store reads and writes.
|
|
820
|
+
*/
|
|
821
|
+
interface CredentialStorageBundle {
|
|
822
|
+
storageFactory: (profile?: string) => AuthConfigStorage;
|
|
823
|
+
getActiveStore: (profile?: string) => CredentialStore;
|
|
824
|
+
}
|
|
825
|
+
/**
|
|
826
|
+
* Build a credential-storage bundle for a consumer (wrangler, future
|
|
827
|
+
* Cloudflare CLIs).
|
|
828
|
+
*
|
|
829
|
+
* The bundle's `storage` is an `AuthConfigStorage` that re-resolves the
|
|
830
|
+
* underlying store on every read/write/clear/path call. Selection order
|
|
831
|
+
* (highest precedence first):
|
|
832
|
+
*
|
|
833
|
+
* 1. `CLOUDFLARE_AUTH_USE_KEYRING=false` env var — forces the file store.
|
|
834
|
+
* 2. `CLOUDFLARE_AUTH_USE_KEYRING=true` env var — forces keyring storage;
|
|
835
|
+
* failures throw rather than soft-falling-back.
|
|
836
|
+
* 3. `isKeyringEnabled()` callback (the consumer's persistent preference) —
|
|
837
|
+
* uses keyring storage; failures soft-fall-back with a one-time warning.
|
|
838
|
+
* 4. Otherwise — defaults to the plaintext file store.
|
|
839
|
+
*
|
|
840
|
+
* The env var and the `isKeyringEnabled` callback are re-read on every
|
|
841
|
+
* call so runtime preference changes take effect without rebuilding the
|
|
842
|
+
* storage layer.
|
|
843
|
+
*/
|
|
844
|
+
declare function createCredentialStorageContext(context: CredentialStorageContext): CredentialStorageBundle;
|
|
845
|
+
/**
|
|
846
|
+
* Outcome of {@link scrubEncryptedCredentials}, so callers can tailor their
|
|
847
|
+
* messaging (e.g. warn that a keyring entry may remain).
|
|
848
|
+
*/
|
|
849
|
+
interface ScrubEncryptedCredentialsResult {
|
|
850
|
+
/**
|
|
851
|
+
* Whether the keyring backend was *reachable* — i.e. a `KeyProvider`
|
|
852
|
+
* resolved for this platform. When `true`, the encrypted store's `clear()`
|
|
853
|
+
* removed the `.enc` file (and any plaintext `.toml`) and attempted to
|
|
854
|
+
* delete the keyring key. When `false`, only the `.enc` file was removed
|
|
855
|
+
* best-effort and a keyring entry (if one exists) was left behind.
|
|
856
|
+
*
|
|
857
|
+
* Note this reflects reachability, not that every operation succeeded: the
|
|
858
|
+
* key deletion is best-effort (see `EncryptedFileCredentialStore.clear()`),
|
|
859
|
+
* so in the rare case a reachable keyring fails mid-delete the `.enc`
|
|
860
|
+
* ciphertext is still gone and only a bare, unusable key could linger.
|
|
861
|
+
*/
|
|
862
|
+
backendAvailable: boolean;
|
|
863
|
+
/** Whether an encrypted `.enc` file existed before the scrub. */
|
|
864
|
+
encryptedFileExisted: boolean;
|
|
865
|
+
}
|
|
866
|
+
/**
|
|
867
|
+
* Best-effort removal of a profile's encrypted credentials (`.enc` file) and
|
|
868
|
+
* the keyring entry holding its encryption key.
|
|
869
|
+
*
|
|
870
|
+
* Shared by the `--no-use-keyring` opt-out (default profile) and
|
|
871
|
+
* `wrangler auth delete <name>` (named profile) so both clear the encrypted
|
|
872
|
+
* backend the same way, independent of the current keyring preference (a
|
|
873
|
+
* profile may have been encrypted in a previous session even though keyring
|
|
874
|
+
* storage is currently disabled).
|
|
875
|
+
*
|
|
876
|
+
* When the keyring backend is reachable, the encrypted store's `clear()`
|
|
877
|
+
* removes the `.enc` file *and* the keyring key (and any plaintext
|
|
878
|
+
* `.toml`). When it isn't (Linux without `secret-tool`, Windows without the
|
|
879
|
+
* binding, an unsupported platform), the `.enc` file is removed best-effort
|
|
880
|
+
* and `backendAvailable` is `false` so the caller can warn that the keyring
|
|
881
|
+
* entry may remain. This never attempts a (Windows) binding install — a scrub
|
|
882
|
+
* must not block on provisioning a backend it is trying to tear down.
|
|
883
|
+
*/
|
|
884
|
+
declare function scrubEncryptedCredentials(options: {
|
|
885
|
+
serviceName: string;
|
|
886
|
+
configPath: string;
|
|
887
|
+
profile?: string;
|
|
888
|
+
}): ScrubEncryptedCredentialsResult;
|
|
889
|
+
|
|
890
|
+
/**
|
|
891
|
+
* Reset module-level per-session resolver flags (memoized warnings, the
|
|
892
|
+
* Windows install-failed latch).
|
|
893
|
+
*
|
|
894
|
+
* Tests use this to start each case from a clean slate. In production
|
|
895
|
+
* the flags reset naturally when the wrangler process exits.
|
|
896
|
+
*/
|
|
897
|
+
declare function resetCredentialStorageState(): void;
|
|
898
|
+
/**
|
|
899
|
+
* Alias kept for tests that previously called this to fully tear down
|
|
900
|
+
* both the configuration and the session flags. With the per-consumer
|
|
901
|
+
* configuration captured in `createCredentialStorageContext`, this now
|
|
902
|
+
* does the same thing as {@link resetCredentialStorageState}: clear the
|
|
903
|
+
* session flags.
|
|
904
|
+
*/
|
|
905
|
+
declare const clearCredentialStorageState: typeof resetCredentialStorageState;
|
|
906
|
+
|
|
907
|
+
/**
|
|
908
|
+
* Resolve the keyring account name for the given auth profile.
|
|
909
|
+
*
|
|
910
|
+
* Shares {@link resolveAuthProfileBaseName} with the file paths so the
|
|
911
|
+
* keyring entry tracks the same identity as the on-disk files: the default
|
|
912
|
+
* profile gets `default` in production or the environment name otherwise
|
|
913
|
+
* (so a single OS user can hold production and staging credentials
|
|
914
|
+
* side-by-side), while a named profile gets the profile name. This means
|
|
915
|
+
* each profile holds its own encryption key, so clearing one profile's
|
|
916
|
+
* credentials never disturbs another's.
|
|
917
|
+
*
|
|
918
|
+
* The service name is consumer-configured (passed to each `KeyProvider`'s
|
|
919
|
+
* constructor) — this account-name derivation is Cloudflare-wide and stays
|
|
920
|
+
* inside `@cloudflare/workers-auth`.
|
|
921
|
+
*/
|
|
922
|
+
declare function getKeyringAccountName(profile?: string): string;
|
|
923
|
+
|
|
924
|
+
/** Signature of the `/usr/bin/security` invoker. Overridable for tests. */
|
|
925
|
+
type MacSecurityCommandRunner = (args: string[], options?: {
|
|
926
|
+
input?: string;
|
|
927
|
+
}) => SpawnSyncReturns<string>;
|
|
928
|
+
/**
|
|
929
|
+
* Override the `/usr/bin/security` invoker for tests. Pass `undefined` to
|
|
930
|
+
* restore the default real-process runner.
|
|
931
|
+
*/
|
|
932
|
+
declare function setMacSecurityCommandRunner(fn: MacSecurityCommandRunner | undefined): void;
|
|
933
|
+
/**
|
|
934
|
+
* macOS Keychain backend that stores the encryption key for the active
|
|
935
|
+
* {@link EncryptedFileCredentialStore} via the `/usr/bin/security` CLI.
|
|
936
|
+
*
|
|
937
|
+
* The `security` binary is part of every macOS install so this path has
|
|
938
|
+
* zero install cost. The `serviceName` is consumer-provided so different
|
|
939
|
+
* Cloudflare CLIs (wrangler, future tools) can coexist on the same
|
|
940
|
+
* keychain without colliding.
|
|
941
|
+
*
|
|
942
|
+
* Trade-off: `add-generic-password -w <secret>` puts the secret on the
|
|
943
|
+
* argv of a short-lived subprocess, briefly visible to other processes
|
|
944
|
+
* running as the same user (e.g. via `ps`). This is the same trade-off
|
|
945
|
+
* accepted by `git credential-osxkeychain`. Because the secret here is
|
|
946
|
+
* only the 32-byte encryption key (not the OAuth tokens themselves), the
|
|
947
|
+
* exposure window is narrower than the previous direct-keyring design.
|
|
948
|
+
*/
|
|
949
|
+
declare class MacSecurityKeyProvider implements KeyProvider {
|
|
950
|
+
private readonly serviceName;
|
|
951
|
+
private readonly profile?;
|
|
952
|
+
constructor(serviceName: string, profile?: string | undefined);
|
|
953
|
+
getKey(): Uint8Array | undefined;
|
|
954
|
+
setKey(key: Uint8Array): void;
|
|
955
|
+
deleteKey(): void;
|
|
956
|
+
describe(): string;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
/** Signature of the `secret-tool` invoker. Overridable for tests. */
|
|
960
|
+
type LinuxSecretToolRunner = (args: string[], options?: {
|
|
961
|
+
input?: string;
|
|
962
|
+
}) => SpawnSyncReturns<string>;
|
|
963
|
+
/**
|
|
964
|
+
* Override the `secret-tool` invoker for tests. Pass `undefined` to restore
|
|
965
|
+
* the default real-process runner. Resets the memoized
|
|
966
|
+
* {@link probeSecretTool} result so the next call re-probes through the
|
|
967
|
+
* new runner.
|
|
968
|
+
*/
|
|
969
|
+
declare function setLinuxSecretToolRunner(fn: LinuxSecretToolRunner | undefined): void;
|
|
970
|
+
/**
|
|
971
|
+
* Probe whether `secret-tool` is callable in the current environment.
|
|
972
|
+
*
|
|
973
|
+
* Returns `true` when `secret-tool --version` exits 0. The probe does not
|
|
974
|
+
* exercise the keyring backend itself — a missing D-Bus session surfaces
|
|
975
|
+
* on the first real read/write rather than every consumer invocation, so
|
|
976
|
+
* we avoid the extra latency on every command for users whose desktop
|
|
977
|
+
* session is fully working.
|
|
978
|
+
*
|
|
979
|
+
* The result is memoized per-process: `secret-tool` is not going to be
|
|
980
|
+
* uninstalled mid-command, and the resolver re-resolves the active store
|
|
981
|
+
* on every credential operation (see `resolver.ts`), so caching keeps the
|
|
982
|
+
* probe off the hot path. Tests reset the cache via
|
|
983
|
+
* {@link setLinuxSecretToolRunner}.
|
|
984
|
+
*/
|
|
985
|
+
declare function probeSecretTool(): boolean;
|
|
986
|
+
/**
|
|
987
|
+
* Linux backend that stores the encryption key via libsecret's
|
|
988
|
+
* `secret-tool` CLI.
|
|
989
|
+
*
|
|
990
|
+
* The key is passed to `secret-tool store` via stdin so it never appears
|
|
991
|
+
* on the subprocess argv. Lookup writes the key envelope to stdout, which
|
|
992
|
+
* is captured by `spawnSync`.
|
|
993
|
+
*
|
|
994
|
+
* `secret-tool` is part of the `libsecret-tools` package on most Linux
|
|
995
|
+
* distros. The resolver in {@link "../resolver"} probes for its presence
|
|
996
|
+
* and surfaces actionable install hints when missing; this class assumes
|
|
997
|
+
* the tool is available.
|
|
998
|
+
*/
|
|
999
|
+
declare class LinuxSecretToolKeyProvider implements KeyProvider {
|
|
1000
|
+
private readonly serviceName;
|
|
1001
|
+
private readonly profile?;
|
|
1002
|
+
constructor(serviceName: string, profile?: string | undefined);
|
|
1003
|
+
getKey(): Uint8Array | undefined;
|
|
1004
|
+
setKey(key: Uint8Array): void;
|
|
1005
|
+
deleteKey(): void;
|
|
1006
|
+
describe(): string;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
/**
|
|
1010
|
+
* Backend that stores the encryption key via `@napi-rs/keyring`'s
|
|
1011
|
+
* native `Entry` class.
|
|
1012
|
+
*
|
|
1013
|
+
* Used on Windows once the binding has been lazy-installed (via the
|
|
1014
|
+
* resolver), and by tests on every platform that register an in-memory
|
|
1015
|
+
* `KeyringEntryFactory` via {@link setKeyringEntryFactory}.
|
|
1016
|
+
*
|
|
1017
|
+
* On Windows the binding talks to the Credential Manager wincred API.
|
|
1018
|
+
* On macOS / Linux (when used by tests), the test factory short-circuits
|
|
1019
|
+
* the lazy load so no real keychain is touched.
|
|
1020
|
+
*/
|
|
1021
|
+
declare class NapiKeyringKeyProvider implements KeyProvider {
|
|
1022
|
+
private readonly serviceName;
|
|
1023
|
+
private readonly installDir;
|
|
1024
|
+
private readonly profile?;
|
|
1025
|
+
/**
|
|
1026
|
+
* @param serviceName keyring service identifier (e.g. `"wrangler"`).
|
|
1027
|
+
* @param installDir directory hosting the lazy-installed `@napi-rs/keyring`
|
|
1028
|
+
* binding, derived from the consumer's config path.
|
|
1029
|
+
* @param profile the auth profile (selects the keyring account name).
|
|
1030
|
+
*/
|
|
1031
|
+
constructor(serviceName: string, installDir: string, profile?: string | undefined);
|
|
1032
|
+
private entry;
|
|
1033
|
+
getKey(): Uint8Array | undefined;
|
|
1034
|
+
setKey(key: Uint8Array): void;
|
|
1035
|
+
deleteKey(): void;
|
|
1036
|
+
describe(): string;
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
/**
|
|
1040
|
+
* Pinned version of `@napi-rs/keyring` that gets installed lazily on
|
|
1041
|
+
* Windows when the user opts into keyring storage.
|
|
1042
|
+
*
|
|
1043
|
+
* Hard-coded so we stamp the same version into both the user-facing
|
|
1044
|
+
* "install it globally" hint and the actual `npm install` command —
|
|
1045
|
+
* ensuring CI users running the global-install workaround see exactly
|
|
1046
|
+
* the version we tested against.
|
|
1047
|
+
*/
|
|
1048
|
+
declare const PINNED_KEYRING_VERSION = "1.3.0";
|
|
1049
|
+
/** Signature of the `npm` invoker. Overridable for tests. */
|
|
1050
|
+
type NpmRunner = (args: string[]) => SpawnSyncReturns<string>;
|
|
1051
|
+
/**
|
|
1052
|
+
* Override the `npm` invoker for tests. Pass `undefined` to restore the
|
|
1053
|
+
* default real-process runner. Resets the memoized
|
|
1054
|
+
* {@link findKeyringBinding} cache so the next call re-probes through
|
|
1055
|
+
* the new runner.
|
|
1056
|
+
*/
|
|
1057
|
+
declare function setNpmRunner(fn: NpmRunner | undefined): void;
|
|
1058
|
+
/**
|
|
1059
|
+
* Directory used to host the lazy-installed `@napi-rs/keyring` binding, under
|
|
1060
|
+
* the consumer-provided global config directory (`configPath`). A sibling of
|
|
1061
|
+
* the credentials dir so `runInTempDir()` test fixtures (which redirect `HOME`
|
|
1062
|
+
* / `XDG_CONFIG_HOME`) isolate the install dir alongside everything else stored
|
|
1063
|
+
* under the config path.
|
|
1064
|
+
*
|
|
1065
|
+
* `configPath` is supplied by the client (wrangler, or a future `cf` CLI) — the
|
|
1066
|
+
* same value used for the credential files — so each CLI's native binding lives
|
|
1067
|
+
* under its own config directory rather than a hard-coded wrangler location.
|
|
1068
|
+
*/
|
|
1069
|
+
declare function getKeyringInstallDir(configPath: string): string;
|
|
1070
|
+
/**
|
|
1071
|
+
* Locate an installed `@napi-rs/keyring` binding usable from this process.
|
|
1072
|
+
*
|
|
1073
|
+
* Search order:
|
|
1074
|
+
* 1. The private install dir written by {@link installKeyringBindingSync}.
|
|
1075
|
+
* 2. The user's global npm root, so a manual `npm install -g
|
|
1076
|
+
* @napi-rs/keyring` works in CI environments where the lazy install
|
|
1077
|
+
* path is unavailable.
|
|
1078
|
+
*
|
|
1079
|
+
* Returns `null` when no binding is available; callers handle the missing
|
|
1080
|
+
* binding case explicitly so they can surface remediation instructions.
|
|
1081
|
+
*
|
|
1082
|
+
* The result is memoized per-process, keyed by `installDir`. The resolver
|
|
1083
|
+
* calls this on every credential operation, so without caching we would spawn
|
|
1084
|
+
* `npm root -g` each time the binding is not in the lazy dir. The cache is
|
|
1085
|
+
* invalidated by {@link installKeyringBindingSync} on a successful install and
|
|
1086
|
+
* by {@link setNpmRunner} for test isolation.
|
|
1087
|
+
*/
|
|
1088
|
+
declare function findKeyringBinding(installDir: string): string | null;
|
|
1089
|
+
/**
|
|
1090
|
+
* Install `@napi-rs/keyring` into the private install dir using the user's
|
|
1091
|
+
* `npm`.
|
|
1092
|
+
*
|
|
1093
|
+
* Throws a {@link UserError} when `npm` cannot be spawned or returns a
|
|
1094
|
+
* non-zero exit code, so callers can surface actionable remediation hints
|
|
1095
|
+
* rather than a raw stack trace.
|
|
1096
|
+
*/
|
|
1097
|
+
declare function installKeyringBindingSync(installDir: string): void;
|
|
1098
|
+
/**
|
|
1099
|
+
* Minimal slice of `@napi-rs/keyring`'s `Entry` class that {@link
|
|
1100
|
+
* NapiKeyringKeyProvider} depends on.
|
|
1101
|
+
*
|
|
1102
|
+
* Defined locally so we can load the underlying module lazily — the native
|
|
1103
|
+
* binary must not be required (and `dlopen`-ed) unless the user has
|
|
1104
|
+
* actually opted into keyring storage.
|
|
1105
|
+
*/
|
|
1106
|
+
interface KeyringEntry {
|
|
1107
|
+
setPassword(password: string): void;
|
|
1108
|
+
getPassword(): string | null;
|
|
1109
|
+
deletePassword(): boolean;
|
|
1110
|
+
}
|
|
1111
|
+
/** Factory signature used by `NapiKeyringKeyProvider` to create entries. */
|
|
1112
|
+
type KeyringEntryFactory = (service: string, account: string) => KeyringEntry;
|
|
1113
|
+
/**
|
|
1114
|
+
* Override the keyring entry factory used by `NapiKeyringKeyProvider`.
|
|
1115
|
+
*
|
|
1116
|
+
* Tests use this to inject an in-memory fake so they never touch the
|
|
1117
|
+
* developer machine's real keychain. Pass `undefined` to restore the
|
|
1118
|
+
* default (lazy dynamic require).
|
|
1119
|
+
*/
|
|
1120
|
+
declare function setKeyringEntryFactory(factory: KeyringEntryFactory | undefined): void;
|
|
1121
|
+
|
|
1122
|
+
/**
|
|
1123
|
+
* Outcome of trying to create a `KeyProvider` for the current platform.
|
|
1124
|
+
*
|
|
1125
|
+
* - `available`: a provider exists and is ready to use immediately.
|
|
1126
|
+
* - `needs-install`: a provider is in principle supported but the local
|
|
1127
|
+
* binding/tool isn't installed yet. The resolver decides whether to
|
|
1128
|
+
* attempt an interactive install or surface remediation.
|
|
1129
|
+
* - `unsupported`: the platform has no `KeyProvider` implementation
|
|
1130
|
+
* (e.g. FreeBSD). The resolver falls back to file storage.
|
|
1131
|
+
*/
|
|
1132
|
+
type KeyProviderResolution = {
|
|
1133
|
+
kind: "available";
|
|
1134
|
+
provider: KeyProvider;
|
|
1135
|
+
} | {
|
|
1136
|
+
kind: "needs-install";
|
|
1137
|
+
install: () => void;
|
|
1138
|
+
afterInstall: () => KeyProvider;
|
|
1139
|
+
} | {
|
|
1140
|
+
kind: "unsupported";
|
|
1141
|
+
};
|
|
1142
|
+
/**
|
|
1143
|
+
* Inject a `KeyProvider` factory for testing. Pass `undefined` to restore
|
|
1144
|
+
* the real per-platform resolution. The factory receives the auth profile
|
|
1145
|
+
* so profile-aware tests can hand back a provider scoped to that profile.
|
|
1146
|
+
*/
|
|
1147
|
+
declare function setKeyProviderFactoryForTesting(factory: ((serviceName: string, profile?: string) => KeyProvider) | undefined): void;
|
|
1148
|
+
/**
|
|
1149
|
+
* Resolve the appropriate `KeyProvider` for the current platform.
|
|
1150
|
+
*
|
|
1151
|
+
* Pure resolution: this function never spawns long-running work, never
|
|
1152
|
+
* installs anything, and never logs. The "needs-install" arm returns
|
|
1153
|
+
* thunks the caller can invoke once it has decided how to handle the
|
|
1154
|
+
* missing-binding case (interactive install vs. hard-error).
|
|
1155
|
+
*
|
|
1156
|
+
* `configPath` is the consumer's global config directory; on Windows it locates
|
|
1157
|
+
* the lazy-installed `@napi-rs/keyring` binding under the CLI's own config dir.
|
|
1158
|
+
* The macOS / Linux backends don't use it.
|
|
1159
|
+
*/
|
|
1160
|
+
declare function resolveKeyProvider(serviceName: string, profile: string | undefined, configPath: string): KeyProviderResolution;
|
|
1161
|
+
|
|
1162
|
+
/**
|
|
1163
|
+
* Self-documenting algorithm identifier stamped into the on-disk envelope.
|
|
1164
|
+
*/
|
|
1165
|
+
declare const ALGORITHM_LABEL = "AES-256-GCM";
|
|
1166
|
+
/**
|
|
1167
|
+
* Envelope format for the encrypted payload written to disk.
|
|
1168
|
+
*
|
|
1169
|
+
* The `v` field lets us evolve the format (e.g. switch algorithm, add key
|
|
1170
|
+
* IDs) without breaking older readers — they can detect an unknown version
|
|
1171
|
+
* and refuse to decrypt rather than fail in an obscure way deep inside
|
|
1172
|
+
* the cipher.
|
|
1173
|
+
*/
|
|
1174
|
+
interface EncryptedEnvelope {
|
|
1175
|
+
/** Schema version. Bump on incompatible changes. */
|
|
1176
|
+
v: 1;
|
|
1177
|
+
/** Algorithm label. Informational; the reader still validates against {@link CIPHER_NAME}. */
|
|
1178
|
+
alg: typeof ALGORITHM_LABEL;
|
|
1179
|
+
/** Base64-encoded 12-byte IV. */
|
|
1180
|
+
iv: string;
|
|
1181
|
+
/** Base64-encoded 16-byte GCM auth tag. */
|
|
1182
|
+
tag: string;
|
|
1183
|
+
/** Base64-encoded ciphertext. */
|
|
1184
|
+
ciphertext: string;
|
|
1185
|
+
}
|
|
1186
|
+
/**
|
|
1187
|
+
* Generate a fresh 32-byte symmetric key suitable for AES-256.
|
|
1188
|
+
*
|
|
1189
|
+
* Uses `node:crypto.randomBytes`, which is a thin wrapper over the OS
|
|
1190
|
+
* CSPRNG (`/dev/urandom` on Unix, `BCryptGenRandom` on Windows).
|
|
1191
|
+
*/
|
|
1192
|
+
declare function generateKey(): Uint8Array;
|
|
1193
|
+
/**
|
|
1194
|
+
* Encrypt a UTF-8 plaintext into an {@link EncryptedEnvelope} using
|
|
1195
|
+
* AES-256-GCM with a freshly-generated IV.
|
|
1196
|
+
*
|
|
1197
|
+
* GCM is authenticated encryption: the auth tag is computed over the
|
|
1198
|
+
* ciphertext and validated by {@link decryptString}. Any tampering with
|
|
1199
|
+
* the IV, tag, or ciphertext causes decryption to throw.
|
|
1200
|
+
*
|
|
1201
|
+
* IV uniqueness is critical for GCM security — generating a fresh random
|
|
1202
|
+
* IV per call (rather than counter-based) keeps callers from accidentally
|
|
1203
|
+
* reusing one when the same key encrypts multiple payloads.
|
|
1204
|
+
*/
|
|
1205
|
+
declare function encryptString(plaintext: string, key: Uint8Array): EncryptedEnvelope;
|
|
1206
|
+
/**
|
|
1207
|
+
* Decrypt an {@link EncryptedEnvelope} back into the original UTF-8
|
|
1208
|
+
* plaintext.
|
|
1209
|
+
*
|
|
1210
|
+
* @throws {Error} when the key length is wrong, the envelope version is
|
|
1211
|
+
* unknown, the IV/tag lengths don't match what AES-GCM expects, or the
|
|
1212
|
+
* GCM auth tag fails to verify (tampering or wrong key).
|
|
1213
|
+
*/
|
|
1214
|
+
declare function decryptString(envelope: EncryptedEnvelope, key: Uint8Array): string;
|
|
1215
|
+
/**
|
|
1216
|
+
* Type-narrow `unknown` to an {@link EncryptedEnvelope}, returning
|
|
1217
|
+
* `undefined` when the input doesn't match the schema.
|
|
1218
|
+
*
|
|
1219
|
+
* Used by {@link EncryptedFileCredentialStore.read} to handle corrupted /
|
|
1220
|
+
* truncated / pre-format-v1 files as "no credentials stored" rather than
|
|
1221
|
+
* crashing the consumer.
|
|
1222
|
+
*/
|
|
1223
|
+
declare function parseEncryptedEnvelope(raw: unknown): EncryptedEnvelope | undefined;
|
|
1224
|
+
|
|
1225
|
+
export { type AuthConfigStorage, type ConfigStorage, type CredentialStorageBundle, type CredentialStorageContext, type CredentialStore, type DeactivateDirectoryResult, type DirectoryBindingOperations, type DirectoryBindingsStorage, type EncryptedEnvelope, EncryptedFileCredentialStore, FileCredentialStore, type KeyProvider, type KeyProviderResolution, type KeyringEntry, type KeyringEntryFactory, LinuxSecretToolKeyProvider, type LinuxSecretToolRunner, type LoginOrRefreshFailureReason, type LoginOrRefreshResult, type LoginProps, type MacSecurityCommandRunner, MacSecurityKeyProvider, NapiKeyringKeyProvider, type NpmRunner, type OAuthFlowContext, type OAuthFlowLogger, PINNED_KEYRING_VERSION, PKCE_CHARSET, type ProfileConfigOperations, type ProfileStore, type ScrubEncryptedCredentialsResult, TEMPORARY_TERMS_NOTICE, TEMPORARY_TERMS_PROMPT, type TemporaryPreviewAccount, type UserAuthConfig, clearAccessCaches, clearCredentialStorageState, createCredentialStorageContext, createOAuthFlow, createProfileStore, decryptString, domainUsesAccess, encryptString, findKeyringBinding, generateAuthUrl, generateKey, generateRandomState, getAccessHeaders, getAuthConfigFilePath, getAuthFromEnv, getAuthUrlFromEnv, getCloudflareAPITokenFromEnv, getCloudflareAuthUseKeyringFromEnv, getCloudflareGlobalAuthEmailFromEnv, getCloudflareGlobalAuthKeyFromEnv, getEncryptedAuthConfigFilePath, getKeyringAccountName, getKeyringInstallDir, installKeyringBindingSync, parseEncryptedEnvelope, probeSecretTool, readStoredAuthState, resetCredentialStorageState, resolveKeyProvider, scrubEncryptedCredentials, setKeyProviderFactoryForTesting, setKeyringEntryFactory, setLinuxSecretToolRunner, setMacSecurityCommandRunner, setNpmRunner, validateProfileName };
|