diff --git a/packages/core/acme-client/.eslintrc b/packages/core/acme-client/.eslintrc index dc2d3f80d..ea5983458 100644 --- a/packages/core/acme-client/.eslintrc +++ b/packages/core/acme-client/.eslintrc @@ -1,4 +1,13 @@ { + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 2022, + "sourceType": "module" + }, + "ignorePatterns": [ + "dist", + "node_modules" + ], "extends": [ "plugin:prettier/recommended", "prettier" @@ -7,9 +16,12 @@ "eslint-plugin-import" ], "env": { + "node": true, + "es2022": true, "mocha": true }, "rules": { + "prettier/prettier": "off", "@typescript-eslint/no-var-requires": "off", "@typescript-eslint/ban-ts-comment": "off", "@typescript-eslint/ban-ts-ignore": "off", diff --git a/packages/core/acme-client/.gitignore b/packages/core/acme-client/.gitignore index 880dfa8e8..0956ae15d 100644 --- a/packages/core/acme-client/.gitignore +++ b/packages/core/acme-client/.gitignore @@ -4,3 +4,8 @@ node_modules/ npm-debug.log package-lock.json /.idea/ +/dist/ +/dist-test/ +/logs/ +/tsconfig.tsbuildinfo +/tsconfig.test.tsbuildinfo diff --git a/packages/core/acme-client/package.json b/packages/core/acme-client/package.json index 4eddf5437..30345c6e2 100644 --- a/packages/core/acme-client/package.json +++ b/packages/core/acme-client/package.json @@ -5,16 +5,16 @@ "author": "nmorsman", "version": "1.39.12", "type": "module", - "module": "scr/index.js", - "main": "src/index.js", - "types": "types/index.d.ts", + "module": "./dist/index.js", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "license": "MIT", "homepage": "https://github.com/publishlab/node-acme-client", "engines": { "node": ">= 18" }, "files": [ - "src", + "dist", "types" ], "dependencies": { @@ -47,14 +47,17 @@ "typescript": "^5.4.2" }, "scripts": { - "build-docs": "jsdoc2md src/client.js > docs/client.md && jsdoc2md src/crypto/index.js > docs/crypto.md && jsdoc2md src/crypto/forge.js > docs/forge.md", - "lint": "eslint .", - "lint-types": "tsd", - "prepublishOnly": "npm run build-docs", + "before-build": "node -e \"const fs=require('fs');fs.rmSync('dist',{recursive:true,force:true});fs.rmSync('tsconfig.tsbuildinfo',{force:true});\"", + "build": "npm run before-build && tsc --skipLibCheck", + "build-docs": "jsdoc2md dist/client.js > docs/client.md && jsdoc2md dist/crypto/index.js > docs/crypto.md && jsdoc2md dist/crypto/forge.js > docs/forge.md", + "lint": "eslint \"src/**/*.ts\" \"types/**/*.ts\"", + "lint-types": "tsd --files \"types/index.test-d.ts\"", + "prepublishOnly": "npm run build && npm run build-docs", "test": "mocha -t 60000 \"test/setup.js\" \"test/**/*.spec.js\"", - "test:unit": "echo no unit tests", + "before-test:unit": "node -e \"const fs=require('fs');fs.rmSync('dist-test',{recursive:true,force:true});fs.rmSync('tsconfig.test.tsbuildinfo',{force:true});\"", + "test:unit": "npm run before-test:unit && tsc -p tsconfig.test.json --skipLibCheck && mocha -t 60000 \"dist-test/**/*.test.js\"", "pub": "npm publish", - "compile": "echo '1'" + "compile": "tsc --skipLibCheck --watch" }, "repository": { "type": "git", diff --git a/packages/core/acme-client/src/api.js b/packages/core/acme-client/src/api.ts similarity index 99% rename from packages/core/acme-client/src/api.js rename to packages/core/acme-client/src/api.ts index b7e270372..74f3d5d94 100644 --- a/packages/core/acme-client/src/api.js +++ b/packages/core/acme-client/src/api.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * ACME API client */ diff --git a/packages/core/acme-client/src/auto.js b/packages/core/acme-client/src/auto.ts similarity index 99% rename from packages/core/acme-client/src/auto.js rename to packages/core/acme-client/src/auto.ts index 03030c703..47955e418 100644 --- a/packages/core/acme-client/src/auto.js +++ b/packages/core/acme-client/src/auto.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * ACME auto helper */ diff --git a/packages/core/acme-client/src/axios.js b/packages/core/acme-client/src/axios.ts similarity index 99% rename from packages/core/acme-client/src/axios.js rename to packages/core/acme-client/src/axios.ts index 48ce623ce..df67ed4e1 100644 --- a/packages/core/acme-client/src/axios.js +++ b/packages/core/acme-client/src/axios.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Axios instance */ diff --git a/packages/core/acme-client/src/client.js b/packages/core/acme-client/src/client.ts similarity index 99% rename from packages/core/acme-client/src/client.js rename to packages/core/acme-client/src/client.ts index 4efe793be..76eadbf97 100644 --- a/packages/core/acme-client/src/client.js +++ b/packages/core/acme-client/src/client.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * ACME client * @@ -570,7 +571,7 @@ class AcmeClient { * ``` */ - async waitForValidStatus(item,d) { + async waitForValidStatus(item, d?) { if (!item.url) { throw new Error(`[${d}] Unable to verify status of item, URL not found`); } diff --git a/packages/core/acme-client/src/crypto/forge.js b/packages/core/acme-client/src/crypto/forge.ts similarity index 97% rename from packages/core/acme-client/src/crypto/forge.js rename to packages/core/acme-client/src/crypto/forge.ts index 2203ebc81..9d9e31c4d 100644 --- a/packages/core/acme-client/src/crypto/forge.js +++ b/packages/core/acme-client/src/crypto/forge.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Legacy node-forge crypto interface * @@ -112,7 +113,7 @@ function parseDomains(obj) { * ``` */ -export async function createPrivateKey(size = 2048) { +export async function createPrivateKey(size = 2048): Promise { const keyPair = await generateKeyPair({ bits: size }); const pemKey = forge.pki.privateKeyToPem(keyPair.privateKey); return Buffer.from(pemKey); @@ -131,7 +132,7 @@ export async function createPrivateKey(size = 2048) { * ``` */ -export const createPublicKey = async (key) => { +export const createPublicKey = async (key): Promise => { const privateKey = forge.pki.privateKeyFromPem(key); const publicKey = forge.pki.rsa.setPublicKey(privateKey.n, privateKey.e); const pemKey = forge.pki.publicKeyToPem(publicKey); @@ -174,7 +175,7 @@ export const splitPemChain = (str) => forge.pem.decode(str).map(forge.pem.encode * ``` */ -export const getModulus = async (input) => { +export const getModulus = async (input): Promise => { if (!Buffer.isBuffer(input)) { input = Buffer.from(input); } @@ -197,7 +198,7 @@ export const getModulus = async (input) => { * ``` */ -export const getPublicExponent = async (input) => { +export const getPublicExponent = async (input): Promise => { if (!Buffer.isBuffer(input)) { input = Buffer.from(input); } diff --git a/packages/core/acme-client/src/crypto/index.js b/packages/core/acme-client/src/crypto/index.ts similarity index 99% rename from packages/core/acme-client/src/crypto/index.js rename to packages/core/acme-client/src/crypto/index.ts index a8b208b5e..7cda00eae 100644 --- a/packages/core/acme-client/src/crypto/index.js +++ b/packages/core/acme-client/src/crypto/index.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Native Node.js crypto interface * @@ -67,7 +68,7 @@ function getKeyInfo(keyPem) { * ``` */ -export async function createPrivateRsaKey(modulusLength = 2048, encodingType = 'pkcs8') { +export async function createPrivateRsaKey(modulusLength = 2048, encodingType = 'pkcs8'): Promise { const pair = await generateKeyPair('rsa', { modulusLength, privateKeyEncoding: { @@ -105,7 +106,7 @@ export const createPrivateKey = createPrivateRsaKey; * ``` */ -export const createPrivateEcdsaKey = async (namedCurve = 'P-256', encodingType = 'pkcs8') => { +export const createPrivateEcdsaKey = async (namedCurve = 'P-256', encodingType = 'pkcs8'): Promise => { const pair = await generateKeyPair('ec', { namedCurve, privateKeyEncoding: { @@ -129,7 +130,7 @@ export const createPrivateEcdsaKey = async (namedCurve = 'P-256', encodingType = * ``` */ -export const getPublicKey = (keyPem) => { +export const getPublicKey = (keyPem): Buffer => { const info = getKeyInfo(keyPem); const publicKey = info.publicKey.export({ diff --git a/packages/core/acme-client/src/error.js b/packages/core/acme-client/src/error.ts similarity index 88% rename from packages/core/acme-client/src/error.js rename to packages/core/acme-client/src/error.ts index 2595aa058..7c9dab7b7 100644 --- a/packages/core/acme-client/src/error.js +++ b/packages/core/acme-client/src/error.ts @@ -1,3 +1,4 @@ +// @ts-nocheck export class CancelError extends Error { constructor(message) { super(message); diff --git a/packages/core/acme-client/src/http.js b/packages/core/acme-client/src/http.ts similarity index 99% rename from packages/core/acme-client/src/http.js rename to packages/core/acme-client/src/http.ts index 646692cac..400419029 100644 --- a/packages/core/acme-client/src/http.js +++ b/packages/core/acme-client/src/http.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * ACME HTTP client */ diff --git a/packages/core/acme-client/src/index.test.ts b/packages/core/acme-client/src/index.test.ts new file mode 100644 index 000000000..841a76938 --- /dev/null +++ b/packages/core/acme-client/src/index.test.ts @@ -0,0 +1,19 @@ +import assert from "node:assert/strict"; +import { directory, getAllSslProviderDomains, getDirectoryUrl } from "./index.js"; + +declare const describe: any; +declare const it: any; + +describe("directory helpers", () => { + it("selects the provider specific directory endpoint", () => { + assert.equal(getDirectoryUrl({ sslProvider: "sslcom", pkType: "ec" }), directory.sslcom.ec); + assert.equal(getDirectoryUrl({ sslProvider: "letsencrypt", pkType: "rsa" }), directory.letsencrypt.production); + }); + + it("includes configured provider domains", () => { + const domains = getAllSslProviderDomains(); + + assert.ok(domains.includes("acme.litessl.com")); + assert.ok(domains.includes("acme.ssl.com")); + }); +}); diff --git a/packages/core/acme-client/src/index.js b/packages/core/acme-client/src/index.ts similarity index 95% rename from packages/core/acme-client/src/index.js rename to packages/core/acme-client/src/index.ts index f777f88a2..88ffcdacd 100644 --- a/packages/core/acme-client/src/index.js +++ b/packages/core/acme-client/src/index.ts @@ -1,8 +1,9 @@ +// @ts-nocheck /** * acme-client */ -import AcmeClinet from './client.js' -export const Client = AcmeClinet +export { default as Client } from './client.js' +export type * from './types.js' /** * Directory URLs @@ -103,4 +104,4 @@ export * from './logger.js' export * from './verify.js' export * from './error.js' -export * from './util.js' \ No newline at end of file +export * from './util.js' diff --git a/packages/core/acme-client/src/logger.js b/packages/core/acme-client/src/logger.ts similarity index 95% rename from packages/core/acme-client/src/logger.js rename to packages/core/acme-client/src/logger.ts index c85e667cb..bc7fce101 100644 --- a/packages/core/acme-client/src/logger.js +++ b/packages/core/acme-client/src/logger.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * ACME logger */ diff --git a/packages/core/acme-client/src/rfc8555.ts b/packages/core/acme-client/src/rfc8555.ts new file mode 100644 index 000000000..675163445 --- /dev/null +++ b/packages/core/acme-client/src/rfc8555.ts @@ -0,0 +1,123 @@ +/** + * Account + * + * https://datatracker.ietf.org/doc/html/rfc8555#section-7.1.2 + * https://datatracker.ietf.org/doc/html/rfc8555#section-7.3 + * https://datatracker.ietf.org/doc/html/rfc8555#section-7.3.2 + */ + +export interface Account { + status: "valid" | "deactivated" | "revoked"; + orders: string; + contact?: string[]; + termsOfServiceAgreed?: boolean; + externalAccountBinding?: object; +} + +export interface AccountCreateRequest { + contact?: string[]; + termsOfServiceAgreed?: boolean; + onlyReturnExisting?: boolean; + externalAccountBinding?: object; +} + +export interface AccountUpdateRequest { + status?: string; + contact?: string[]; + termsOfServiceAgreed?: boolean; +} + +/** + * Order + * + * https://datatracker.ietf.org/doc/html/rfc8555#section-7.1.3 + * https://datatracker.ietf.org/doc/html/rfc8555#section-7.4 + */ + +export interface Order { + status: "pending" | "ready" | "processing" | "valid" | "invalid"; + identifiers: Identifier[]; + authorizations: string[]; + finalize: string; + expires?: string; + notBefore?: string; + notAfter?: string; + error?: object; + certificate?: string; +} + +export interface OrderCreateRequest { + identifiers: Identifier[]; + notBefore?: string; + notAfter?: string; +} + +/** + * Authorization + * + * https://datatracker.ietf.org/doc/html/rfc8555#section-7.1.4 + */ + +export interface Authorization { + identifier: Identifier; + status: "pending" | "valid" | "invalid" | "deactivated" | "expired" | "revoked"; + challenges: Challenge[]; + expires?: string; + wildcard?: boolean; +} + +export interface Identifier { + type: string; + value: string; +} + +/** + * Challenge + * + * https://datatracker.ietf.org/doc/html/rfc8555#section-8 + * https://datatracker.ietf.org/doc/html/rfc8555#section-8.3 + * https://datatracker.ietf.org/doc/html/rfc8555#section-8.4 + */ + +export interface ChallengeAbstract { + type: string; + url: string; + status: "pending" | "processing" | "valid" | "invalid"; + validated?: string; + error?: object; +} + +export interface HttpChallenge extends ChallengeAbstract { + type: "http-01"; + token: string; +} + +export interface DnsChallenge extends ChallengeAbstract { + type: "dns-01"; + token: string; +} + +export type Challenge = HttpChallenge | DnsChallenge; + +/** + * Certificate + * + * https://datatracker.ietf.org/doc/html/rfc8555#section-7.6 + */ + +export enum CertificateRevocationReason { + Unspecified = 0, + KeyCompromise = 1, + CACompromise = 2, + AffiliationChanged = 3, + Superseded = 4, + CessationOfOperation = 5, + CertificateHold = 6, + RemoveFromCRL = 8, + PrivilegeWithdrawn = 9, + AACompromise = 10, +} + +export interface CertificateRevocationRequest { + reason?: CertificateRevocationReason; +} diff --git a/packages/core/acme-client/src/types.ts b/packages/core/acme-client/src/types.ts new file mode 100644 index 000000000..8a46923da --- /dev/null +++ b/packages/core/acme-client/src/types.ts @@ -0,0 +1,131 @@ +import type * as rfc8555 from "./rfc8555.js"; +import type { Challenge } from "./rfc8555.js"; + +export type * from "./rfc8555.js"; + +export type PrivateKeyBuffer = Buffer; +export type PublicKeyBuffer = Buffer; +export type CertificateBuffer = Buffer; +export type CsrBuffer = Buffer; + +export type PrivateKeyString = string; +export type PublicKeyString = string; +export type CertificateString = string; +export type CsrString = string; + +export interface Order extends rfc8555.Order { + url: string; +} + +export interface Authorization extends rfc8555.Authorization { + url: string; +} + +export type UrlMapping = { + enabled: boolean; + mappings: Record; +}; + +export interface ClientExternalAccountBindingOptions { + kid: string; + hmacKey: string; +} + +export interface ClientOptions { + sslProvider: string; + directoryUrl: string; + accountKey: PrivateKeyBuffer | PrivateKeyString; + accountUrl?: string; + externalAccountBinding?: ClientExternalAccountBindingOptions; + backoffAttempts?: number; + backoffMin?: number; + backoffMax?: number; + urlMapping?: UrlMapping; + signal?: AbortSignal; + logger?: any; +} + +export interface ClientAutoOptions { + csr: CsrBuffer | CsrString; + challengeCreateFn: ( + authz: Authorization, + keyAuthorization: (challenge: Challenge) => Promise + ) => Promise<{ recordReq?: any; recordRes?: any; dnsProvider?: any; challenge: Challenge; keyAuthorization: string }>; + challengeRemoveFn: (authz: Authorization, challenge: Challenge, keyAuthorization: string, recordReq: any, recordRes: any, dnsProvider: any, httpUploader: any) => Promise; + email?: string; + termsOfServiceAgreed?: boolean; + skipChallengeVerification?: boolean; + challengePriority?: string[]; + preferredChain?: string; + signal?: AbortSignal; + profile?: string; + waitDnsDiffuseTime?: number; +} + +export interface CertificateDomains { + commonName: string; + altNames: string[]; +} + +export interface CertificateIssuer { + commonName: string; +} + +export interface CertificateInfo { + issuer: CertificateIssuer; + domains: CertificateDomains; + notAfter: Date; + notBefore: Date; +} + +export interface CsrOptions { + keySize?: number; + commonName?: string; + altNames?: string[]; + country?: string; + state?: string; + locality?: string; + organization?: string; + organizationUnit?: string; + emailAddress?: string; +} + +export interface RsaPublicJwk { + e: string; + kty: string; + n: string; +} + +export interface EcdsaPublicJwk { + crv: string; + kty: string; + x: string; + y: string; +} + +export interface CryptoInterface { + createPrivateKey(keySize?: number, encodingType?: string): Promise; + createPrivateRsaKey(keySize?: number, encodingType?: string): Promise; + createPrivateEcdsaKey(namedCurve?: "P-256" | "P-384" | "P-521", encodingType?: string): Promise; + getPublicKey(keyPem: PrivateKeyBuffer | PrivateKeyString | PublicKeyBuffer | PublicKeyString): PublicKeyBuffer; + getJwk(keyPem: PrivateKeyBuffer | PrivateKeyString | PublicKeyBuffer | PublicKeyString): RsaPublicJwk | EcdsaPublicJwk; + splitPemChain(chainPem: CertificateBuffer | CertificateString): string[]; + getPemBodyAsB64u(pem: CertificateBuffer | CertificateString): string; + readCsrDomains(csrPem: CsrBuffer | CsrString): CertificateDomains; + readCertificateInfo(certPem: CertificateBuffer | CertificateString): CertificateInfo; + createCsr(data: CsrOptions, keyPem?: PrivateKeyBuffer | PrivateKeyString, encodingType?: string): Promise<[PrivateKeyBuffer, CsrBuffer]>; + createAlpnCertificate(authz: Authorization, keyAuthorization: string, keyPem?: PrivateKeyBuffer | PrivateKeyString): Promise<[PrivateKeyBuffer, CertificateBuffer]>; + isAlpnCertificateAuthorizationValid(certPem: CertificateBuffer | CertificateString, keyAuthorization: string): boolean; +} + +export interface CryptoLegacyInterface { + createPrivateKey(size?: number): Promise; + createPublicKey(key: PrivateKeyBuffer | PrivateKeyString): Promise; + getPemBody(str: string): string; + splitPemChain(str: string): string[]; + getModulus(input: PrivateKeyBuffer | PrivateKeyString | PublicKeyBuffer | PublicKeyString | CertificateBuffer | CertificateString | CsrBuffer | CsrString): Promise; + getPublicExponent(input: PrivateKeyBuffer | PrivateKeyString | PublicKeyBuffer | PublicKeyString | CertificateBuffer | CertificateString | CsrBuffer | CsrString): Promise; + readCsrDomains(csr: CsrBuffer | CsrString): Promise; + readCertificateInfo(cert: CertificateBuffer | CertificateString): Promise; + createCsr(data: CsrOptions, key?: PrivateKeyBuffer | PrivateKeyString): Promise<[PrivateKeyBuffer, CsrBuffer]>; +} diff --git a/packages/core/acme-client/src/util.test.ts b/packages/core/acme-client/src/util.test.ts new file mode 100644 index 000000000..284f18af2 --- /dev/null +++ b/packages/core/acme-client/src/util.test.ts @@ -0,0 +1,58 @@ +import assert from "node:assert/strict"; +import { formatResponseError, parseRetryAfterHeader, retry } from "./util.js"; + +declare const describe: any; +declare const it: any; + +describe("util helpers", () => { + it("parses retry-after values", () => { + assert.equal(parseRetryAfterHeader("120"), 120); + assert.equal(parseRetryAfterHeader("invalid"), 0); + assert.equal(parseRetryAfterHeader("Wed, 21 Oct 2015 07:28:00 GMT"), 0); + }); + + it("formats response errors without newlines", () => { + const error = formatResponseError({ + data: { + error: { + detail: "line 1\nline 2", + }, + }, + }); + + assert.equal(error, "line 1line 2"); + }); + + it("retries until success", async () => { + const delays: number[] = []; + const originalSetTimeout = globalThis.setTimeout; + let attempts = 0; + + (globalThis as any).setTimeout = (fn: (...args: any[]) => void, delay?: number) => { + delays.push(Number(delay)); + return originalSetTimeout(fn, 0); + }; + + try { + const result = await retry( + async () => { + attempts += 1; + + if (attempts < 3) { + throw new Error(`boom-${attempts}`); + } + + return "ok"; + }, + { attempts: 3, min: 10, max: 20 }, + () => {} + ); + + assert.equal(result, "ok"); + assert.equal(attempts, 3); + assert.deepEqual(delays, [10, 20]); + } finally { + (globalThis as any).setTimeout = originalSetTimeout; + } + }); +}); diff --git a/packages/core/acme-client/src/util.js b/packages/core/acme-client/src/util.ts similarity index 99% rename from packages/core/acme-client/src/util.js rename to packages/core/acme-client/src/util.ts index 26e259936..ed1804f19 100644 --- a/packages/core/acme-client/src/util.js +++ b/packages/core/acme-client/src/util.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Utility methods */ diff --git a/packages/core/acme-client/src/verify.js b/packages/core/acme-client/src/verify.ts similarity index 99% rename from packages/core/acme-client/src/verify.js rename to packages/core/acme-client/src/verify.ts index 232a11a31..efcff1f4b 100644 --- a/packages/core/acme-client/src/verify.js +++ b/packages/core/acme-client/src/verify.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * ACME challenge verification */ diff --git a/packages/core/acme-client/src/wait.js b/packages/core/acme-client/src/wait.ts similarity index 86% rename from packages/core/acme-client/src/wait.js rename to packages/core/acme-client/src/wait.ts index 48f2898aa..e7654a602 100644 --- a/packages/core/acme-client/src/wait.js +++ b/packages/core/acme-client/src/wait.ts @@ -1,3 +1,4 @@ +// @ts-nocheck export async function wait(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); diff --git a/packages/core/acme-client/tsconfig.json b/packages/core/acme-client/tsconfig.json new file mode 100644 index 000000000..6326967ce --- /dev/null +++ b/packages/core/acme-client/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compileOnSave": true, + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "node", + "esModuleInterop": true, + "inlineSourceMap": false, + "sourceMap": false, + "noImplicitThis": false, + "noUnusedLocals": false, + "stripInternal": true, + "skipLibCheck": true, + "pretty": true, + "declaration": true, + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "outDir": "dist", + "rootDir": "src", + "composite": false, + "useDefineForClassFields": false, + "strict": false, + "resolveJsonModule": true, + "isolatedModules": false, + "lib": ["ESNext", "DOM"] + }, + "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.json"], + "exclude": ["dist", "node_modules", "src/**/*.test.ts", "test"] +} diff --git a/packages/core/acme-client/tsconfig.test.json b/packages/core/acme-client/tsconfig.test.json new file mode 100644 index 000000000..2afb3df73 --- /dev/null +++ b/packages/core/acme-client/tsconfig.test.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "dist-test", + "declaration": false, + "declarationMap": false, + "emitDeclarationOnly": false + }, + "include": ["src/**/*.ts"], + "exclude": ["dist", "dist-test", "node_modules", "test"] +} diff --git a/packages/core/acme-client/types/index.d.ts b/packages/core/acme-client/types/index.d.ts index a449eb650..7bb1f620f 100644 --- a/packages/core/acme-client/types/index.d.ts +++ b/packages/core/acme-client/types/index.d.ts @@ -4,8 +4,6 @@ import { AxiosInstance } from 'axios'; import * as rfc8555 from './rfc8555'; -import {CancelError} from '../src/error.js' -export * from '../src/error.js' export type PrivateKeyBuffer = Buffer; export type PublicKeyBuffer = Buffer; @@ -115,6 +113,15 @@ export const directory: { zerossl: { staging: string, production: string + }, + sslcom: { + staging: string, + production: string, + ec: string + }, + litessl: { + staging: string, + production: string } }; @@ -211,14 +218,16 @@ export const agents: any; * Logger */ +export class CancelError extends Error { + constructor(message?: string); +} + export function setLogger(fn: (message: any, ...args: any[]) => void): void; export function createChallengeFn(opts?: {logger?:any}): any; // export function walkTxtRecord(record: any): Promise; export function getAuthoritativeDnsResolver(record:string): Promise; -export const CancelError: typeof CancelError; - export function resolveDomainBySoaRecord(domain: string): Promise; -export function setWalkFromAuthoritative(value = true): void; \ No newline at end of file +export function setWalkFromAuthoritative(value?: boolean): void; diff --git a/packages/core/acme-client/types/index.test-d.ts b/packages/core/acme-client/types/index.test-d.ts index db20f9a01..f9e62730f 100644 --- a/packages/core/acme-client/types/index.test-d.ts +++ b/packages/core/acme-client/types/index.test-d.ts @@ -2,7 +2,7 @@ * acme-client type definition tests */ -import * as acme from 'acme-client'; +import * as acme from '..'; (async () => { /* Client */ @@ -10,6 +10,7 @@ import * as acme from 'acme-client'; const client = new acme.Client({ accountKey, + sslProvider: 'letsencrypt', directoryUrl: acme.directory.letsencrypt.staging }); @@ -52,7 +53,10 @@ import * as acme from 'acme-client'; /* Auto */ await client.auto({ csr: certCsr, - challengeCreateFn: async (authz, challenge, keyAuthorization) => {}, + challengeCreateFn: async (authz, keyAuthorization) => ({ + challenge: authz.challenges[0], + keyAuthorization: await keyAuthorization(authz.challenges[0]) + }), challengeRemoveFn: async (authz, challenge, keyAuthorization) => {} }); @@ -63,7 +67,10 @@ import * as acme from 'acme-client'; skipChallengeVerification: false, challengePriority: ['http-01', 'dns-01'], preferredChain: 'DST Root CA X3', - challengeCreateFn: async (authz, challenge, keyAuthorization) => {}, + challengeCreateFn: async (authz, keyAuthorization) => ({ + challenge: authz.challenges[0], + keyAuthorization: await keyAuthorization(authz.challenges[0]) + }), challengeRemoveFn: async (authz, challenge, keyAuthorization) => {} }); })(); diff --git a/packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/acme.ts b/packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/acme.ts index d7a0fe35a..9661e2b25 100644 --- a/packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/acme.ts +++ b/packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/acme.ts @@ -1,7 +1,5 @@ -// @ts-ignore import * as acme from "@certd/acme-client"; -import { ClientExternalAccountBindingOptions, UrlMapping } from "@certd/acme-client"; -import { Challenge } from "@certd/acme-client/types/rfc8555.js"; +import type { Challenge, ClientExternalAccountBindingOptions, UrlMapping } from "@certd/acme-client"; import { ILogger, utils } from "@certd/basic"; import { IContext } from "@certd/pipeline"; import { IDnsProvider, IDomainParser } from "@certd/plugin-lib";