@alchemy.run/acme 0.0.0 → 2.0.0-beta.85
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/LICENSE +201 -0
- package/README.md +48 -4
- package/lib/Account.d.ts +121 -0
- package/lib/Account.d.ts.map +1 -0
- package/lib/Account.js +163 -0
- package/lib/Account.js.map +1 -0
- package/lib/Certificate.d.ts +138 -0
- package/lib/Certificate.d.ts.map +1 -0
- package/lib/Certificate.js +157 -0
- package/lib/Certificate.js.map +1 -0
- package/lib/CertificateAuthority.d.ts +25 -0
- package/lib/CertificateAuthority.d.ts.map +1 -0
- package/lib/CertificateAuthority.js +22 -0
- package/lib/CertificateAuthority.js.map +1 -0
- package/lib/Client.d.ts +89 -0
- package/lib/Client.d.ts.map +1 -0
- package/lib/Client.js +237 -0
- package/lib/Client.js.map +1 -0
- package/lib/Der.d.ts +43 -0
- package/lib/Der.d.ts.map +1 -0
- package/lib/Der.js +138 -0
- package/lib/Der.js.map +1 -0
- package/lib/Dns.d.ts +59 -0
- package/lib/Dns.d.ts.map +1 -0
- package/lib/Dns.js +104 -0
- package/lib/Dns.js.map +1 -0
- package/lib/DnsSolver.d.ts +60 -0
- package/lib/DnsSolver.d.ts.map +1 -0
- package/lib/DnsSolver.js +48 -0
- package/lib/DnsSolver.js.map +1 -0
- package/lib/Errors.d.ts +93 -0
- package/lib/Errors.d.ts.map +1 -0
- package/lib/Errors.js +51 -0
- package/lib/Errors.js.map +1 -0
- package/lib/IssueCertificate.d.ts +76 -0
- package/lib/IssueCertificate.d.ts.map +1 -0
- package/lib/IssueCertificate.js +3 -0
- package/lib/IssueCertificate.js.map +1 -0
- package/lib/IssueCertificateHttp.d.ts +24 -0
- package/lib/IssueCertificateHttp.d.ts.map +1 -0
- package/lib/IssueCertificateHttp.js +56 -0
- package/lib/IssueCertificateHttp.js.map +1 -0
- package/lib/Pki.d.ts +56 -0
- package/lib/Pki.d.ts.map +1 -0
- package/lib/Pki.js +182 -0
- package/lib/Pki.js.map +1 -0
- package/lib/Providers.d.ts +30 -0
- package/lib/Providers.d.ts.map +1 -0
- package/lib/Providers.js +31 -0
- package/lib/Providers.js.map +1 -0
- package/lib/index.d.ts +12 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +12 -0
- package/lib/index.js.map +1 -0
- package/package.json +47 -3
- package/src/Account.ts +254 -0
- package/src/Certificate.ts +272 -0
- package/src/CertificateAuthority.ts +41 -0
- package/src/Client.ts +405 -0
- package/src/Der.ts +157 -0
- package/src/Dns.ts +227 -0
- package/src/DnsSolver.ts +109 -0
- package/src/Errors.ts +90 -0
- package/src/IssueCertificate.ts +89 -0
- package/src/IssueCertificateHttp.ts +67 -0
- package/src/Pki.ts +275 -0
- package/src/Providers.ts +39 -0
- package/src/index.ts +11 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DNS-01 solvers: how the ACME flow publishes `_acme-challenge` TXT
|
|
3
|
+
* records.
|
|
4
|
+
*
|
|
5
|
+
* A solver has two forms:
|
|
6
|
+
*
|
|
7
|
+
* - a **descriptor** — plain, serializable data in a resource's props
|
|
8
|
+
* (`{ type: "Cloudflare.DNS", zoneId }`) that survives state and the RPC
|
|
9
|
+
* boundary. Each DNS solver has a constructor
|
|
10
|
+
* (`Cloudflare.ACME.ZoneSolver(zone)`) and a layer registering the
|
|
11
|
+
* matching implementation, so the ACME provider never imports a DNS SDK
|
|
12
|
+
* itself.
|
|
13
|
+
* - a **runtime solver** — the {@link DnsSolver} interface a running
|
|
14
|
+
* Worker or Service hands to `IssueCertificate.issue`, built from a
|
|
15
|
+
* runtime DNS write client (`Cloudflare.ACME.zoneSolver(dns)`).
|
|
16
|
+
*/
|
|
17
|
+
import * as Context from "effect/Context";
|
|
18
|
+
import * as Effect from "effect/Effect";
|
|
19
|
+
import type * as HttpClient from "effect/http/HttpClient";
|
|
20
|
+
import * as Layer from "effect/Layer";
|
|
21
|
+
import type { PropagationOptions } from "./Dns.ts";
|
|
22
|
+
import { DnsSolverNotRegistered, type DnsPropagationTimeout, type DnsSolverError } from "./Errors.ts";
|
|
23
|
+
/** A challenge record to publish: the `_acme-challenge.<name>` FQDN and its TXT value. */
|
|
24
|
+
export interface DnsChallengeRecord {
|
|
25
|
+
readonly fqdn: string;
|
|
26
|
+
readonly value: string;
|
|
27
|
+
}
|
|
28
|
+
/** Runtime DNS-01 solver. `R` is whatever context the underlying client needs. */
|
|
29
|
+
export interface DnsSolver<R = never> {
|
|
30
|
+
/** Publish `value` as a TXT record at `fqdn`. Idempotent. */
|
|
31
|
+
readonly present: (record: DnsChallengeRecord) => Effect.Effect<void, DnsSolverError, R>;
|
|
32
|
+
/** Remove the record published by `present`. Idempotent; runs in a finalizer. */
|
|
33
|
+
readonly cleanup: (record: DnsChallengeRecord) => Effect.Effect<void, DnsSolverError, R>;
|
|
34
|
+
/**
|
|
35
|
+
* Wait until the record is visible. Defaults to polling public DNS over
|
|
36
|
+
* HTTPS; a solver for a private DNS (tests, split-horizon zones) overrides it.
|
|
37
|
+
*/
|
|
38
|
+
readonly propagated?: ((record: DnsChallengeRecord, options: PropagationOptions) => Effect.Effect<void, DnsSolverError | DnsPropagationTimeout, R | HttpClient.HttpClient>) | undefined;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Serializable solver description stored in `ACME.Certificate` props.
|
|
42
|
+
* `type` selects the registered implementation; the rest is provider data.
|
|
43
|
+
*/
|
|
44
|
+
export interface DnsSolverDescriptor {
|
|
45
|
+
readonly type: string;
|
|
46
|
+
readonly [key: string]: unknown;
|
|
47
|
+
}
|
|
48
|
+
/** Builds a runtime solver from a descriptor at reconcile time. */
|
|
49
|
+
export type DnsSolverFactory = (descriptor: DnsSolverDescriptor) => Effect.Effect<DnsSolver, DnsSolverError>;
|
|
50
|
+
/** Resolve the registered implementation for a descriptor. */
|
|
51
|
+
export declare const resolveDnsSolver: (descriptor: DnsSolverDescriptor) => Effect.Effect<DnsSolver, DnsSolverNotRegistered | DnsSolverError>;
|
|
52
|
+
/** A solver whose methods run with `context` provided (drops `R`). */
|
|
53
|
+
export declare const provideSolver: <R>(solver: DnsSolver<R>, context: Context.Context<R>) => DnsSolver;
|
|
54
|
+
/**
|
|
55
|
+
* Register a solver implementation from a `providers()` layer, capturing
|
|
56
|
+
* whatever services `R` the solver needs from that layer's own context so
|
|
57
|
+
* the ACME provider can run it without knowing about the DNS provider.
|
|
58
|
+
*/
|
|
59
|
+
export declare const dnsSolverLayer: <R>(type: string, make: (descriptor: DnsSolverDescriptor) => Effect.Effect<DnsSolver<R>, DnsSolverError>) => Layer.Layer<DnsSolverFactory, never, R>;
|
|
60
|
+
//# sourceMappingURL=DnsSolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DnsSolver.d.ts","sourceRoot":"","sources":["../src/DnsSolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,UAAU,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAEtC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AACnD,OAAO,EACL,sBAAsB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACpB,MAAM,aAAa,CAAC;AAErB,0FAA0F;AAC1F,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,kFAAkF;AAClF,MAAM,WAAW,SAAS,CAAC,CAAC,GAAG,KAAK;IAClC,6DAA6D;IAC7D,QAAQ,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC;IACzF,iFAAiF;IACjF,QAAQ,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC;IACzF;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAChB,CAAC,CACC,MAAM,EAAE,kBAAkB,EAC1B,OAAO,EAAE,kBAAkB,KACxB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,cAAc,GAAG,qBAAqB,EAAE,CAAC,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC,GAC5F,SAAS,CAAC;CACf;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC;AAED,mEAAmE;AACnE,MAAM,MAAM,gBAAgB,GAAG,CAC7B,UAAU,EAAE,mBAAmB,KAC5B,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;AAK9C,8DAA8D;AAC9D,eAAO,MAAM,gBAAgB,eACf,mBAAmB,KAC9B,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,sBAAsB,GAAG,cAAc,CAO/D,CAAC;AAEL,sEAAsE;AACtE,eAAO,MAAM,aAAa,GAAI,CAAC,UAAU,SAAS,CAAC,CAAC,CAAC,WAAW,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,KAAG,SAQnF,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,cAAc,GAAI,CAAC,QACxB,MAAM,QACN,CAAC,UAAU,EAAE,mBAAmB,KAAK,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,KACrF,KAAK,CAAC,KAAK,CAAC,gBAAgB,EAAE,KAAK,EAAE,CAAC,CAQtC,CAAC"}
|
package/lib/DnsSolver.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DNS-01 solvers: how the ACME flow publishes `_acme-challenge` TXT
|
|
3
|
+
* records.
|
|
4
|
+
*
|
|
5
|
+
* A solver has two forms:
|
|
6
|
+
*
|
|
7
|
+
* - a **descriptor** — plain, serializable data in a resource's props
|
|
8
|
+
* (`{ type: "Cloudflare.DNS", zoneId }`) that survives state and the RPC
|
|
9
|
+
* boundary. Each DNS solver has a constructor
|
|
10
|
+
* (`Cloudflare.ACME.ZoneSolver(zone)`) and a layer registering the
|
|
11
|
+
* matching implementation, so the ACME provider never imports a DNS SDK
|
|
12
|
+
* itself.
|
|
13
|
+
* - a **runtime solver** — the {@link DnsSolver} interface a running
|
|
14
|
+
* Worker or Service hands to `IssueCertificate.issue`, built from a
|
|
15
|
+
* runtime DNS write client (`Cloudflare.ACME.zoneSolver(dns)`).
|
|
16
|
+
*/
|
|
17
|
+
import * as Context from "effect/Context";
|
|
18
|
+
import * as Effect from "effect/Effect";
|
|
19
|
+
import * as Layer from "effect/Layer";
|
|
20
|
+
import * as Option from "effect/Option";
|
|
21
|
+
import { DnsSolverNotRegistered, } from "./Errors.js";
|
|
22
|
+
const solverService = (type) => Context.Service(`alchemy/ACME/DnsSolver/${type}`);
|
|
23
|
+
/** Resolve the registered implementation for a descriptor. */
|
|
24
|
+
export const resolveDnsSolver = (descriptor) => Effect.gen(function* () {
|
|
25
|
+
const factory = yield* Effect.serviceOption(solverService(descriptor.type));
|
|
26
|
+
if (Option.isNone(factory)) {
|
|
27
|
+
return yield* new DnsSolverNotRegistered({ type: descriptor.type });
|
|
28
|
+
}
|
|
29
|
+
return yield* factory.value(descriptor);
|
|
30
|
+
});
|
|
31
|
+
/** A solver whose methods run with `context` provided (drops `R`). */
|
|
32
|
+
export const provideSolver = (solver, context) => ({
|
|
33
|
+
present: (record) => solver.present(record).pipe(Effect.provideContext(context)),
|
|
34
|
+
cleanup: (record) => solver.cleanup(record).pipe(Effect.provideContext(context)),
|
|
35
|
+
propagated: solver.propagated === undefined
|
|
36
|
+
? undefined
|
|
37
|
+
: (record, options) => solver.propagated(record, options).pipe(Effect.provideContext(context)),
|
|
38
|
+
});
|
|
39
|
+
/**
|
|
40
|
+
* Register a solver implementation from a `providers()` layer, capturing
|
|
41
|
+
* whatever services `R` the solver needs from that layer's own context so
|
|
42
|
+
* the ACME provider can run it without knowing about the DNS provider.
|
|
43
|
+
*/
|
|
44
|
+
export const dnsSolverLayer = (type, make) => Layer.effect(solverService(type), Effect.gen(function* () {
|
|
45
|
+
const context = yield* Effect.context();
|
|
46
|
+
return (descriptor) => make(descriptor).pipe(Effect.map((solver) => provideSolver(solver, context)));
|
|
47
|
+
}));
|
|
48
|
+
//# sourceMappingURL=DnsSolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DnsSolver.js","sourceRoot":"","sources":["../src/DnsSolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,EACL,sBAAsB,GAGvB,MAAM,aAAa,CAAC;AAwCrB,MAAM,aAAa,GAAG,CAAC,IAAY,EAAE,EAAE,CACrC,OAAO,CAAC,OAAO,CAAmB,0BAA0B,IAAI,EAAE,CAAC,CAAC;AAEtE,8DAA8D;AAC9D,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,UAA+B,EACoC,EAAE,CACrE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,aAAa,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5E,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC,CAAC,IAAI,sBAAsB,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;AAC1C,CAAC,CAAC,CAAC;AAEL,sEAAsE;AACtE,MAAM,CAAC,MAAM,aAAa,GAAG,CAAI,MAAoB,EAAE,OAA2B,EAAa,EAAE,CAAC,CAAC;IACjG,OAAO,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;IAChF,OAAO,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;IAChF,UAAU,EACR,MAAM,CAAC,UAAU,KAAK,SAAS;QAC7B,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,CAClB,MAAM,CAAC,UAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;CACjF,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,IAAY,EACZ,IAAsF,EAC7C,EAAE,CAC3C,KAAK,CAAC,MAAM,CACV,aAAa,CAAC,IAAI,CAAC,EACnB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,EAAK,CAAC;IAC3C,OAAO,CAAC,UAA+B,EAAE,EAAE,CACzC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;AAClF,CAAC,CAAC,CACH,CAAC"}
|
package/lib/Errors.d.ts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/** A problem the CA attached to an order or one of its identifiers. */
|
|
2
|
+
export interface IdentifierProblem {
|
|
3
|
+
/** The identifier the problem concerns, when the CA said. */
|
|
4
|
+
readonly identifier?: string | undefined;
|
|
5
|
+
/** The `urn:ietf:params:acme:error:*` type. */
|
|
6
|
+
readonly type?: string | undefined;
|
|
7
|
+
/** Human-readable detail from the CA. */
|
|
8
|
+
readonly detail?: string | undefined;
|
|
9
|
+
}
|
|
10
|
+
declare const OrderInvalid_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
11
|
+
readonly _tag: "ACME.OrderInvalid";
|
|
12
|
+
} & Readonly<A>;
|
|
13
|
+
/**
|
|
14
|
+
* The CA moved the order to `invalid`. Carries the problem documents the
|
|
15
|
+
* order and its authorizations reported, one per failed identifier where
|
|
16
|
+
* the CA said which.
|
|
17
|
+
*/
|
|
18
|
+
export declare class OrderInvalid extends OrderInvalid_base<{
|
|
19
|
+
readonly orderUrl: string;
|
|
20
|
+
readonly problems: ReadonlyArray<IdentifierProblem>;
|
|
21
|
+
}> {
|
|
22
|
+
get message(): string;
|
|
23
|
+
}
|
|
24
|
+
declare const ChallengeFailed_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
25
|
+
readonly _tag: "ACME.ChallengeFailed";
|
|
26
|
+
} & Readonly<A>;
|
|
27
|
+
/** The CA rejected the DNS-01 challenge for one identifier. */
|
|
28
|
+
export declare class ChallengeFailed extends ChallengeFailed_base<{
|
|
29
|
+
readonly identifier: string;
|
|
30
|
+
readonly type?: string | undefined;
|
|
31
|
+
readonly detail?: string | undefined;
|
|
32
|
+
}> {
|
|
33
|
+
get message(): string;
|
|
34
|
+
}
|
|
35
|
+
declare const ChallengeUnsupported_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
36
|
+
readonly _tag: "ACME.ChallengeUnsupported";
|
|
37
|
+
} & Readonly<A>;
|
|
38
|
+
/** The CA offered no `dns-01` challenge for an identifier. */
|
|
39
|
+
export declare class ChallengeUnsupported extends ChallengeUnsupported_base<{
|
|
40
|
+
readonly identifier: string;
|
|
41
|
+
readonly offered: ReadonlyArray<string>;
|
|
42
|
+
}> {
|
|
43
|
+
get message(): string;
|
|
44
|
+
}
|
|
45
|
+
declare const OrderTimeout_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
46
|
+
readonly _tag: "ACME.OrderTimeout";
|
|
47
|
+
} & Readonly<A>;
|
|
48
|
+
/** The order never reached a terminal state within the polling budget. */
|
|
49
|
+
export declare class OrderTimeout extends OrderTimeout_base<{
|
|
50
|
+
readonly orderUrl: string;
|
|
51
|
+
readonly status: string;
|
|
52
|
+
}> {
|
|
53
|
+
get message(): string;
|
|
54
|
+
}
|
|
55
|
+
declare const DnsPropagationTimeout_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
56
|
+
readonly _tag: "ACME.DnsPropagationTimeout";
|
|
57
|
+
} & Readonly<A>;
|
|
58
|
+
/** The `_acme-challenge` TXT record never became visible to public resolvers. */
|
|
59
|
+
export declare class DnsPropagationTimeout extends DnsPropagationTimeout_base<{
|
|
60
|
+
readonly fqdn: string;
|
|
61
|
+
readonly value: string;
|
|
62
|
+
}> {
|
|
63
|
+
get message(): string;
|
|
64
|
+
}
|
|
65
|
+
declare const DnsSolverError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
66
|
+
readonly _tag: "ACME.DnsSolverError";
|
|
67
|
+
} & Readonly<A>;
|
|
68
|
+
/** A DNS solver could not publish or remove a challenge record. */
|
|
69
|
+
export declare class DnsSolverError extends DnsSolverError_base<{
|
|
70
|
+
readonly message: string;
|
|
71
|
+
readonly cause?: unknown;
|
|
72
|
+
}> {
|
|
73
|
+
}
|
|
74
|
+
declare const DnsSolverNotRegistered_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
75
|
+
readonly _tag: "ACME.DnsSolverNotRegistered";
|
|
76
|
+
} & Readonly<A>;
|
|
77
|
+
/** A solver descriptor names a `type` no registered DNS provider handles. */
|
|
78
|
+
export declare class DnsSolverNotRegistered extends DnsSolverNotRegistered_base<{
|
|
79
|
+
readonly type: string;
|
|
80
|
+
}> {
|
|
81
|
+
get message(): string;
|
|
82
|
+
}
|
|
83
|
+
declare const PkiError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
84
|
+
readonly _tag: "ACME.PkiError";
|
|
85
|
+
} & Readonly<A>;
|
|
86
|
+
/** Key generation, CSR encoding or certificate parsing failed. */
|
|
87
|
+
export declare class PkiError extends PkiError_base<{
|
|
88
|
+
readonly message: string;
|
|
89
|
+
readonly cause?: unknown;
|
|
90
|
+
}> {
|
|
91
|
+
}
|
|
92
|
+
export {};
|
|
93
|
+
//# sourceMappingURL=Errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Errors.d.ts","sourceRoot":"","sources":["../src/Errors.ts"],"names":[],"mappings":"AAEA,uEAAuE;AACvE,MAAM,WAAW,iBAAiB;IAChC,6DAA6D;IAC7D,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,+CAA+C;IAC/C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,yCAAyC;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC;;;;AAED;;;;GAIG;AACH,qBAAa,YAAa,SAAQ,kBAAsC;IACtE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAC;CACrD,CAAC;IACA,IAAa,OAAO,WAKnB;CACF;;;;AAED,+DAA+D;AAC/D,qBAAa,eAAgB,SAAQ,qBAAyC;IAC5E,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC,CAAC;IACA,IAAa,OAAO,WAEnB;CACF;;;;AAED,8DAA8D;AAC9D,qBAAa,oBAAqB,SAAQ,0BAA8C;IACtF,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CACzC,CAAC;IACA,IAAa,OAAO,WAEnB;CACF;;;;AAED,0EAA0E;AAC1E,qBAAa,YAAa,SAAQ,kBAAsC;IACtE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;IACA,IAAa,OAAO,WAEnB;CACF;;;;AAED,iFAAiF;AACjF,qBAAa,qBAAsB,SAAQ,2BAA+C;IACxF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,CAAC;IACA,IAAa,OAAO,WAEnB;CACF;;;;AAED,mEAAmE;AACnE,qBAAa,cAAe,SAAQ,oBAAwC;IAC1E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;CAAG;;;;AAEL,6EAA6E;AAC7E,qBAAa,sBAAuB,SAAQ,4BAAgD;IAC1F,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,CAAC;IACA,IAAa,OAAO,WAEnB;CACF;;;;AAED,kEAAkE;AAClE,qBAAa,QAAS,SAAQ,cAAkC;IAC9D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;CAAG"}
|
package/lib/Errors.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as Data from "effect/Data";
|
|
2
|
+
/**
|
|
3
|
+
* The CA moved the order to `invalid`. Carries the problem documents the
|
|
4
|
+
* order and its authorizations reported, one per failed identifier where
|
|
5
|
+
* the CA said which.
|
|
6
|
+
*/
|
|
7
|
+
export class OrderInvalid extends Data.TaggedError("ACME.OrderInvalid") {
|
|
8
|
+
get message() {
|
|
9
|
+
const details = this.problems
|
|
10
|
+
.map((p) => [p.identifier, p.type, p.detail].filter(Boolean).join(": "))
|
|
11
|
+
.join("; ");
|
|
12
|
+
return `ACME order ${this.orderUrl} is invalid${details ? `: ${details}` : ""}`;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** The CA rejected the DNS-01 challenge for one identifier. */
|
|
16
|
+
export class ChallengeFailed extends Data.TaggedError("ACME.ChallengeFailed") {
|
|
17
|
+
get message() {
|
|
18
|
+
return `DNS-01 challenge for ${this.identifier} failed${this.detail ? `: ${this.detail}` : ""}`;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** The CA offered no `dns-01` challenge for an identifier. */
|
|
22
|
+
export class ChallengeUnsupported extends Data.TaggedError("ACME.ChallengeUnsupported") {
|
|
23
|
+
get message() {
|
|
24
|
+
return `The CA offered no dns-01 challenge for ${this.identifier} (offered: ${this.offered.join(", ") || "none"})`;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/** The order never reached a terminal state within the polling budget. */
|
|
28
|
+
export class OrderTimeout extends Data.TaggedError("ACME.OrderTimeout") {
|
|
29
|
+
get message() {
|
|
30
|
+
return `ACME order ${this.orderUrl} is still "${this.status}" after the polling budget`;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** The `_acme-challenge` TXT record never became visible to public resolvers. */
|
|
34
|
+
export class DnsPropagationTimeout extends Data.TaggedError("ACME.DnsPropagationTimeout") {
|
|
35
|
+
get message() {
|
|
36
|
+
return `TXT ${this.fqdn} did not propagate within the wait budget`;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** A DNS solver could not publish or remove a challenge record. */
|
|
40
|
+
export class DnsSolverError extends Data.TaggedError("ACME.DnsSolverError") {
|
|
41
|
+
}
|
|
42
|
+
/** A solver descriptor names a `type` no registered DNS provider handles. */
|
|
43
|
+
export class DnsSolverNotRegistered extends Data.TaggedError("ACME.DnsSolverNotRegistered") {
|
|
44
|
+
get message() {
|
|
45
|
+
return `No DNS-01 solver is registered for "${this.type}". Include ACME.providers() in the stack.`;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/** Key generation, CSR encoding or certificate parsing failed. */
|
|
49
|
+
export class PkiError extends Data.TaggedError("ACME.PkiError") {
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=Errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Errors.js","sourceRoot":"","sources":["../src/Errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,aAAa,CAAC;AAYpC;;;;GAIG;AACH,MAAM,OAAO,YAAa,SAAQ,IAAI,CAAC,WAAW,CAAC,mBAAmB,CAGpE;IACA,IAAa,OAAO;QAClB,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ;aAC1B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;aACvE,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,OAAO,cAAc,IAAI,CAAC,QAAQ,cAAc,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IAClF,CAAC;CACF;AAED,+DAA+D;AAC/D,MAAM,OAAO,eAAgB,SAAQ,IAAI,CAAC,WAAW,CAAC,sBAAsB,CAI1E;IACA,IAAa,OAAO;QAClB,OAAO,wBAAwB,IAAI,CAAC,UAAU,UAAU,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IAClG,CAAC;CACF;AAED,8DAA8D;AAC9D,MAAM,OAAO,oBAAqB,SAAQ,IAAI,CAAC,WAAW,CAAC,2BAA2B,CAGpF;IACA,IAAa,OAAO;QAClB,OAAO,0CAA0C,IAAI,CAAC,UAAU,cAAc,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM,GAAG,CAAC;IACrH,CAAC;CACF;AAED,0EAA0E;AAC1E,MAAM,OAAO,YAAa,SAAQ,IAAI,CAAC,WAAW,CAAC,mBAAmB,CAGpE;IACA,IAAa,OAAO;QAClB,OAAO,cAAc,IAAI,CAAC,QAAQ,cAAc,IAAI,CAAC,MAAM,4BAA4B,CAAC;IAC1F,CAAC;CACF;AAED,iFAAiF;AACjF,MAAM,OAAO,qBAAsB,SAAQ,IAAI,CAAC,WAAW,CAAC,4BAA4B,CAGtF;IACA,IAAa,OAAO;QAClB,OAAO,OAAO,IAAI,CAAC,IAAI,2CAA2C,CAAC;IACrE,CAAC;CACF;AAED,mEAAmE;AACnE,MAAM,OAAO,cAAe,SAAQ,IAAI,CAAC,WAAW,CAAC,qBAAqB,CAGxE;CAAG;AAEL,6EAA6E;AAC7E,MAAM,OAAO,sBAAuB,SAAQ,IAAI,CAAC,WAAW,CAAC,6BAA6B,CAExF;IACA,IAAa,OAAO;QAClB,OAAO,uCAAuC,IAAI,CAAC,IAAI,2CAA2C,CAAC;IACrG,CAAC;CACF;AAED,kEAAkE;AAClE,MAAM,OAAO,QAAS,SAAQ,IAAI,CAAC,WAAW,CAAC,eAAe,CAG5D;CAAG"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import * as Binding from "alchemy/Binding";
|
|
2
|
+
import type { RuntimeContext } from "alchemy/RuntimeContext";
|
|
3
|
+
import type * as Effect from "effect/Effect";
|
|
4
|
+
import type { Account } from "./Account.ts";
|
|
5
|
+
import type { IssueError, IssueRequest, IssuedCertificate, RevokeError, RevokeRequest } from "./Client.ts";
|
|
6
|
+
/**
|
|
7
|
+
* Issue (and revoke) certificates at runtime as an {@link Account} — for
|
|
8
|
+
* services that terminate TLS themselves and need certificates on demand,
|
|
9
|
+
* like a relay minting `*.<tenant>.example.com` when a tenant first
|
|
10
|
+
* connects.
|
|
11
|
+
*
|
|
12
|
+
* Init transports the account's directory URL, account URL and redacted
|
|
13
|
+
* private key through resource Outputs. Protect the runtime and state store
|
|
14
|
+
* as secret material. The caller chooses where to store the issued PEMs.
|
|
15
|
+
*
|
|
16
|
+
* ### Issue on demand
|
|
17
|
+
* Publish the DNS-01 record through any runtime DNS write client wrapped
|
|
18
|
+
* as a solver (`Cloudflare.ACME.zoneSolver(dns)`).
|
|
19
|
+
*
|
|
20
|
+
* **Example:** Mint a wildcard from a Fly Service and upload it to its App
|
|
21
|
+
* ```typescript
|
|
22
|
+
* export default class Relay extends Fly.Service<Relay>()(
|
|
23
|
+
* "Relay",
|
|
24
|
+
* { app: RelayApp, main: import.meta.url },
|
|
25
|
+
* Effect.gen(function* () {
|
|
26
|
+
* const acme = yield* ACME.IssueCertificate(ZeroSsl);
|
|
27
|
+
* const dns = yield* Cloudflare.DNS.WriteDns(Zone);
|
|
28
|
+
* const certs = yield* Fly.WriteCertificates(RelayApp);
|
|
29
|
+
* return {
|
|
30
|
+
* fetch: Effect.gen(function* () {
|
|
31
|
+
* const issued = yield* acme.issue({
|
|
32
|
+
* identifiers: ["*.tenant.example.com"],
|
|
33
|
+
* solver: Cloudflare.ACME.zoneSolver(dns),
|
|
34
|
+
* });
|
|
35
|
+
* yield* certs.upload({
|
|
36
|
+
* hostname: "*.tenant.example.com",
|
|
37
|
+
* fullchain: issued.chain,
|
|
38
|
+
* privateKey: issued.privateKey,
|
|
39
|
+
* });
|
|
40
|
+
* return HttpServerResponse.text("ok");
|
|
41
|
+
* }),
|
|
42
|
+
* };
|
|
43
|
+
* }).pipe(
|
|
44
|
+
* Effect.provide(ACME.IssueCertificateHttp),
|
|
45
|
+
* Effect.provide(Cloudflare.DNS.WriteDnsHttp),
|
|
46
|
+
* Effect.provide(Fly.WriteCertificatesHttp),
|
|
47
|
+
* ),
|
|
48
|
+
* ) {}
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* ### Rate limits
|
|
52
|
+
* The SDK retry policy applies to individual requests. Apply
|
|
53
|
+
* `Acme.Retry.none` from `@distilled.cloud/acme` to surface failures
|
|
54
|
+
* immediately; `AcmeRateLimited.retryAfter` carries the CA's retry hint.
|
|
55
|
+
*
|
|
56
|
+
* ### Which CA from a Cloudflare Worker
|
|
57
|
+
* CA reachability depends on the host's egress. Let's Encrypt has returned
|
|
58
|
+
* TLS failures from deployed Cloudflare Workers in live testing; the
|
|
59
|
+
* deployed-Worker example uses ZeroSSL instead. Verify the selected CA
|
|
60
|
+
* from the runtime where issuance will run.
|
|
61
|
+
*
|
|
62
|
+
* @binding
|
|
63
|
+
* @product Certificate
|
|
64
|
+
* @category Certificates
|
|
65
|
+
*/
|
|
66
|
+
export interface IssueCertificate extends Binding.Service<IssueCertificate, "ACME.IssueCertificate", (account: Account) => Effect.Effect<IssueCertificateClient>> {
|
|
67
|
+
}
|
|
68
|
+
export declare const IssueCertificate: IssueCertificate;
|
|
69
|
+
/** Runtime issuance client bound to one account. */
|
|
70
|
+
export interface IssueCertificateClient {
|
|
71
|
+
/** Order, solve DNS-01, finalize and download a certificate. */
|
|
72
|
+
issue<R = never>(request: IssueRequest<R>): Effect.Effect<IssuedCertificate, IssueError, RuntimeContext | R>;
|
|
73
|
+
/** Revoke a certificate (`AcmeAlreadyRevoked` counts as success). */
|
|
74
|
+
revoke(request: RevokeRequest): Effect.Effect<void, RevokeError, RuntimeContext>;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=IssueCertificate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IssueCertificate.d.ts","sourceRoot":"","sources":["../src/IssueCertificate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,iBAAiB,CAAC;AAC3C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,KAAK,MAAM,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EACV,UAAU,EACV,YAAY,EACZ,iBAAiB,EACjB,WAAW,EACX,aAAa,EACd,MAAM,aAAa,CAAC;AAErB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AACH,MAAM,WAAW,gBAAiB,SAAQ,OAAO,CAAC,OAAO,CACvD,gBAAgB,EAChB,uBAAuB,EACvB,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAC5D;CAAG;AAEJ,eAAO,MAAM,gBAAgB,kBAA6D,CAAC;AAE3F,oDAAoD;AACpD,MAAM,WAAW,sBAAsB;IACrC,gEAAgE;IAChE,KAAK,CAAC,CAAC,GAAG,KAAK,EACb,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,GACvB,MAAM,CAAC,MAAM,CAAC,iBAAiB,EAAE,UAAU,EAAE,cAAc,GAAG,CAAC,CAAC,CAAC;IACpE,qEAAqE;IACrE,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,cAAc,CAAC,CAAC;CAClF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IssueCertificate.js","sourceRoot":"","sources":["../src/IssueCertificate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,iBAAiB,CAAC;AA8E3C,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAmB,uBAAuB,CAAC,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as Layer from "effect/Layer";
|
|
2
|
+
import { IssueCertificate } from "./IssueCertificate.ts";
|
|
3
|
+
/**
|
|
4
|
+
* Implementation of {@link IssueCertificate}: the account's directory
|
|
5
|
+
* URL, account URL and private key are bound into the host at deploy time
|
|
6
|
+
* and read back at runtime; every call signs with them over HTTPS.
|
|
7
|
+
*
|
|
8
|
+
* Provide it on the Worker / Service / Action Effect.
|
|
9
|
+
*
|
|
10
|
+
* ### Provide the layer
|
|
11
|
+
* **Example:** On a Fly Service
|
|
12
|
+
* ```typescript
|
|
13
|
+
* Effect.gen(function* () {
|
|
14
|
+
* const acme = yield* ACME.IssueCertificate(LetsEncrypt);
|
|
15
|
+
* // ...
|
|
16
|
+
* }).pipe(Effect.provide(ACME.IssueCertificateHttp))
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @layer
|
|
20
|
+
* @product Certificate
|
|
21
|
+
* @provides ACME.IssueCertificate
|
|
22
|
+
*/
|
|
23
|
+
export declare const IssueCertificateHttp: Layer.Layer<IssueCertificate, never, never>;
|
|
24
|
+
//# sourceMappingURL=IssueCertificateHttp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IssueCertificateHttp.d.ts","sourceRoot":"","sources":["../src/IssueCertificateHttp.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAQtC,OAAO,EAAE,gBAAgB,EAA+B,MAAM,uBAAuB,CAAC;AAEtF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,oBAAoB,6CAkChC,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as Output from "alchemy/Output";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import * as Layer from "effect/Layer";
|
|
4
|
+
import { accountLayer, issueCertificate, revokeCertificate, } from "./Client.js";
|
|
5
|
+
import { IssueCertificate } from "./IssueCertificate.js";
|
|
6
|
+
/**
|
|
7
|
+
* Implementation of {@link IssueCertificate}: the account's directory
|
|
8
|
+
* URL, account URL and private key are bound into the host at deploy time
|
|
9
|
+
* and read back at runtime; every call signs with them over HTTPS.
|
|
10
|
+
*
|
|
11
|
+
* Provide it on the Worker / Service / Action Effect.
|
|
12
|
+
*
|
|
13
|
+
* ### Provide the layer
|
|
14
|
+
* **Example:** On a Fly Service
|
|
15
|
+
* ```typescript
|
|
16
|
+
* Effect.gen(function* () {
|
|
17
|
+
* const acme = yield* ACME.IssueCertificate(LetsEncrypt);
|
|
18
|
+
* // ...
|
|
19
|
+
* }).pipe(Effect.provide(ACME.IssueCertificateHttp))
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @layer
|
|
23
|
+
* @product Certificate
|
|
24
|
+
* @provides ACME.IssueCertificate
|
|
25
|
+
*/
|
|
26
|
+
export const IssueCertificateHttp = Layer.succeed(IssueCertificate, Effect.fn(function* (account) {
|
|
27
|
+
const directoryUrl = yield* account.directoryUrl;
|
|
28
|
+
const accountUrl = yield* account.accountUrl;
|
|
29
|
+
const trustedRoot = yield* account.trustedRoot.pipe(Output.map((root) => root ?? ""));
|
|
30
|
+
const privateKey = yield* account.privateKey;
|
|
31
|
+
const credentials = Effect.all({
|
|
32
|
+
directoryUrl,
|
|
33
|
+
trustedRoot,
|
|
34
|
+
accountUrl,
|
|
35
|
+
privateKey,
|
|
36
|
+
}).pipe(Effect.map((bound) => ({
|
|
37
|
+
ca: {
|
|
38
|
+
directoryUrl: bound.directoryUrl,
|
|
39
|
+
trustedRoot: bound.trustedRoot || undefined,
|
|
40
|
+
},
|
|
41
|
+
accountKey: bound.privateKey,
|
|
42
|
+
accountUrl: bound.accountUrl,
|
|
43
|
+
})));
|
|
44
|
+
const client = {
|
|
45
|
+
issue: Effect.fn("ACME.IssueCertificate.issue")(function* (request) {
|
|
46
|
+
const creds = yield* credentials;
|
|
47
|
+
return yield* issueCertificate(request).pipe(Effect.provide(accountLayer(creds)));
|
|
48
|
+
}),
|
|
49
|
+
revoke: Effect.fn("ACME.IssueCertificate.revoke")(function* (request) {
|
|
50
|
+
const creds = yield* credentials;
|
|
51
|
+
return yield* revokeCertificate(request).pipe(Effect.provide(accountLayer(creds)));
|
|
52
|
+
}),
|
|
53
|
+
};
|
|
54
|
+
return client;
|
|
55
|
+
}));
|
|
56
|
+
//# sourceMappingURL=IssueCertificateHttp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IssueCertificateHttp.js","sourceRoot":"","sources":["../src/IssueCertificateHttp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,gBAAgB,CAAC;AACzC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAEtC,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,GAElB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,gBAAgB,EAA+B,MAAM,uBAAuB,CAAC;AAEtF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,KAAK,CAAC,OAAO,CAC/C,gBAAgB,EAChB,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,OAAgB;IACnC,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;IACjD,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;IAC7C,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;IACtF,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;IAC7C,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC;QAC7B,YAAY;QACZ,WAAW;QACX,UAAU;QACV,UAAU;KACX,CAAC,CAAC,IAAI,CACL,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAsB,EAAE,CAAC,CAAC;QACzC,EAAE,EAAE;YACF,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,SAAS;SAC5C;QACD,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,UAAU,EAAE,KAAK,CAAC,UAAU;KAC7B,CAAC,CAAC,CACJ,CAAC;IACF,MAAM,MAAM,GAA2B;QACrC,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC,6BAA6B,CAAC,CAAC,QAAQ,CAAC,EAAE,OAAO;YAChE,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,WAAW,CAAC;YACjC,OAAO,KAAK,CAAC,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACpF,CAAC,CAAC;QACF,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,8BAA8B,CAAC,CAAC,QAAQ,CAAC,EAAE,OAAO;YAClE,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,WAAW,CAAC;YACjC,OAAO,KAAK,CAAC,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACrF,CAAC,CAAC;KACH,CAAC;IACF,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC,CACH,CAAC"}
|
package/lib/Pki.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keys, PKCS#10 certificate requests and X.509 parsing for the ACME flow.
|
|
3
|
+
* WebCrypto plus the tiny DER codec in `Der.ts` — no native code, so the
|
|
4
|
+
* same code runs at deploy time and inside a Worker or Fly Service.
|
|
5
|
+
*/
|
|
6
|
+
import * as Effect from "effect/Effect";
|
|
7
|
+
import * as Redacted from "effect/Redacted";
|
|
8
|
+
import { PkiError } from "./Errors.ts";
|
|
9
|
+
export type KeyAlgorithm = "ES256" | "RS256";
|
|
10
|
+
/** The DER bytes of the first (or `index`-th) PEM block in `pem`. */
|
|
11
|
+
export declare const fromPem: (pem: string, index?: number) => Uint8Array;
|
|
12
|
+
/** Every PEM block in a chain, leaf first. */
|
|
13
|
+
export declare const splitPemChain: (pem: string) => string[];
|
|
14
|
+
export interface GeneratedKey {
|
|
15
|
+
readonly algorithm: KeyAlgorithm;
|
|
16
|
+
/** PKCS#8 PEM. */
|
|
17
|
+
readonly privateKeyPem: Redacted.Redacted<string>;
|
|
18
|
+
readonly privateKey: CryptoKey;
|
|
19
|
+
/** SubjectPublicKeyInfo DER. */
|
|
20
|
+
readonly spki: Uint8Array;
|
|
21
|
+
}
|
|
22
|
+
/** Generate a certificate key pair (ES256 P-256 by default). */
|
|
23
|
+
export declare const generateKey: (algorithm?: KeyAlgorithm) => Effect.Effect<GeneratedKey, PkiError>;
|
|
24
|
+
/** Import a PKCS#8 PEM private key (ES256 or RS256, detected from the DER). */
|
|
25
|
+
export declare const importPrivateKey: (pem: Redacted.Redacted<string> | string) => Effect.Effect<{
|
|
26
|
+
readonly key: CryptoKey;
|
|
27
|
+
readonly algorithm: KeyAlgorithm;
|
|
28
|
+
}, PkiError>;
|
|
29
|
+
/** The private JWK of a PKCS#8 PEM key (for revocation signed by the certificate key). */
|
|
30
|
+
export declare const privateKeyToJwk: (pem: Redacted.Redacted<string> | string) => Effect.Effect<Redacted.Redacted<string>, PkiError>;
|
|
31
|
+
/**
|
|
32
|
+
* A PKCS#10 certificate request for `identifiers` signed by `key`: the
|
|
33
|
+
* first identifier is the subject CN, all of them are `subjectAltName`
|
|
34
|
+
* dNSName entries. Returned as DER.
|
|
35
|
+
*/
|
|
36
|
+
export declare const createCsr: (options: {
|
|
37
|
+
readonly key: GeneratedKey;
|
|
38
|
+
readonly identifiers: ReadonlyArray<string>;
|
|
39
|
+
}) => Effect.Effect<Uint8Array, PkiError>;
|
|
40
|
+
/** base64url of a DER CSR, as ACME's `finalize` expects. */
|
|
41
|
+
export declare const csrToBase64Url: (der: Uint8Array) => string;
|
|
42
|
+
export interface ParsedCertificate {
|
|
43
|
+
/** Serial number as lowercase hex. */
|
|
44
|
+
readonly serial: string;
|
|
45
|
+
readonly notBefore: Date;
|
|
46
|
+
readonly notAfter: Date;
|
|
47
|
+
/** Issuer distinguished name, `CN` first (`CN=R11, O=Let's Encrypt`). */
|
|
48
|
+
readonly issuer: string;
|
|
49
|
+
/** Subject distinguished name in the same form. */
|
|
50
|
+
readonly subject: string;
|
|
51
|
+
/** `subjectAltName` dNSName entries. */
|
|
52
|
+
readonly dnsNames: ReadonlyArray<string>;
|
|
53
|
+
}
|
|
54
|
+
/** Parse the first certificate of a PEM (or a DER buffer). */
|
|
55
|
+
export declare const parseCertificate: (input: string | Uint8Array) => Effect.Effect<ParsedCertificate, PkiError>;
|
|
56
|
+
//# sourceMappingURL=Pki.d.ts.map
|
package/lib/Pki.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Pki.d.ts","sourceRoot":"","sources":["../src/Pki.ts"],"names":[],"mappings":"AACA;;;;GAIG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,OAAO,CAAC;AAmC7C,qEAAqE;AACrE,eAAO,MAAM,OAAO,QAAS,MAAM,qBAAc,UAchD,CAAC;AAEF,8CAA8C;AAC9C,eAAO,MAAM,aAAa,QAAS,MAAM,KAAG,MAAM,EACoB,CAAC;AAQvE,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC;IACjC,kBAAkB;IAClB,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAClD,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,gCAAgC;IAChC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;CAC3B;AAED,gEAAgE;AAChE,eAAO,MAAM,WAAW,eACX,YAAY,KACtB,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,QAAQ,CAWnC,CAAC;AAUL,+EAA+E;AAC/E,eAAO,MAAM,gBAAgB,QACtB,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,MAAM,KACtC,MAAM,CAAC,MAAM,CAAC;IAAE,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAA;CAAE,EAAE,QAAQ,CAapF,CAAC;AAEL,0FAA0F;AAC1F,eAAO,MAAM,eAAe,QACrB,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,MAAM,KACtC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAOjD,CAAC;AAQJ;;;;GAIG;AACH,eAAO,MAAM,SAAS,YAAa;IACjC,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAC7C,KAAG,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,QAAQ,CAmClC,CAAC;AAEL,4DAA4D;AAC5D,eAAO,MAAM,cAAc,QAAS,UAAU,KAAG,MAA6B,CAAC;AAM/E,MAAM,WAAW,iBAAiB;IAChC,sCAAsC;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC;IACxB,yEAAyE;IACzE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,mDAAmD;IACnD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,wCAAwC;IACxC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAC1C;AAyBD,8DAA8D;AAC9D,eAAO,MAAM,gBAAgB,UACpB,MAAM,GAAG,UAAU,KACzB,MAAM,CAAC,MAAM,CAAC,iBAAiB,EAAE,QAAQ,CAyCxC,CAAC"}
|