@push.rocks/smartacme 9.1.3 → 9.2.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_ts/00_commitinfo_data.js +2 -2
- package/dist_ts/acme/acme.classes.account.js +1 -1
- package/dist_ts/acme/acme.classes.challenge.js +1 -1
- package/dist_ts/acme/acme.classes.client.js +1 -1
- package/dist_ts/acme/acme.classes.crypto.d.ts +1 -1
- package/dist_ts/acme/acme.classes.crypto.js +1 -1
- package/dist_ts/acme/acme.classes.directory.js +1 -1
- package/dist_ts/acme/acme.classes.error.js +1 -1
- package/dist_ts/acme/acme.classes.http-client.js +1 -1
- package/dist_ts/acme/acme.classes.order.js +1 -1
- package/dist_ts/acme/acme.interfaces.js +1 -1
- package/dist_ts/acme/index.js +1 -1
- package/dist_ts/certmanagers/index.js +1 -1
- package/dist_ts/certmanagers/memory.js +1 -1
- package/dist_ts/certmanagers/mongo.js +1 -1
- package/dist_ts/handlers/Dns01Handler.js +1 -1
- package/dist_ts/handlers/Http01Handler.js +1 -1
- package/dist_ts/handlers/Http01MemoryHandler.js +1 -1
- package/dist_ts/handlers/IChallengeHandler.js +1 -1
- package/dist_ts/handlers/index.js +1 -1
- package/dist_ts/index.d.ts +2 -0
- package/dist_ts/index.js +4 -1
- package/dist_ts/interfaces/accountdata.js +1 -1
- package/dist_ts/interfaces/certmanager.js +1 -1
- package/dist_ts/interfaces/index.js +1 -1
- package/dist_ts/plugins.js +1 -1
- package/dist_ts/smartacme.classes.cert.js +1 -1
- package/dist_ts/smartacme.classes.certmatcher.js +1 -1
- package/dist_ts/smartacme.classes.smartacme.js +1 -1
- package/dist_ts_server/index.d.ts +4 -0
- package/dist_ts_server/index.js +4 -0
- package/dist_ts_server/server.classes.account.store.d.ts +12 -0
- package/dist_ts_server/server.classes.account.store.js +25 -0
- package/dist_ts_server/server.classes.acmeserver.d.ts +22 -0
- package/dist_ts_server/server.classes.acmeserver.js +100 -0
- package/dist_ts_server/server.classes.ca.d.ts +25 -0
- package/dist_ts_server/server.classes.ca.js +109 -0
- package/dist_ts_server/server.classes.challenge.verifier.d.ts +16 -0
- package/dist_ts_server/server.classes.challenge.verifier.js +56 -0
- package/dist_ts_server/server.classes.jws.verifier.d.ts +31 -0
- package/dist_ts_server/server.classes.jws.verifier.js +116 -0
- package/dist_ts_server/server.classes.nonce.d.ts +12 -0
- package/dist_ts_server/server.classes.nonce.js +32 -0
- package/dist_ts_server/server.classes.order.store.d.ts +21 -0
- package/dist_ts_server/server.classes.order.store.js +57 -0
- package/dist_ts_server/server.classes.router.d.ts +17 -0
- package/dist_ts_server/server.classes.router.js +99 -0
- package/dist_ts_server/server.handlers.account.d.ts +8 -0
- package/dist_ts_server/server.handlers.account.js +59 -0
- package/dist_ts_server/server.handlers.authz.d.ts +7 -0
- package/dist_ts_server/server.handlers.authz.js +41 -0
- package/dist_ts_server/server.handlers.cert.d.ts +7 -0
- package/dist_ts_server/server.handlers.cert.js +18 -0
- package/dist_ts_server/server.handlers.challenge.d.ts +10 -0
- package/dist_ts_server/server.handlers.challenge.js +110 -0
- package/dist_ts_server/server.handlers.directory.d.ts +5 -0
- package/dist_ts_server/server.handlers.directory.js +23 -0
- package/dist_ts_server/server.handlers.finalize.d.ts +8 -0
- package/dist_ts_server/server.handlers.finalize.js +65 -0
- package/dist_ts_server/server.handlers.nonce.d.ts +7 -0
- package/dist_ts_server/server.handlers.nonce.js +17 -0
- package/dist_ts_server/server.handlers.order.d.ts +11 -0
- package/dist_ts_server/server.handlers.order.js +131 -0
- package/dist_ts_server/server.interfaces.d.ts +72 -0
- package/dist_ts_server/server.interfaces.js +2 -0
- package/package.json +11 -11
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/acme/acme.classes.crypto.ts +1 -1
- package/ts/index.ts +4 -0
- package/ts_server/index.ts +12 -0
- package/ts_server/server.classes.account.store.ts +27 -0
- package/ts_server/server.classes.acmeserver.ts +128 -0
- package/ts_server/server.classes.ca.ts +142 -0
- package/ts_server/server.classes.challenge.verifier.ts +61 -0
- package/ts_server/server.classes.jws.verifier.ts +153 -0
- package/ts_server/server.classes.nonce.ts +36 -0
- package/ts_server/server.classes.order.store.ts +72 -0
- package/ts_server/server.classes.router.ts +116 -0
- package/ts_server/server.handlers.account.ts +85 -0
- package/ts_server/server.handlers.authz.ts +58 -0
- package/ts_server/server.handlers.cert.ts +32 -0
- package/ts_server/server.handlers.challenge.ts +142 -0
- package/ts_server/server.handlers.directory.ts +30 -0
- package/ts_server/server.handlers.finalize.ts +93 -0
- package/ts_server/server.handlers.nonce.ts +29 -0
- package/ts_server/server.handlers.order.ts +177 -0
- package/ts_server/server.interfaces.ts +98 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type * as http from 'node:http';
|
|
2
|
+
import type { IAcmeDirectory } from '../ts/acme/acme.interfaces.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* GET /directory — Returns the ACME directory object with all endpoint URLs.
|
|
6
|
+
*/
|
|
7
|
+
export function createDirectoryHandler(baseUrl: string) {
|
|
8
|
+
return async (
|
|
9
|
+
_req: http.IncomingMessage,
|
|
10
|
+
res: http.ServerResponse,
|
|
11
|
+
_params: Record<string, string>,
|
|
12
|
+
_body: any,
|
|
13
|
+
): Promise<void> => {
|
|
14
|
+
const directory: IAcmeDirectory = {
|
|
15
|
+
newNonce: `${baseUrl}/new-nonce`,
|
|
16
|
+
newAccount: `${baseUrl}/new-account`,
|
|
17
|
+
newOrder: `${baseUrl}/new-order`,
|
|
18
|
+
revokeCert: `${baseUrl}/revoke-cert`,
|
|
19
|
+
keyChange: `${baseUrl}/key-change`,
|
|
20
|
+
meta: {
|
|
21
|
+
termsOfService: `${baseUrl}/terms`,
|
|
22
|
+
website: `${baseUrl}`,
|
|
23
|
+
caaIdentities: [],
|
|
24
|
+
externalAccountRequired: false,
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
28
|
+
res.end(JSON.stringify(directory));
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type * as http from 'node:http';
|
|
2
|
+
import type { JwsVerifier } from './server.classes.jws.verifier.js';
|
|
3
|
+
import { AcmeServerError } from './server.classes.jws.verifier.js';
|
|
4
|
+
import type { IServerOrderStore } from './server.interfaces.js';
|
|
5
|
+
import type { AcmeServerCA } from './server.classes.ca.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* POST /finalize/:id — Submit CSR and issue certificate.
|
|
9
|
+
*/
|
|
10
|
+
export function createFinalizeHandler(
|
|
11
|
+
baseUrl: string,
|
|
12
|
+
jwsVerifier: JwsVerifier,
|
|
13
|
+
orderStore: IServerOrderStore,
|
|
14
|
+
ca: AcmeServerCA,
|
|
15
|
+
) {
|
|
16
|
+
return async (
|
|
17
|
+
req: http.IncomingMessage,
|
|
18
|
+
res: http.ServerResponse,
|
|
19
|
+
params: Record<string, string>,
|
|
20
|
+
body: any,
|
|
21
|
+
): Promise<void> => {
|
|
22
|
+
const orderId = params.id;
|
|
23
|
+
const requestUrl = `${baseUrl}/finalize/${orderId}`;
|
|
24
|
+
const verified = await jwsVerifier.verify(body, requestUrl);
|
|
25
|
+
|
|
26
|
+
if (!verified.kid) {
|
|
27
|
+
throw new AcmeServerError(400, 'urn:ietf:params:acme:error:malformed', 'Finalize requires kid');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const order = await orderStore.getOrder(orderId);
|
|
31
|
+
if (!order) {
|
|
32
|
+
throw new AcmeServerError(404, 'urn:ietf:params:acme:error:malformed', 'Order not found');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Check all authorizations are valid and update order status if needed
|
|
36
|
+
if (order.status === 'pending') {
|
|
37
|
+
let allValid = true;
|
|
38
|
+
for (const authzId of order.authorizationIds) {
|
|
39
|
+
const authz = await orderStore.getAuthorization(authzId);
|
|
40
|
+
if (!authz || authz.status !== 'valid') {
|
|
41
|
+
allValid = false;
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (allValid) {
|
|
46
|
+
await orderStore.updateOrder(orderId, { status: 'ready' });
|
|
47
|
+
order.status = 'ready';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (order.status !== 'ready') {
|
|
52
|
+
throw new AcmeServerError(
|
|
53
|
+
403,
|
|
54
|
+
'urn:ietf:params:acme:error:orderNotReady',
|
|
55
|
+
`Order is in "${order.status}" state, expected "ready"`,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const { payload } = verified;
|
|
60
|
+
if (!payload?.csr) {
|
|
61
|
+
throw new AcmeServerError(400, 'urn:ietf:params:acme:error:malformed', 'Missing CSR in finalize request');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Transition to processing
|
|
65
|
+
await orderStore.updateOrder(orderId, { status: 'processing' });
|
|
66
|
+
|
|
67
|
+
// Sign the certificate
|
|
68
|
+
const certPem = await ca.signCsr(payload.csr);
|
|
69
|
+
|
|
70
|
+
// Store certificate and update order
|
|
71
|
+
const certUrl = `${baseUrl}/cert/${orderId}`;
|
|
72
|
+
await orderStore.storeCertPem(orderId, certPem);
|
|
73
|
+
await orderStore.updateOrder(orderId, {
|
|
74
|
+
status: 'valid',
|
|
75
|
+
certificate: certUrl,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const responseBody = {
|
|
79
|
+
status: 'valid',
|
|
80
|
+
expires: order.expires,
|
|
81
|
+
identifiers: order.identifiers,
|
|
82
|
+
authorizations: order.authorizationIds.map((id) => `${baseUrl}/authz/${id}`),
|
|
83
|
+
finalize: order.finalize,
|
|
84
|
+
certificate: certUrl,
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
res.writeHead(200, {
|
|
88
|
+
'Content-Type': 'application/json',
|
|
89
|
+
'Location': `${baseUrl}/order/${orderId}`,
|
|
90
|
+
});
|
|
91
|
+
res.end(JSON.stringify(responseBody));
|
|
92
|
+
};
|
|
93
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type * as http from 'node:http';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* HEAD /new-nonce — Returns 200 with Replay-Nonce header (added by router).
|
|
5
|
+
* GET /new-nonce — Returns 204 with Replay-Nonce header (added by router).
|
|
6
|
+
*/
|
|
7
|
+
export function createNonceHeadHandler() {
|
|
8
|
+
return async (
|
|
9
|
+
_req: http.IncomingMessage,
|
|
10
|
+
res: http.ServerResponse,
|
|
11
|
+
_params: Record<string, string>,
|
|
12
|
+
_body: any,
|
|
13
|
+
): Promise<void> => {
|
|
14
|
+
res.writeHead(200, { 'Content-Type': 'application/octet-stream' });
|
|
15
|
+
res.end();
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function createNonceGetHandler() {
|
|
20
|
+
return async (
|
|
21
|
+
_req: http.IncomingMessage,
|
|
22
|
+
res: http.ServerResponse,
|
|
23
|
+
_params: Record<string, string>,
|
|
24
|
+
_body: any,
|
|
25
|
+
): Promise<void> => {
|
|
26
|
+
res.writeHead(204);
|
|
27
|
+
res.end();
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import type * as http from 'node:http';
|
|
2
|
+
import * as crypto from 'node:crypto';
|
|
3
|
+
import type { JwsVerifier } from './server.classes.jws.verifier.js';
|
|
4
|
+
import { AcmeServerError } from './server.classes.jws.verifier.js';
|
|
5
|
+
import type { IServerOrderStore, IServerAccountStore } from './server.interfaces.js';
|
|
6
|
+
import type { IAcmeIdentifier } from '../ts/acme/acme.interfaces.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* POST /new-order — Create a new ACME order.
|
|
10
|
+
*/
|
|
11
|
+
export function createNewOrderHandler(
|
|
12
|
+
baseUrl: string,
|
|
13
|
+
jwsVerifier: JwsVerifier,
|
|
14
|
+
orderStore: IServerOrderStore,
|
|
15
|
+
) {
|
|
16
|
+
return async (
|
|
17
|
+
req: http.IncomingMessage,
|
|
18
|
+
res: http.ServerResponse,
|
|
19
|
+
_params: Record<string, string>,
|
|
20
|
+
body: any,
|
|
21
|
+
): Promise<void> => {
|
|
22
|
+
const requestUrl = `${baseUrl}/new-order`;
|
|
23
|
+
const verified = await jwsVerifier.verify(body, requestUrl);
|
|
24
|
+
|
|
25
|
+
if (!verified.kid) {
|
|
26
|
+
throw new AcmeServerError(400, 'urn:ietf:params:acme:error:malformed', 'newOrder requires kid');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const { payload } = verified;
|
|
30
|
+
const identifiers: IAcmeIdentifier[] = payload?.identifiers;
|
|
31
|
+
|
|
32
|
+
if (!identifiers || !Array.isArray(identifiers) || identifiers.length === 0) {
|
|
33
|
+
throw new AcmeServerError(
|
|
34
|
+
400,
|
|
35
|
+
'urn:ietf:params:acme:error:malformed',
|
|
36
|
+
'Order must include at least one identifier',
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const orderId = crypto.randomBytes(16).toString('hex');
|
|
41
|
+
const expires = new Date();
|
|
42
|
+
expires.setDate(expires.getDate() + 7);
|
|
43
|
+
|
|
44
|
+
// Create authorizations and challenges for each identifier
|
|
45
|
+
const authorizationIds: string[] = [];
|
|
46
|
+
|
|
47
|
+
for (const identifier of identifiers) {
|
|
48
|
+
const authzId = crypto.randomBytes(16).toString('hex');
|
|
49
|
+
const isWildcard = identifier.value.startsWith('*.');
|
|
50
|
+
const domain = isWildcard ? identifier.value.slice(2) : identifier.value;
|
|
51
|
+
|
|
52
|
+
// Create challenges for this authorization
|
|
53
|
+
const challengeIds: string[] = [];
|
|
54
|
+
|
|
55
|
+
// HTTP-01 challenge (not for wildcards)
|
|
56
|
+
if (!isWildcard) {
|
|
57
|
+
const http01Id = crypto.randomBytes(16).toString('hex');
|
|
58
|
+
const http01Token = crypto.randomBytes(32).toString('base64url');
|
|
59
|
+
await orderStore.createChallenge({
|
|
60
|
+
id: http01Id,
|
|
61
|
+
authorizationId: authzId,
|
|
62
|
+
type: 'http-01',
|
|
63
|
+
token: http01Token,
|
|
64
|
+
status: 'pending',
|
|
65
|
+
});
|
|
66
|
+
challengeIds.push(http01Id);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// DNS-01 challenge (always)
|
|
70
|
+
const dns01Id = crypto.randomBytes(16).toString('hex');
|
|
71
|
+
const dns01Token = crypto.randomBytes(32).toString('base64url');
|
|
72
|
+
await orderStore.createChallenge({
|
|
73
|
+
id: dns01Id,
|
|
74
|
+
authorizationId: authzId,
|
|
75
|
+
type: 'dns-01',
|
|
76
|
+
token: dns01Token,
|
|
77
|
+
status: 'pending',
|
|
78
|
+
});
|
|
79
|
+
challengeIds.push(dns01Id);
|
|
80
|
+
|
|
81
|
+
await orderStore.createAuthorization({
|
|
82
|
+
id: authzId,
|
|
83
|
+
orderId,
|
|
84
|
+
identifier: { type: 'dns', value: domain },
|
|
85
|
+
status: 'pending',
|
|
86
|
+
expires: expires.toISOString(),
|
|
87
|
+
challengeIds,
|
|
88
|
+
wildcard: isWildcard || undefined,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
authorizationIds.push(authzId);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const order = await orderStore.createOrder({
|
|
95
|
+
id: orderId,
|
|
96
|
+
accountUrl: verified.kid,
|
|
97
|
+
status: 'pending',
|
|
98
|
+
identifiers,
|
|
99
|
+
authorizationIds,
|
|
100
|
+
expires: expires.toISOString(),
|
|
101
|
+
finalize: `${baseUrl}/finalize/${orderId}`,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const responseBody = {
|
|
105
|
+
status: order.status,
|
|
106
|
+
expires: order.expires,
|
|
107
|
+
identifiers: order.identifiers,
|
|
108
|
+
authorizations: order.authorizationIds.map((id) => `${baseUrl}/authz/${id}`),
|
|
109
|
+
finalize: order.finalize,
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
res.writeHead(201, {
|
|
113
|
+
'Content-Type': 'application/json',
|
|
114
|
+
'Location': `${baseUrl}/order/${orderId}`,
|
|
115
|
+
});
|
|
116
|
+
res.end(JSON.stringify(responseBody));
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* POST /order/:id — Poll order status (POST-as-GET).
|
|
122
|
+
*/
|
|
123
|
+
export function createOrderPollHandler(
|
|
124
|
+
baseUrl: string,
|
|
125
|
+
jwsVerifier: JwsVerifier,
|
|
126
|
+
orderStore: IServerOrderStore,
|
|
127
|
+
) {
|
|
128
|
+
return async (
|
|
129
|
+
req: http.IncomingMessage,
|
|
130
|
+
res: http.ServerResponse,
|
|
131
|
+
params: Record<string, string>,
|
|
132
|
+
body: any,
|
|
133
|
+
): Promise<void> => {
|
|
134
|
+
const orderId = params.id;
|
|
135
|
+
const requestUrl = `${baseUrl}/order/${orderId}`;
|
|
136
|
+
await jwsVerifier.verify(body, requestUrl);
|
|
137
|
+
|
|
138
|
+
const order = await orderStore.getOrder(orderId);
|
|
139
|
+
if (!order) {
|
|
140
|
+
throw new AcmeServerError(404, 'urn:ietf:params:acme:error:malformed', 'Order not found');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Check if all authorizations are valid → transition to ready
|
|
144
|
+
if (order.status === 'pending') {
|
|
145
|
+
let allValid = true;
|
|
146
|
+
for (const authzId of order.authorizationIds) {
|
|
147
|
+
const authz = await orderStore.getAuthorization(authzId);
|
|
148
|
+
if (!authz || authz.status !== 'valid') {
|
|
149
|
+
allValid = false;
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (allValid) {
|
|
154
|
+
await orderStore.updateOrder(orderId, { status: 'ready' });
|
|
155
|
+
order.status = 'ready';
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const responseBody: Record<string, any> = {
|
|
160
|
+
status: order.status,
|
|
161
|
+
expires: order.expires,
|
|
162
|
+
identifiers: order.identifiers,
|
|
163
|
+
authorizations: order.authorizationIds.map((id) => `${baseUrl}/authz/${id}`),
|
|
164
|
+
finalize: order.finalize,
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
if (order.certificate) {
|
|
168
|
+
responseBody.certificate = order.certificate;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
res.writeHead(200, {
|
|
172
|
+
'Content-Type': 'application/json',
|
|
173
|
+
'Location': requestUrl,
|
|
174
|
+
});
|
|
175
|
+
res.end(JSON.stringify(responseBody));
|
|
176
|
+
};
|
|
177
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { IAcmeIdentifier } from '../ts/acme/acme.interfaces.js';
|
|
2
|
+
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// Server configuration
|
|
5
|
+
// ============================================================================
|
|
6
|
+
|
|
7
|
+
export interface IAcmeServerOptions {
|
|
8
|
+
port?: number;
|
|
9
|
+
hostname?: string;
|
|
10
|
+
baseUrl?: string;
|
|
11
|
+
/** When false, challenges auto-approve on trigger (useful for testing) */
|
|
12
|
+
challengeVerification?: boolean;
|
|
13
|
+
caOptions?: {
|
|
14
|
+
commonName?: string;
|
|
15
|
+
validityDays?: number;
|
|
16
|
+
certValidityDays?: number;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// Pluggable storage interfaces
|
|
22
|
+
// ============================================================================
|
|
23
|
+
|
|
24
|
+
export interface IServerAccountStore {
|
|
25
|
+
create(account: IServerAccount): Promise<IServerAccount>;
|
|
26
|
+
getByThumbprint(thumbprint: string): Promise<IServerAccount | null>;
|
|
27
|
+
getByUrl(url: string): Promise<IServerAccount | null>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface IServerOrderStore {
|
|
31
|
+
createOrder(order: IServerOrder): Promise<IServerOrder>;
|
|
32
|
+
getOrder(id: string): Promise<IServerOrder | null>;
|
|
33
|
+
updateOrder(id: string, updates: Partial<IServerOrder>): Promise<void>;
|
|
34
|
+
createAuthorization(authz: IServerAuthorization): Promise<IServerAuthorization>;
|
|
35
|
+
getAuthorization(id: string): Promise<IServerAuthorization | null>;
|
|
36
|
+
updateAuthorization(id: string, updates: Partial<IServerAuthorization>): Promise<void>;
|
|
37
|
+
createChallenge(challenge: IServerChallenge): Promise<IServerChallenge>;
|
|
38
|
+
getChallenge(id: string): Promise<IServerChallenge | null>;
|
|
39
|
+
updateChallenge(id: string, updates: Partial<IServerChallenge>): Promise<void>;
|
|
40
|
+
storeCertPem(orderId: string, pem: string): Promise<void>;
|
|
41
|
+
getCertPem(orderId: string): Promise<string | null>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ============================================================================
|
|
45
|
+
// Internal server models
|
|
46
|
+
// ============================================================================
|
|
47
|
+
|
|
48
|
+
export interface IServerAccount {
|
|
49
|
+
id: string;
|
|
50
|
+
thumbprint: string;
|
|
51
|
+
url: string;
|
|
52
|
+
jwk: Record<string, string>;
|
|
53
|
+
status: string;
|
|
54
|
+
contact: string[];
|
|
55
|
+
createdAt: string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface IServerOrder {
|
|
59
|
+
id: string;
|
|
60
|
+
accountUrl: string;
|
|
61
|
+
status: string;
|
|
62
|
+
identifiers: IAcmeIdentifier[];
|
|
63
|
+
authorizationIds: string[];
|
|
64
|
+
expires: string;
|
|
65
|
+
finalize: string;
|
|
66
|
+
certificate?: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface IServerAuthorization {
|
|
70
|
+
id: string;
|
|
71
|
+
orderId: string;
|
|
72
|
+
identifier: IAcmeIdentifier;
|
|
73
|
+
status: string;
|
|
74
|
+
expires: string;
|
|
75
|
+
challengeIds: string[];
|
|
76
|
+
wildcard?: boolean;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface IServerChallenge {
|
|
80
|
+
id: string;
|
|
81
|
+
authorizationId: string;
|
|
82
|
+
type: string;
|
|
83
|
+
token: string;
|
|
84
|
+
status: string;
|
|
85
|
+
validated?: string;
|
|
86
|
+
error?: { type: string; detail: string };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ============================================================================
|
|
90
|
+
// Route handler type
|
|
91
|
+
// ============================================================================
|
|
92
|
+
|
|
93
|
+
export type TRouteHandler = (
|
|
94
|
+
req: import('node:http').IncomingMessage,
|
|
95
|
+
res: import('node:http').ServerResponse,
|
|
96
|
+
params: Record<string, string>,
|
|
97
|
+
body: any,
|
|
98
|
+
) => Promise<void>;
|