mirror of
https://github.com/certd/certd.git
synced 2026-04-14 12:30:54 +08:00
Compare commits
106 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4656019898 | ||
|
|
7eceabb2d8 | ||
|
|
eade2c2b68 | ||
|
|
6ec950818c | ||
|
|
7058b20df4 | ||
|
|
a09b0e48c1 | ||
|
|
664bb66a91 | ||
|
|
eba333de7a | ||
|
|
f47b35f6d5 | ||
|
|
c04707c0f7 | ||
|
|
22ebcd4dd1 | ||
|
|
d46dab4fdd | ||
|
|
d44849c53c | ||
|
|
dbc5a3c6b3 | ||
|
|
4a5fa767ed | ||
|
|
1b7debc6a4 | ||
|
|
19a6b94680 | ||
|
|
65a72b8d60 | ||
|
|
7f61cab101 | ||
|
|
692e2b5b96 | ||
|
|
37caef38ad | ||
|
|
9cc01db1d5 | ||
|
|
9172440f79 | ||
|
|
e0eb3a4413 | ||
|
|
ae0f16bf35 | ||
|
|
6c9ed162e3 | ||
|
|
3849b52cdf | ||
|
|
9ecfcb5814 | ||
|
|
54ad09f755 | ||
|
|
6ee4dc165b | ||
|
|
8e2eb89696 | ||
|
|
9d397cc8be | ||
|
|
cbfb0755b3 | ||
|
|
d8d127ee9d | ||
|
|
0ed5430e80 | ||
|
|
878c1f52fa | ||
|
|
586d23fc55 | ||
|
|
6900452b49 | ||
|
|
b97e0e512d | ||
|
|
f740ff517f | ||
|
|
e5989fe023 | ||
|
|
4323156fbe | ||
|
|
3c721901c5 | ||
|
|
5c2c50839a | ||
|
|
fd54c2ffac | ||
|
|
7e483e6091 | ||
|
|
80c48e9acd | ||
|
|
b98f1c0dd0 | ||
|
|
b53874a0b8 | ||
|
|
c4c9adb8bf | ||
|
|
eed265faf1 | ||
|
|
3dc6dd403d | ||
|
|
deb9ba0c43 | ||
|
|
fa33ff499d | ||
|
|
2ed4967744 | ||
|
|
ad360e81cb | ||
|
|
f95f5188b4 | ||
|
|
17d1efa395 | ||
|
|
732cbc5e92 | ||
|
|
5d2d0955b1 | ||
|
|
20feacea12 | ||
|
|
575bf2b73b | ||
|
|
934e6e2bd0 | ||
|
|
fbb9a47e8f | ||
|
|
368132daae | ||
|
|
3d54d04017 | ||
|
|
5b1494b3ce | ||
|
|
ebf2a820cc | ||
|
|
9caa4cd1d4 | ||
|
|
91fd80d44f | ||
|
|
f932e553b0 | ||
|
|
0dd4953197 | ||
|
|
aaea6aa1f3 | ||
|
|
ab4a0aea70 | ||
|
|
29f923537e | ||
|
|
24aa416740 | ||
|
|
08e517ff00 | ||
|
|
29f65389bd | ||
|
|
960a1964c7 | ||
|
|
760d54ba85 | ||
|
|
b1b21d3efc | ||
|
|
5acd7f6fb6 | ||
|
|
a31f1c7f5e | ||
|
|
660ae7333b | ||
|
|
6cf699b25f | ||
|
|
7e5dea51a5 | ||
|
|
92446c3399 | ||
|
|
d9eb927b0a | ||
|
|
39ad7597fa | ||
|
|
83d1bda56a | ||
|
|
20bc5aa6c7 | ||
|
|
162e10909b | ||
|
|
0f1ae6ccd9 | ||
|
|
dd730f6beb | ||
|
|
c9d5cda953 | ||
|
|
33fb1a6bf3 | ||
|
|
a1344245cd | ||
|
|
fe2ca6bed3 | ||
|
|
19a3c7874a | ||
|
|
83e40836eb | ||
|
|
4304c9443a | ||
|
|
b72f8e796c | ||
|
|
7c15f52368 | ||
|
|
adf569eb62 | ||
|
|
340801e743 | ||
|
|
56a1f8158a |
80
CHANGELOG.md
80
CHANGELOG.md
@@ -3,6 +3,86 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
# [1.21.0](https://github.com/certd/certd/compare/v1.20.17...v1.21.0) (2024-07-03)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 支持zero ssl ([eade2c2](https://github.com/certd/certd/commit/eade2c2b681569f03e9cd466e7d5bcd6703ed492))
|
||||||
|
|
||||||
|
## [1.20.17](https://github.com/certd/certd/compare/v1.20.16...v1.20.17) (2024-07-03)
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 创建dns解析后,强制等待60s ([f47b35f](https://github.com/certd/certd/commit/f47b35f6d5bd7d675005c3e286b7e9a029201f8b))
|
||||||
|
* 文件上传提示由cert.crt改为cert.pem ([a09b0e4](https://github.com/certd/certd/commit/a09b0e48c176f3ed763791bd50322c29729f7c1c))
|
||||||
|
* 优化cname verify ([eba333d](https://github.com/certd/certd/commit/eba333de7a5b5ef4b0b7eaa904f578720102fa61))
|
||||||
|
|
||||||
|
## [1.20.16](https://github.com/certd/certd/compare/v1.20.15...v1.20.16) (2024-07-01)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复配置了cdn cname后申请失败的bug ([4a5fa76](https://github.com/certd/certd/commit/4a5fa767edc347d03d29a467e86c9a4d70b0220c))
|
||||||
|
|
||||||
|
## [1.20.15](https://github.com/certd/certd/compare/v1.20.14...v1.20.15) (2024-06-28)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复无法强制取消任务的bug ([9cc01db](https://github.com/certd/certd/commit/9cc01db1d569a5c45bb3e731f35d85df324a8e62))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 腾讯云dns provider 支持腾讯云的accessId ([e0eb3a4](https://github.com/certd/certd/commit/e0eb3a441384d474fe2923c69b25318264bdc9df))
|
||||||
|
* 支持windows文件上传 ([7f61cab](https://github.com/certd/certd/commit/7f61cab101fa13b4e88234e9ad47434e6130fed2))
|
||||||
|
|
||||||
|
## [1.20.14](https://github.com/certd/certd/compare/v1.20.13...v1.20.14) (2024-06-23)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复修改密码功能异常问题 ([f740ff5](https://github.com/certd/certd/commit/f740ff517f521dce361284c2c54bccc68aee0ea2))
|
||||||
|
|
||||||
|
## [1.20.13](https://github.com/certd/certd/compare/v1.20.12...v1.20.13) (2024-06-18)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 日志高度越界 ([c4c9adb](https://github.com/certd/certd/commit/c4c9adb8bfd513f57252e523794e3799a9b220f8))
|
||||||
|
* 修复邮箱设置页面SMTP拼写错误的问题 ([b98f1c0](https://github.com/certd/certd/commit/b98f1c0dd0bc6c6b4f814c578692afdf6d90b88d))
|
||||||
|
* 修复logo问题 ([7e483e6](https://github.com/certd/certd/commit/7e483e60913d509b113148c735fe13ba1d72dddf))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 增加警告,修复一些样式错乱问题 ([fd54c2f](https://github.com/certd/certd/commit/fd54c2ffac492222e85ff2f5f49a9ee5cfc73588))
|
||||||
|
* ssh登录支持openssh格式私钥、支持私钥密码 ([5c2c508](https://github.com/certd/certd/commit/5c2c50839a9076004f9034d754ac6deb531acdfb))
|
||||||
|
|
||||||
|
## [1.20.12](https://github.com/certd/certd/compare/v1.20.10...v1.20.12) (2024-06-17)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复aliyun域名超过100个找不到域名的bug ([5b1494b](https://github.com/certd/certd/commit/5b1494b3ce93d1026dc56ee741342fbb8bf7be24))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 增加系统设置,可以关闭自助注册功能 ([20feace](https://github.com/certd/certd/commit/20feacea12d43386540db6a600f391d786be4014))
|
||||||
|
* 增加cloudflare access token说明 ([934e6e2](https://github.com/certd/certd/commit/934e6e2bd05387cd50ffab95f230933543954098))
|
||||||
|
* 支持重置管理员密码,忘记密码的补救方案 ([732cbc5](https://github.com/certd/certd/commit/732cbc5e927b526850724594830392b2f10c6705))
|
||||||
|
* 支持cloudflare域名 ([fbb9a47](https://github.com/certd/certd/commit/fbb9a47e8f7bb805289b9ee64bd46ffee0f01c06))
|
||||||
|
|
||||||
|
## [1.20.10](https://github.com/certd/certd/compare/v1.20.9...v1.20.10) (2024-05-30)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 增加权限相关helper说明 ([83e4083](https://github.com/certd/certd/commit/83e40836ebff10bec60efe8933183e1ba1c22bf9))
|
||||||
|
* 增加权限相关helper说明 ([4304c94](https://github.com/certd/certd/commit/4304c9443ad9248f63dd6d8c512d8d6f32f90d37))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 上传到主机插件支持复制到本机路径 ([92446c3](https://github.com/certd/certd/commit/92446c339936f98f08f654b8971a7393d8435224))
|
||||||
|
* 优化文件下载包名 ([d9eb927](https://github.com/certd/certd/commit/d9eb927b0a1445feab08b1958aa9ea80637a5ae6))
|
||||||
|
* 增加任务复制功能 ([39ad759](https://github.com/certd/certd/commit/39ad7597fa0e19cc1f7631bbd6fea0a9e05a62c9))
|
||||||
|
|
||||||
|
## [1.20.9](https://github.com/certd/certd/compare/v1.20.8...v1.20.9) (2024-03-22)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package root
|
||||||
|
|
||||||
## [1.20.8](https://github.com/certd/certd/compare/v1.20.7...v1.20.8) (2024-03-22)
|
## [1.20.8](https://github.com/certd/certd/compare/v1.20.7...v1.20.8) (2024-03-22)
|
||||||
|
|
||||||
**Note:** Version bump only for package root
|
**Note:** Version bump only for package root
|
||||||
|
|||||||
84
README.md
84
README.md
@@ -6,7 +6,7 @@ CertD 是一个免费全自动申请和部署SSL证书的工具。
|
|||||||
## 一、特性
|
## 一、特性
|
||||||
本项目不仅支持证书申请过程自动化,还可以自动化部署证书,让你的证书永不过期。
|
本项目不仅支持证书申请过程自动化,还可以自动化部署证书,让你的证书永不过期。
|
||||||
|
|
||||||
* 全自动申请证书(支持阿里云、腾讯云、华为云注册的域名)
|
* 全自动申请证书(支持阿里云、腾讯云、华为云、Cloudflare注册的域名)
|
||||||
* 全自动部署证书(目前支持服务器上传部署、部署到阿里云、腾讯云等)
|
* 全自动部署证书(目前支持服务器上传部署、部署到阿里云、腾讯云等)
|
||||||
* 支持通配符域名
|
* 支持通配符域名
|
||||||
* 支持多个域名打到一个证书上
|
* 支持多个域名打到一个证书上
|
||||||
@@ -42,24 +42,32 @@ https://certd.handsfree.work/
|
|||||||
|
|
||||||
### 1. 安装docker、docker-compose
|
### 1. 安装docker、docker-compose
|
||||||
|
|
||||||
1.1 安装docker
|
1.1 准备一台云服务器
|
||||||
https://docs.docker.com/engine/install/
|
* 【阿里云】云服务器2核2G,新老用户同享,99元/年,续费同价!【 [立即购买](https://www.aliyun.com/benefit?scm=20140722.M_10244282._.V_1&source=5176.11533457&userCode=qya11txb )】
|
||||||
|
* 【腾讯云】云服务器2核2G,新老用户同享,99元/年,续费同价!【 [立即购买](https://cloud.tencent.com/act/cps/redirect?redirect=6094&cps_key=b3ef73330335d7a6efa4a4bbeeb6b2c9&from=console)】
|
||||||
|
|
||||||
|
|
||||||
|
1.2 安装docker
|
||||||
|
https://docs.docker.com/engine/install/
|
||||||
|
选择对应的操作系统,按照官方文档执行命令即可
|
||||||
|
|
||||||
1.2 安装docker-compose
|
|
||||||
https://docs.docker.com/compose/install/linux/
|
|
||||||
|
|
||||||
### 2. 下载docker-compose.yaml文件
|
### 2. 下载docker-compose.yaml文件
|
||||||
|
|
||||||
|
[docker-compose.yaml下载](https://gitee.com/certd/certd/raw/v2/docker/run/docker-compose.yaml)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
mkdir certd
|
mkdir certd
|
||||||
cd certd
|
cd certd
|
||||||
|
# wget下载docker-compose.yaml文件
|
||||||
wget https://raw.githubusercontent.com/certd/certd/v2/docker/run/docker-compose.yaml
|
wget https://raw.githubusercontent.com/certd/certd/v2/docker/run/docker-compose.yaml
|
||||||
# 或者使用gitee地址
|
# 或者使用gitee地址
|
||||||
wget https://gitee.com/certd/certd/raw/v2/docker/run/docker-compose.yaml
|
wget https://gitee.com/certd/certd/raw/v2/docker/run/docker-compose.yaml
|
||||||
|
|
||||||
# 根据需要修改里面的配置
|
# 根据需要修改里面的配置
|
||||||
# 1.修改镜像版本号
|
# 1.修改镜像版本号【可选】
|
||||||
# 2.配置数据保存路径
|
# 2.配置数据保存路径【可选】
|
||||||
# 3.配置certd_auth_jwt_secret
|
# 3.配置certd_auth_jwt_secret【必须】
|
||||||
vi docker-compose.yaml
|
vi docker-compose.yaml
|
||||||
|
|
||||||
|
|
||||||
@@ -71,14 +79,14 @@ https://github.com/certd/certd/releases
|
|||||||
### 3. 运行
|
### 3. 运行
|
||||||
```bash
|
```bash
|
||||||
# 如果docker compose是插件化安装
|
# 如果docker compose是插件化安装
|
||||||
export CERTD_VERSION=1.2.0
|
export CERTD_VERSION=latest
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
|
|
||||||
#如果docker compose是独立安装
|
|
||||||
export CERTD_VERSION=1.2.0
|
|
||||||
docker-compose up -d
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
如果提示 没有compose命令,请安装docker-compose
|
||||||
|
https://docs.docker.com/compose/install/linux/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 4. 访问
|
### 4. 访问
|
||||||
|
|
||||||
http://your_server_ip:7001
|
http://your_server_ip:7001
|
||||||
@@ -86,8 +94,14 @@ http://your_server_ip:7001
|
|||||||
记得修改密码
|
记得修改密码
|
||||||
|
|
||||||
|
|
||||||
## 五、一些说明
|
### 5. 升级
|
||||||
|
|
||||||
|
* 修改版本号,重新运行 `docker compose up -d` 即可
|
||||||
|
* 数据存在`/data/certd`目录下,不用担心数据丢失
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 五、一些说明
|
||||||
* 本项目ssl证书提供商为letencrypt
|
* 本项目ssl证书提供商为letencrypt
|
||||||
* 申请过程遵循acme协议
|
* 申请过程遵循acme协议
|
||||||
* 需要验证域名所有权,一般有两种方式(目前本项目仅支持dns-01)
|
* 需要验证域名所有权,一般有两种方式(目前本项目仅支持dns-01)
|
||||||
@@ -99,7 +113,37 @@ http://your_server_ip:7001
|
|||||||
* 免费证书过期时间90天,以后可能还会缩短,所以自动化部署必不可少
|
* 免费证书过期时间90天,以后可能还会缩短,所以自动化部署必不可少
|
||||||
* 设置每天自动运行,当证书过期前20天,会自动重新申请证书并部署
|
* 设置每天自动运行,当证书过期前20天,会自动重新申请证书并部署
|
||||||
|
|
||||||
## 六、联系作者
|
## 六、不同平台的设置说明
|
||||||
|
|
||||||
|
* [Cloudflare](./doc/cf/cf.md)
|
||||||
|
* [腾讯云](./doc/tencent/tencent.md)
|
||||||
|
* [windows主机](./doc/host/host.md)
|
||||||
|
|
||||||
|
|
||||||
|
## 七、问题处理
|
||||||
|
### 7.1 忘记管理员密码
|
||||||
|
解决方法如下:
|
||||||
|
1. 修改docker-compose.yaml文件,将环境变量`certd_system_resetAdminPassword`改为`true`
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
certd:
|
||||||
|
environment: # 环境变量
|
||||||
|
- certd_system_resetAdminPassword=false
|
||||||
|
```
|
||||||
|
2. 重启容器
|
||||||
|
```shell
|
||||||
|
docker compose up -d
|
||||||
|
docker logs -f --tail 500 certd
|
||||||
|
# 观察日志,当日志中输出“重置1号管理员用户的密码完成”,即可操作下一步
|
||||||
|
```
|
||||||
|
3. 修改docker-compose.yaml,将`certd_system_resetAdminPassword`改回`false`
|
||||||
|
4. 再次重启容器
|
||||||
|
```shell
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
5. 使用admin/123456登录系统,请及时修改管理员密码
|
||||||
|
|
||||||
|
## 八、联系作者
|
||||||
如有疑问,欢迎加入群聊(请备注certd)
|
如有疑问,欢迎加入群聊(请备注certd)
|
||||||
* QQ群:141236433
|
* QQ群:141236433
|
||||||
* 微信群:
|
* 微信群:
|
||||||
@@ -111,7 +155,7 @@ http://your_server_ip:7001
|
|||||||
<img height="230" src="./doc/images/me.png">
|
<img height="230" src="./doc/images/me.png">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## 捐赠
|
## 九、捐赠
|
||||||
媳妇儿说:“一天到晚搞开源,也不管管老婆孩子!😡😡😡”
|
媳妇儿说:“一天到晚搞开源,也不管管老婆孩子!😡😡😡”
|
||||||
拜托各位捐赠支持一下,让媳妇儿开心开心,我也能有更多时间进行开源项目,感谢🙏🙏🙏
|
拜托各位捐赠支持一下,让媳妇儿开心开心,我也能有更多时间进行开源项目,感谢🙏🙏🙏
|
||||||
<p align="center">
|
<p align="center">
|
||||||
@@ -119,12 +163,12 @@ http://your_server_ip:7001
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
## 七、贡献代码
|
## 十、贡献代码
|
||||||
|
|
||||||
[贡献插件教程](./packages/plugins/plugin-center/README.md)
|
[贡献插件教程](./plugin.md)
|
||||||
|
|
||||||
|
|
||||||
## 八、我的其他项目
|
## 十一、我的其他项目
|
||||||
* [袖手GPT](https://ai.handsfree.work/) ChatGPT,国内可用,无需FQ,每日免费额度
|
* [袖手GPT](https://ai.handsfree.work/) ChatGPT,国内可用,无需FQ,每日免费额度
|
||||||
* [fast-crud](https://gitee.com/fast-crud/fast-crud/) 基于vue3的crud快速开发框架
|
* [fast-crud](https://gitee.com/fast-crud/fast-crud/) 基于vue3的crud快速开发框架
|
||||||
* [dev-sidecar](https://github.com/docmirror/dev-sidecar/) 直连访问github工具,无需FQ,解决github无法访问的问题
|
* [dev-sidecar](https://github.com/docmirror/dev-sidecar/) 直连访问github工具,无需FQ,解决github无法访问的问题
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import http from 'axios'
|
|||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
|
|
||||||
//读取 packages/core/pipline/package.json的版本号
|
//读取 packages/core/pipline/package.json的版本号
|
||||||
import {default as packageJson} from './packages/core/pipeline/package.json';
|
import {default as packageJson} from './packages/core/pipeline/package.json' assert { type: "json" };
|
||||||
|
|
||||||
const certdVersion = packageJson.version
|
const certdVersion = packageJson.version
|
||||||
console.log("certdVersion", certdVersion)
|
console.log("certdVersion", certdVersion)
|
||||||
|
|||||||
15
doc/cf/cf.md
Normal file
15
doc/cf/cf.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Cloudflare
|
||||||
|
|
||||||
|
|
||||||
|
## CF Token申请
|
||||||
|
|
||||||
|
### 申请地址:
|
||||||
|
https://dash.cloudflare.com/profile/api-tokens
|
||||||
|
|
||||||
|
### 权限设置:
|
||||||
|
需要设置权限和资源范围
|
||||||
|
权限包括:Zone.Zone.edit, Zone.DNS.edit
|
||||||
|
资源范围:要包含对应域名,推荐直接设置为All Zones
|
||||||
|
最终效果如下,可以切换语言为英文对比如下图检查
|
||||||
|
|
||||||
|

|
||||||
BIN
doc/cf/cf_token.png
Normal file
BIN
doc/cf/cf_token.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 45 KiB |
24
doc/host/host.md
Normal file
24
doc/host/host.md
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# 远程主机
|
||||||
|
|
||||||
|
远程主机基于ssh协议,通过ssh连接远程主机,执行命令。
|
||||||
|
|
||||||
|
## windows开启OpenSSH Server
|
||||||
|
1. 安装OpenSSH Server
|
||||||
|
请前往Microsoft官方文档查看如何开启openSSH
|
||||||
|
https://learn.microsoft.com/zh-cn/windows-server/administration/openssh/openssh_install_firstuse?tabs=gui#install-openssh-for-windows
|
||||||
|
|
||||||
|
2. 启动OpenSSH Server服务
|
||||||
|
```
|
||||||
|
win+R 弹出运行对话框,输入 services.msc 打开服务管理器
|
||||||
|
找到 OpenSSH SSH Server
|
||||||
|
启动ssh server服务,并且设置为自动启动
|
||||||
|
```
|
||||||
|
|
||||||
|
3. 测试ssh登录
|
||||||
|
使用你常用的ssh客户端,连接你的windows主机,进行测试
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
# 如何确定你用户名
|
||||||
|
C:\Users\xiaoj>
|
||||||
|
↑↑↑↑---------这个就是windows ssh的登录用户名
|
||||||
|
```
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 145 KiB |
BIN
doc/tencent/dnspod-token.png
Normal file
BIN
doc/tencent/dnspod-token.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 149 KiB |
BIN
doc/tencent/tencent-access.png
Normal file
BIN
doc/tencent/tencent-access.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 98 KiB |
16
doc/tencent/tencent.md
Normal file
16
doc/tencent/tencent.md
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# 腾讯云
|
||||||
|
|
||||||
|
|
||||||
|
## DNSPOD 授权设置
|
||||||
|
目前腾讯云管理的域名的dns暂时只支持从DNSPOD进行设置
|
||||||
|
打开 https://console.dnspod.cn/account/token/apikey
|
||||||
|
然后按如下方式获取DNSPOD的授权
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
## 腾讯云API密钥设置
|
||||||
|
|
||||||
|
腾讯云其他部署需要API密钥,需要在腾讯云控制台进行设置
|
||||||
|
打开 https://console.cloud.tencent.com/cam/capi
|
||||||
|
然后按如下方式获取腾讯云的API密钥
|
||||||
|

|
||||||
@@ -1,12 +1,14 @@
|
|||||||
FROM registry.cn-shenzhen.aliyuncs.com/handsfree/node:16-alpine
|
FROM registry.cn-shenzhen.aliyuncs.com/handsfree/node:18-alpine
|
||||||
EXPOSE 7001
|
EXPOSE 7001
|
||||||
ENV NODE_ENV production
|
ENV NODE_ENV production
|
||||||
ENV MIDWAY_SERVER_ENV production
|
ENV MIDWAY_SERVER_ENV production
|
||||||
WORKDIR /app/
|
WORKDIR /app/
|
||||||
|
#RUN npm install -g pnpm
|
||||||
#RUN npm install cross-env -g --registry=https://registry.npmmirror.com
|
#RUN npm install cross-env -g --registry=https://registry.npmmirror.com
|
||||||
#RUN npm install pm2 -g --registry=https://registry.npmmirror.com
|
#RUN npm install pm2 -g --registry=https://registry.npmmirror.com
|
||||||
#RUN pm2 install pm2-logrotate
|
#RUN pm2 install pm2-logrotate
|
||||||
ADD ./workspace/certd-server/ /app/
|
ADD ./workspace/certd-server/ /app/
|
||||||
|
RUN sed -i "s/workspace://g" "/app/package.json"
|
||||||
RUN yarn install --production --registry=https://registry.npmmirror.com
|
RUN yarn install --production --registry=https://registry.npmmirror.com
|
||||||
#RUN yarn install --production
|
#RUN yarn install --production
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
FROM registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest
|
|
||||||
EXPOSE 7001
|
|
||||||
RUN npm run build
|
|
||||||
#RUN npm install pm2 -g --registry=https://registry.npmmirror.com
|
|
||||||
#CMD ["pm2-runtime", "start", "./bootstrap.js","--name", "certd","-i","1","--", "-p", "7001"]
|
|
||||||
CMD ["npm","run", "start"]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,19 +1,22 @@
|
|||||||
version: '3.3'
|
version: '3.3'
|
||||||
services:
|
services:
|
||||||
certd:
|
certd:
|
||||||
# 镜像 # ↓↓↓↓↓ --- 1、 修改镜像版本号,或者干脆写成latest
|
# 镜像 # ↓↓↓↓↓ --- 1、 修改镜像版本号,或者干脆写成latest, 如果设置了环境变量 export CERTD_VERSION=latest,这里可以不修改
|
||||||
image: registry.cn-shenzhen.aliyuncs.com/handsfree/certd:${CERTD_VERSION}
|
image: registry.cn-shenzhen.aliyuncs.com/handsfree/certd:${CERTD_VERSION}
|
||||||
container_name: certd # 容器名
|
container_name: certd # 容器名
|
||||||
restart: unless-stopped # 重启
|
restart: unless-stopped # 自动重启
|
||||||
volumes:
|
volumes:
|
||||||
# ↓↓↓↓↓ ------------------------------------------------------- 2、 修改数据库以及证书存储路径
|
# ↓↓↓↓↓ ------------------------------------------------------- 2、 修改数据库以及证书存储路径【可选】
|
||||||
- /data/certd:/app/data
|
- /data/certd:/app/data
|
||||||
ports: # 端口映射
|
ports: # 端口映射
|
||||||
|
# ↓↓↓↓ 如果端口有冲突,可以修改第一个7001为其他不冲突的端口号
|
||||||
- "7001:7001"
|
- "7001:7001"
|
||||||
environment: # 环境变量
|
environment: # 环境变量
|
||||||
- TZ=Asia/Shanghai
|
- TZ=Asia/Shanghai
|
||||||
- certd_auth_jwt_secret=changeme
|
- certd_auth_jwt_secret=changeme
|
||||||
# ↑↑↑↑↑ ---------------------------------- 3、 修改成你的自定义密钥
|
# ↑↑↑↑↑ ---------------------------------- 3、 修改成你的自定义密钥【必须,安全需要】
|
||||||
|
- certd_system_resetAdminPassword=false
|
||||||
|
# ↑↑↑↑↑ 如果忘记管理员密码,可以设置为true,重启之后,管理员密码将改成123456,然后请及时修改回false
|
||||||
# 设置环境变量即可自定义certd配置
|
# 设置环境变量即可自定义certd配置
|
||||||
# 服务端配置项见: packages/ui/certd-server/src/config/config.default.ts
|
# 服务端配置项见: packages/ui/certd-server/src/config/config.default.ts
|
||||||
# 服务端配置规则: certd_ + 配置项, 点号用_代替
|
# 服务端配置规则: certd_ + 配置项, 点号用_代替
|
||||||
|
|||||||
0
docker/run/build.sh → docker/run/run.sh
Executable file → Normal file
0
docker/run/build.sh → docker/run/run.sh
Executable file → Normal file
@@ -9,5 +9,5 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"npmClient": "pnpm",
|
"npmClient": "pnpm",
|
||||||
"version": "1.20.8"
|
"version": "1.21.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,15 +9,8 @@ env:
|
|||||||
rules:
|
rules:
|
||||||
indent: [2, 4, { SwitchCase: 1, VariableDeclarator: 1 }]
|
indent: [2, 4, { SwitchCase: 1, VariableDeclarator: 1 }]
|
||||||
brace-style: [2, 'stroustrup', { allowSingleLine: true }]
|
brace-style: [2, 'stroustrup', { allowSingleLine: true }]
|
||||||
space-before-function-paren: [2, { anonymous: 'never', named: 'never' }]
|
|
||||||
func-names: 0
|
func-names: 0
|
||||||
prefer-destructuring: 0
|
|
||||||
object-curly-newline: 0
|
|
||||||
class-methods-use-this: 0
|
class-methods-use-this: 0
|
||||||
wrap-iife: [2, 'inside']
|
|
||||||
no-param-reassign: 0
|
no-param-reassign: 0
|
||||||
comma-dangle: [2, 'never']
|
|
||||||
max-len: [1, 200, 2, { ignoreUrls: true, ignoreComments: false }]
|
max-len: [1, 200, 2, { ignoreUrls: true, ignoreComments: false }]
|
||||||
no-multiple-empty-lines: [2, { max: 2, maxBOF: 0, maxEOF: 0 }]
|
|
||||||
prefer-object-spread: 0
|
|
||||||
import/no-useless-path-segments: 0
|
import/no-useless-path-segments: 0
|
||||||
|
|||||||
@@ -28,6 +28,6 @@ chown root:root /usr/local/bin/pebble
|
|||||||
chmod 0755 /usr/local/bin/pebble
|
chmod 0755 /usr/local/bin/pebble
|
||||||
|
|
||||||
# Config
|
# Config
|
||||||
sed -i 's/test\/certs\/localhost/\/etc\/pebble/' /etc/pebble/pebble.json
|
sed -i 's#test/certs/localhost#/etc/pebble#' /etc/pebble/pebble.json
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
---
|
|
||||||
name: test
|
name: test
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
@@ -9,10 +8,9 @@ jobs:
|
|||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node: [16, 18, 20]
|
node: [16, 18, 20, 22]
|
||||||
eab: [0, 1]
|
eab: [0, 1]
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Environment
|
# Environment
|
||||||
#
|
#
|
||||||
@@ -41,7 +39,6 @@ jobs:
|
|||||||
ACME_HTTP_PORT: 5002
|
ACME_HTTP_PORT: 5002
|
||||||
ACME_HTTPS_PORT: 5003
|
ACME_HTTPS_PORT: 5003
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Pipeline
|
# Pipeline
|
||||||
#
|
#
|
||||||
|
|||||||
1
packages/core/acme-client/.gitignore
vendored
1
packages/core/acme-client/.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
|
.actrc
|
||||||
.vscode/
|
.vscode/
|
||||||
node_modules/
|
node_modules/
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
|
|||||||
@@ -3,6 +3,57 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
# [1.21.0](https://github.com/publishlab/node-acme-client/compare/v1.20.17...v1.21.0) (2024-07-03)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 支持zero ssl ([eade2c2](https://github.com/publishlab/node-acme-client/commit/eade2c2b681569f03e9cd466e7d5bcd6703ed492))
|
||||||
|
|
||||||
|
## [1.20.17](https://github.com/publishlab/node-acme-client/compare/v1.20.16...v1.20.17) (2024-07-03)
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 创建dns解析后,强制等待60s ([f47b35f](https://github.com/publishlab/node-acme-client/commit/f47b35f6d5bd7d675005c3e286b7e9a029201f8b))
|
||||||
|
* 优化cname verify ([eba333d](https://github.com/publishlab/node-acme-client/commit/eba333de7a5b5ef4b0b7eaa904f578720102fa61))
|
||||||
|
|
||||||
|
## [1.20.16](https://github.com/publishlab/node-acme-client/compare/v1.20.15...v1.20.16) (2024-07-01)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复配置了cdn cname后申请失败的bug ([4a5fa76](https://github.com/publishlab/node-acme-client/commit/4a5fa767edc347d03d29a467e86c9a4d70b0220c))
|
||||||
|
|
||||||
|
## [1.20.15](https://github.com/publishlab/node-acme-client/compare/v1.20.14...v1.20.15) (2024-06-28)
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 腾讯云dns provider 支持腾讯云的accessId ([e0eb3a4](https://github.com/publishlab/node-acme-client/commit/e0eb3a441384d474fe2923c69b25318264bdc9df))
|
||||||
|
|
||||||
|
## [1.20.14](https://github.com/publishlab/node-acme-client/compare/v1.20.13...v1.20.14) (2024-06-23)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/acme-client
|
||||||
|
|
||||||
|
## [1.20.13](https://github.com/publishlab/node-acme-client/compare/v1.20.12...v1.20.13) (2024-06-18)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/acme-client
|
||||||
|
|
||||||
|
## [1.20.12](https://github.com/publishlab/node-acme-client/compare/v1.20.10...v1.20.12) (2024-06-17)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复aliyun域名超过100个找不到域名的bug ([5b1494b](https://github.com/publishlab/node-acme-client/commit/5b1494b3ce93d1026dc56ee741342fbb8bf7be24))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 支持cloudflare域名 ([fbb9a47](https://github.com/publishlab/node-acme-client/commit/fbb9a47e8f7bb805289b9ee64bd46ffee0f01c06))
|
||||||
|
|
||||||
|
## [1.20.10](https://github.com/publishlab/node-acme-client/compare/v1.20.9...v1.20.10) (2024-05-30)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/acme-client
|
||||||
|
|
||||||
|
## [1.20.9](https://github.com/publishlab/node-acme-client/compare/v1.20.8...v1.20.9) (2024-03-22)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/acme-client
|
||||||
|
|
||||||
## [1.20.8](https://github.com/publishlab/node-acme-client/compare/v1.20.7...v1.20.8) (2024-03-22)
|
## [1.20.8](https://github.com/publishlab/node-acme-client/compare/v1.20.7...v1.20.8) (2024-03-22)
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/acme-client
|
**Note:** Version bump only for package @certd/acme-client
|
||||||
@@ -23,6 +74,11 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
|
|||||||
|
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v5.3.1 (2024-05-22)
|
||||||
|
|
||||||
|
* `fixed` Allow `client.auto()` being called with an empty CSR common name
|
||||||
|
* `fixed` Bug when calling `updateAccountKey()` with external account binding
|
||||||
|
|
||||||
## v5.3.0 (2024-02-05)
|
## v5.3.0 (2024-02-05)
|
||||||
|
|
||||||
* `added` Support and tests for satisfying `tls-alpn-01` challenges
|
* `added` Support and tests for satisfying `tls-alpn-01` challenges
|
||||||
@@ -55,7 +111,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
|
|||||||
* `fixed` Upgrade `axios@0.26.1`
|
* `fixed` Upgrade `axios@0.26.1`
|
||||||
* `fixed` Upgrade `node-forge@1.3.0` - [CVE-2022-24771](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-24771), [CVE-2022-24772](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-24772), [CVE-2022-24773](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-24773)
|
* `fixed` Upgrade `node-forge@1.3.0` - [CVE-2022-24771](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-24771), [CVE-2022-24772](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-24772), [CVE-2022-24773](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-24773)
|
||||||
|
|
||||||
## 4.2.4 (2022-03-19)
|
## v4.2.4 (2022-03-19)
|
||||||
|
|
||||||
* `fixed` Use SHA-256 when signing CSRs
|
* `fixed` Use SHA-256 when signing CSRs
|
||||||
|
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ This module is written to handle communication with a Boulder/Let's Encrypt-styl
|
|||||||
|
|
||||||
## Compatibility
|
## Compatibility
|
||||||
|
|
||||||
| acme-client | Node.js | |
|
| acme-client | Node.js | |
|
||||||
| ------------- | --------- | ----------------------------------------- |
|
| ----------- | ------- | ----------------------------------------- |
|
||||||
| v5.x | >= v16 | [Upgrade guide](docs/upgrade-v5.md) |
|
| v5.x | >= v16 | [Upgrade guide](docs/upgrade-v5.md) |
|
||||||
| v4.x | >= v10 | [Changelog](CHANGELOG.md#v400-2020-05-29) |
|
| v4.x | >= v10 | [Changelog](CHANGELOG.md#v400-2020-05-29) |
|
||||||
| v3.x | >= v8 | [Changelog](CHANGELOG.md#v300-2019-07-13) |
|
| v3.x | >= v8 | [Changelog](CHANGELOG.md#v300-2019-07-13) |
|
||||||
| v2.x | >= v4 | [Changelog](CHANGELOG.md#v200-2018-04-02) |
|
| v2.x | >= v4 | [Changelog](CHANGELOG.md#v200-2018-04-02) |
|
||||||
| v1.x | >= v4 | [Changelog](CHANGELOG.md#v100-2017-10-20) |
|
| v1.x | >= v4 | [Changelog](CHANGELOG.md#v100-2017-10-20) |
|
||||||
|
|
||||||
## Table of contents
|
## Table of contents
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ const accountPrivateKey = '<PEM encoded private key>';
|
|||||||
|
|
||||||
const client = new acme.Client({
|
const client = new acme.Client({
|
||||||
directoryUrl: acme.directory.letsencrypt.staging,
|
directoryUrl: acme.directory.letsencrypt.staging,
|
||||||
accountKey: accountPrivateKey
|
accountKey: accountPrivateKey,
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -75,8 +75,8 @@ const client = new acme.Client({
|
|||||||
accountKey: accountPrivateKey,
|
accountKey: accountPrivateKey,
|
||||||
externalAccountBinding: {
|
externalAccountBinding: {
|
||||||
kid: 'YOUR-EAB-KID',
|
kid: 'YOUR-EAB-KID',
|
||||||
hmacKey: 'YOUR-EAB-HMAC-KEY'
|
hmacKey: 'YOUR-EAB-HMAC-KEY',
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ In some cases, for example with some EAB providers, this account creation step m
|
|||||||
const client = new acme.Client({
|
const client = new acme.Client({
|
||||||
directoryUrl: acme.directory.letsencrypt.staging,
|
directoryUrl: acme.directory.letsencrypt.staging,
|
||||||
accountKey: accountPrivateKey,
|
accountKey: accountPrivateKey,
|
||||||
accountUrl: 'https://acme-v02.api.letsencrypt.org/acme/acct/12345678'
|
accountUrl: 'https://acme-v02.api.letsencrypt.org/acme/acct/12345678',
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -113,8 +113,7 @@ const privateRsaKey = await acme.crypto.createPrivateRsaKey();
|
|||||||
const privateEcdsaKey = await acme.crypto.createPrivateEcdsaKey();
|
const privateEcdsaKey = await acme.crypto.createPrivateEcdsaKey();
|
||||||
|
|
||||||
const [certificateKey, certificateCsr] = await acme.crypto.createCsr({
|
const [certificateKey, certificateCsr] = await acme.crypto.createCsr({
|
||||||
commonName: '*.example.com',
|
altNames: ['example.com', '*.example.com'],
|
||||||
altNames: ['example.com']
|
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -139,7 +138,7 @@ const autoOpts = {
|
|||||||
email: 'test@example.com',
|
email: 'test@example.com',
|
||||||
termsOfServiceAgreed: true,
|
termsOfServiceAgreed: true,
|
||||||
challengeCreateFn: async (authz, challenge, keyAuthorization) => {},
|
challengeCreateFn: async (authz, challenge, keyAuthorization) => {},
|
||||||
challengeRemoveFn: async (authz, challenge, keyAuthorization) => {}
|
challengeRemoveFn: async (authz, challenge, keyAuthorization) => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
const certificate = await client.auto(autoOpts);
|
const certificate = await client.auto(autoOpts);
|
||||||
@@ -156,7 +155,7 @@ To modify challenge priority, provide a list of challenge types in `challengePri
|
|||||||
```js
|
```js
|
||||||
await client.auto({
|
await client.auto({
|
||||||
...,
|
...,
|
||||||
challengePriority: ['http-01', 'dns-01']
|
challengePriority: ['http-01', 'dns-01'],
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -171,7 +170,7 @@ To completely disable `acme-client`s internal challenge verification, enable `sk
|
|||||||
```js
|
```js
|
||||||
await client.auto({
|
await client.auto({
|
||||||
...,
|
...,
|
||||||
skipChallengeVerification: true
|
skipChallengeVerification: true,
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -185,14 +184,14 @@ For more fine-grained control you can interact with the ACME API using the metho
|
|||||||
```js
|
```js
|
||||||
const account = await client.createAccount({
|
const account = await client.createAccount({
|
||||||
termsOfServiceAgreed: true,
|
termsOfServiceAgreed: true,
|
||||||
contact: ['mailto:test@example.com']
|
contact: ['mailto:test@example.com'],
|
||||||
});
|
});
|
||||||
|
|
||||||
const order = await client.createOrder({
|
const order = await client.createOrder({
|
||||||
identifiers: [
|
identifiers: [
|
||||||
{ type: 'dns', value: 'example.com' },
|
{ type: 'dns', value: 'example.com' },
|
||||||
{ type: 'dns', value: '*.example.com' }
|
{ type: 'dns', value: '*.example.com' },
|
||||||
]
|
],
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -207,7 +206,7 @@ const acme = require('acme-client');
|
|||||||
|
|
||||||
acme.axios.defaults.proxy = {
|
acme.axios.defaults.proxy = {
|
||||||
host: '127.0.0.1',
|
host: '127.0.0.1',
|
||||||
port: 9000
|
port: 9000,
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
11:19
|
01:14
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ Create ACME client instance
|
|||||||
```js
|
```js
|
||||||
const client = new acme.Client({
|
const client = new acme.Client({
|
||||||
directoryUrl: acme.directory.letsencrypt.staging,
|
directoryUrl: acme.directory.letsencrypt.staging,
|
||||||
accountKey: 'Private key goes here'
|
accountKey: 'Private key goes here',
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
**Example**
|
**Example**
|
||||||
@@ -75,7 +75,7 @@ const client = new acme.Client({
|
|||||||
accountUrl: 'Optional account URL goes here',
|
accountUrl: 'Optional account URL goes here',
|
||||||
backoffAttempts: 10,
|
backoffAttempts: 10,
|
||||||
backoffMin: 5000,
|
backoffMin: 5000,
|
||||||
backoffMax: 30000
|
backoffMax: 30000,
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
**Example**
|
**Example**
|
||||||
@@ -86,8 +86,8 @@ const client = new acme.Client({
|
|||||||
accountKey: 'Private key goes here',
|
accountKey: 'Private key goes here',
|
||||||
externalAccountBinding: {
|
externalAccountBinding: {
|
||||||
kid: 'YOUR-EAB-KID',
|
kid: 'YOUR-EAB-KID',
|
||||||
hmacKey: 'YOUR-EAB-HMAC-KEY'
|
hmacKey: 'YOUR-EAB-HMAC-KEY',
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
<a name="AcmeClient+getTermsOfServiceUrl"></a>
|
<a name="AcmeClient+getTermsOfServiceUrl"></a>
|
||||||
@@ -145,7 +145,7 @@ https://datatracker.ietf.org/doc/html/rfc8555#section-7.3
|
|||||||
Create a new account
|
Create a new account
|
||||||
```js
|
```js
|
||||||
const account = await client.createAccount({
|
const account = await client.createAccount({
|
||||||
termsOfServiceAgreed: true
|
termsOfServiceAgreed: true,
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
**Example**
|
**Example**
|
||||||
@@ -153,7 +153,7 @@ Create a new account with contact info
|
|||||||
```js
|
```js
|
||||||
const account = await client.createAccount({
|
const account = await client.createAccount({
|
||||||
termsOfServiceAgreed: true,
|
termsOfServiceAgreed: true,
|
||||||
contact: ['mailto:test@example.com']
|
contact: ['mailto:test@example.com'],
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
<a name="AcmeClient+updateAccount"></a>
|
<a name="AcmeClient+updateAccount"></a>
|
||||||
@@ -174,7 +174,7 @@ https://datatracker.ietf.org/doc/html/rfc8555#section-7.3.2
|
|||||||
Update existing account
|
Update existing account
|
||||||
```js
|
```js
|
||||||
const account = await client.updateAccount({
|
const account = await client.updateAccount({
|
||||||
contact: ['mailto:foo@example.com']
|
contact: ['mailto:foo@example.com'],
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
<a name="AcmeClient+updateAccountKey"></a>
|
<a name="AcmeClient+updateAccountKey"></a>
|
||||||
@@ -218,8 +218,8 @@ Create a new order
|
|||||||
const order = await client.createOrder({
|
const order = await client.createOrder({
|
||||||
identifiers: [
|
identifiers: [
|
||||||
{ type: 'dns', value: 'example.com' },
|
{ type: 'dns', value: 'example.com' },
|
||||||
{ type: 'dns', value: 'test.example.com' }
|
{ type: 'dns', value: 'test.example.com' },
|
||||||
]
|
],
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
<a name="AcmeClient+getOrder"></a>
|
<a name="AcmeClient+getOrder"></a>
|
||||||
@@ -452,7 +452,7 @@ Revoke certificate with reason
|
|||||||
```js
|
```js
|
||||||
const certificate = { ... }; // Previously created certificate
|
const certificate = { ... }; // Previously created certificate
|
||||||
const result = await client.revokeCertificate(certificate, {
|
const result = await client.revokeCertificate(certificate, {
|
||||||
reason: 4
|
reason: 4,
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
<a name="AcmeClient+auto"></a>
|
<a name="AcmeClient+auto"></a>
|
||||||
@@ -479,7 +479,7 @@ Auto mode
|
|||||||
Order a certificate using auto mode
|
Order a certificate using auto mode
|
||||||
```js
|
```js
|
||||||
const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
|
const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
|
||||||
commonName: 'test.example.com'
|
altNames: ['test.example.com'],
|
||||||
});
|
});
|
||||||
|
|
||||||
const certificate = await client.auto({
|
const certificate = await client.auto({
|
||||||
@@ -491,14 +491,14 @@ const certificate = await client.auto({
|
|||||||
},
|
},
|
||||||
challengeRemoveFn: async (authz, challenge, keyAuthorization) => {
|
challengeRemoveFn: async (authz, challenge, keyAuthorization) => {
|
||||||
// Clean up challenge here
|
// Clean up challenge here
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
**Example**
|
**Example**
|
||||||
Order a certificate using auto mode with preferred chain
|
Order a certificate using auto mode with preferred chain
|
||||||
```js
|
```js
|
||||||
const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
|
const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
|
||||||
commonName: 'test.example.com'
|
altNames: ['test.example.com'],
|
||||||
});
|
});
|
||||||
|
|
||||||
const certificate = await client.auto({
|
const certificate = await client.auto({
|
||||||
@@ -507,7 +507,7 @@ const certificate = await client.auto({
|
|||||||
termsOfServiceAgreed: true,
|
termsOfServiceAgreed: true,
|
||||||
preferredChain: 'DST Root CA X3',
|
preferredChain: 'DST Root CA X3',
|
||||||
challengeCreateFn: async () => {},
|
challengeCreateFn: async () => {},
|
||||||
challengeRemoveFn: async () => {}
|
challengeRemoveFn: async () => {},
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
<a name="Client"></a>
|
<a name="Client"></a>
|
||||||
|
|||||||
@@ -239,29 +239,30 @@ Create a Certificate Signing Request
|
|||||||
Create a Certificate Signing Request
|
Create a Certificate Signing Request
|
||||||
```js
|
```js
|
||||||
const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
|
const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
|
||||||
commonName: 'test.example.com'
|
altNames: ['test.example.com'],
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
**Example**
|
**Example**
|
||||||
Certificate Signing Request with both common and alternative names
|
Certificate Signing Request with both common and alternative names
|
||||||
|
> *Warning*: Certificate subject common name has been [deprecated](https://letsencrypt.org/docs/glossary/#def-CN) and its use is [discouraged](https://cabforum.org/uploads/BRv1.2.3.pdf).
|
||||||
```js
|
```js
|
||||||
const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
|
const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
|
||||||
keySize: 4096,
|
keySize: 4096,
|
||||||
commonName: 'test.example.com',
|
commonName: 'test.example.com',
|
||||||
altNames: ['foo.example.com', 'bar.example.com']
|
altNames: ['foo.example.com', 'bar.example.com'],
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
**Example**
|
**Example**
|
||||||
Certificate Signing Request with additional information
|
Certificate Signing Request with additional information
|
||||||
```js
|
```js
|
||||||
const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
|
const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
|
||||||
commonName: 'test.example.com',
|
altNames: ['test.example.com'],
|
||||||
country: 'US',
|
country: 'US',
|
||||||
state: 'California',
|
state: 'California',
|
||||||
locality: 'Los Angeles',
|
locality: 'Los Angeles',
|
||||||
organization: 'The Company Inc.',
|
organization: 'The Company Inc.',
|
||||||
organizationUnit: 'IT Department',
|
organizationUnit: 'IT Department',
|
||||||
emailAddress: 'contact@example.com'
|
emailAddress: 'contact@example.com',
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
**Example**
|
**Example**
|
||||||
@@ -270,8 +271,9 @@ Certificate Signing Request with ECDSA private key
|
|||||||
const certificateKey = await acme.crypto.createPrivateEcdsaKey();
|
const certificateKey = await acme.crypto.createPrivateEcdsaKey();
|
||||||
|
|
||||||
const [, certificateRequest] = await acme.crypto.createCsr({
|
const [, certificateRequest] = await acme.crypto.createCsr({
|
||||||
commonName: 'test.example.com'
|
altNames: ['test.example.com'],
|
||||||
}, certificateKey);
|
}, certificateKey);
|
||||||
|
```
|
||||||
<a name="createAlpnCertificate"></a>
|
<a name="createAlpnCertificate"></a>
|
||||||
|
|
||||||
## createAlpnCertificate(authz, keyAuthorization, [keyPem]) ⇒ <code>Promise.<Array.<buffer>></code>
|
## createAlpnCertificate(authz, keyAuthorization, [keyPem]) ⇒ <code>Promise.<Array.<buffer>></code>
|
||||||
@@ -298,6 +300,7 @@ Create a ALPN certificate with ECDSA private key
|
|||||||
```js
|
```js
|
||||||
const alpnKey = await acme.crypto.createPrivateEcdsaKey();
|
const alpnKey = await acme.crypto.createPrivateEcdsaKey();
|
||||||
const [, alpnCertificate] = await acme.crypto.createAlpnCertificate(authz, keyAuthorization, alpnKey);
|
const [, alpnCertificate] = await acme.crypto.createAlpnCertificate(authz, keyAuthorization, alpnKey);
|
||||||
|
```
|
||||||
<a name="isAlpnCertificateAuthorizationValid"></a>
|
<a name="isAlpnCertificateAuthorizationValid"></a>
|
||||||
|
|
||||||
## isAlpnCertificateAuthorizationValid(certPem, keyAuthorization) ⇒ <code>boolean</code>
|
## isAlpnCertificateAuthorizationValid(certPem, keyAuthorization) ⇒ <code>boolean</code>
|
||||||
|
|||||||
@@ -222,29 +222,30 @@ Create a Certificate Signing Request
|
|||||||
Create a Certificate Signing Request
|
Create a Certificate Signing Request
|
||||||
```js
|
```js
|
||||||
const [certificateKey, certificateRequest] = await acme.forge.createCsr({
|
const [certificateKey, certificateRequest] = await acme.forge.createCsr({
|
||||||
commonName: 'test.example.com'
|
altNames: ['test.example.com'],
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
**Example**
|
**Example**
|
||||||
Certificate Signing Request with both common and alternative names
|
Certificate Signing Request with both common and alternative names
|
||||||
|
> *Warning*: Certificate subject common name has been [deprecated](https://letsencrypt.org/docs/glossary/#def-CN) and its use is [discouraged](https://cabforum.org/uploads/BRv1.2.3.pdf).
|
||||||
```js
|
```js
|
||||||
const [certificateKey, certificateRequest] = await acme.forge.createCsr({
|
const [certificateKey, certificateRequest] = await acme.forge.createCsr({
|
||||||
keySize: 4096,
|
keySize: 4096,
|
||||||
commonName: 'test.example.com',
|
commonName: 'test.example.com',
|
||||||
altNames: ['foo.example.com', 'bar.example.com']
|
altNames: ['foo.example.com', 'bar.example.com'],
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
**Example**
|
**Example**
|
||||||
Certificate Signing Request with additional information
|
Certificate Signing Request with additional information
|
||||||
```js
|
```js
|
||||||
const [certificateKey, certificateRequest] = await acme.forge.createCsr({
|
const [certificateKey, certificateRequest] = await acme.forge.createCsr({
|
||||||
commonName: 'test.example.com',
|
altNames: ['test.example.com'],
|
||||||
country: 'US',
|
country: 'US',
|
||||||
state: 'California',
|
state: 'California',
|
||||||
locality: 'Los Angeles',
|
locality: 'Los Angeles',
|
||||||
organization: 'The Company Inc.',
|
organization: 'The Company Inc.',
|
||||||
organizationUnit: 'IT Department',
|
organizationUnit: 'IT Department',
|
||||||
emailAddress: 'contact@example.com'
|
emailAddress: 'contact@example.com',
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
**Example**
|
**Example**
|
||||||
@@ -253,5 +254,5 @@ Certificate Signing Request with predefined private key
|
|||||||
const certificateKey = await acme.forge.createPrivateKey();
|
const certificateKey = await acme.forge.createPrivateKey();
|
||||||
|
|
||||||
const [, certificateRequest] = await acme.forge.createCsr({
|
const [, certificateRequest] = await acme.forge.createCsr({
|
||||||
commonName: 'test.example.com'
|
altNames: ['test.example.com'],
|
||||||
}, certificateKey);
|
}, certificateKey);
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ function log(m) {
|
|||||||
process.stdout.write(`${m}\n`);
|
process.stdout.write(`${m}\n`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function used to satisfy an ACME challenge
|
* Function used to satisfy an ACME challenge
|
||||||
*
|
*
|
||||||
@@ -25,7 +24,6 @@ async function challengeCreateFn(authz, challenge, keyAuthorization) {
|
|||||||
log(keyAuthorization);
|
log(keyAuthorization);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function used to remove an ACME challenge response
|
* Function used to remove an ACME challenge response
|
||||||
*
|
*
|
||||||
@@ -41,30 +39,29 @@ async function challengeRemoveFn(authz, challenge, keyAuthorization) {
|
|||||||
log(keyAuthorization);
|
log(keyAuthorization);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main
|
* Main
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = async function() {
|
module.exports = async () => {
|
||||||
/* Init client */
|
/* Init client */
|
||||||
const client = new acme.Client({
|
const client = new acme.Client({
|
||||||
directoryUrl: acme.directory.letsencrypt.staging,
|
directoryUrl: acme.directory.letsencrypt.staging,
|
||||||
accountKey: await acme.crypto.createPrivateKey()
|
accountKey: await acme.crypto.createPrivateKey(),
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Register account */
|
/* Register account */
|
||||||
await client.createAccount({
|
await client.createAccount({
|
||||||
termsOfServiceAgreed: true,
|
termsOfServiceAgreed: true,
|
||||||
contact: ['mailto:test@example.com']
|
contact: ['mailto:test@example.com'],
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Place new order */
|
/* Place new order */
|
||||||
const order = await client.createOrder({
|
const order = await client.createOrder({
|
||||||
identifiers: [
|
identifiers: [
|
||||||
{ type: 'dns', value: 'example.com' },
|
{ type: 'dns', value: 'example.com' },
|
||||||
{ type: 'dns', value: '*.example.com' }
|
{ type: 'dns', value: '*.example.com' },
|
||||||
]
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -138,8 +135,7 @@ module.exports = async function() {
|
|||||||
|
|
||||||
/* Finalize order */
|
/* Finalize order */
|
||||||
const [key, csr] = await acme.crypto.createCsr({
|
const [key, csr] = await acme.crypto.createCsr({
|
||||||
commonName: '*.example.com',
|
altNames: ['example.com', '*.example.com'],
|
||||||
altNames: ['example.com']
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const finalized = await client.finalizeOrder(order, csr);
|
const finalized = await client.finalizeOrder(order, csr);
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ function log(m) {
|
|||||||
process.stdout.write(`${m}\n`);
|
process.stdout.write(`${m}\n`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function used to satisfy an ACME challenge
|
* Function used to satisfy an ACME challenge
|
||||||
*
|
*
|
||||||
@@ -47,7 +46,6 @@ async function challengeCreateFn(authz, challenge, keyAuthorization) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function used to remove an ACME challenge response
|
* Function used to remove an ACME challenge response
|
||||||
*
|
*
|
||||||
@@ -80,25 +78,24 @@ async function challengeRemoveFn(authz, challenge, keyAuthorization) {
|
|||||||
|
|
||||||
/* Replace this */
|
/* Replace this */
|
||||||
log(`Would remove TXT record "${dnsRecord}" with value "${recordValue}"`);
|
log(`Would remove TXT record "${dnsRecord}" with value "${recordValue}"`);
|
||||||
// await dnsProvider.removeRecord(dnsRecord, 'TXT');
|
// await dnsProvider.removeRecord(dnsRecord, 'TXT', recordValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main
|
* Main
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = async function() {
|
module.exports = async () => {
|
||||||
/* Init client */
|
/* Init client */
|
||||||
const client = new acme.Client({
|
const client = new acme.Client({
|
||||||
directoryUrl: acme.directory.letsencrypt.staging,
|
directoryUrl: acme.directory.letsencrypt.staging,
|
||||||
accountKey: await acme.crypto.createPrivateKey()
|
accountKey: await acme.crypto.createPrivateKey(),
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Create CSR */
|
/* Create CSR */
|
||||||
const [key, csr] = await acme.crypto.createCsr({
|
const [key, csr] = await acme.crypto.createCsr({
|
||||||
commonName: 'example.com'
|
altNames: ['example.com'],
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Certificate */
|
/* Certificate */
|
||||||
@@ -107,7 +104,7 @@ module.exports = async function() {
|
|||||||
email: 'test@example.com',
|
email: 'test@example.com',
|
||||||
termsOfServiceAgreed: true,
|
termsOfServiceAgreed: true,
|
||||||
challengeCreateFn,
|
challengeCreateFn,
|
||||||
challengeRemoveFn
|
challengeRemoveFn,
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Done */
|
/* Done */
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ function log(m) {
|
|||||||
process.stdout.write(`${(new Date()).toISOString()} ${m}\n`);
|
process.stdout.write(`${(new Date()).toISOString()} ${m}\n`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main
|
* Main
|
||||||
*/
|
*/
|
||||||
@@ -33,18 +32,16 @@ function log(m) {
|
|||||||
log('Initializing ACME client');
|
log('Initializing ACME client');
|
||||||
const client = new acme.Client({
|
const client = new acme.Client({
|
||||||
directoryUrl: acme.directory.letsencrypt.staging,
|
directoryUrl: acme.directory.letsencrypt.staging,
|
||||||
accountKey: await acme.crypto.createPrivateKey()
|
accountKey: await acme.crypto.createPrivateKey(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Order wildcard certificate
|
* Order wildcard certificate
|
||||||
*/
|
*/
|
||||||
|
|
||||||
log(`Creating CSR for ${WILDCARD_DOMAIN}`);
|
log(`Creating CSR for ${WILDCARD_DOMAIN}`);
|
||||||
const [key, csr] = await acme.crypto.createCsr({
|
const [key, csr] = await acme.crypto.createCsr({
|
||||||
commonName: WILDCARD_DOMAIN,
|
altNames: [WILDCARD_DOMAIN, `*.${WILDCARD_DOMAIN}`],
|
||||||
altNames: [`*.${WILDCARD_DOMAIN}`]
|
|
||||||
});
|
});
|
||||||
|
|
||||||
log(`Ordering certificate for ${WILDCARD_DOMAIN}`);
|
log(`Ordering certificate for ${WILDCARD_DOMAIN}`);
|
||||||
@@ -60,12 +57,11 @@ function log(m) {
|
|||||||
challengeRemoveFn: (authz, challenge, keyAuthorization) => {
|
challengeRemoveFn: (authz, challenge, keyAuthorization) => {
|
||||||
/* TODO: Implement this */
|
/* TODO: Implement this */
|
||||||
log(`[TODO] Remove TXT record key=_acme-challenge.${authz.identifier.value} value=${keyAuthorization}`);
|
log(`[TODO] Remove TXT record key=_acme-challenge.${authz.identifier.value} value=${keyAuthorization}`);
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
log(`Certificate for ${WILDCARD_DOMAIN} created successfully`);
|
log(`Certificate for ${WILDCARD_DOMAIN} created successfully`);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTPS server
|
* HTTPS server
|
||||||
*/
|
*/
|
||||||
@@ -78,7 +74,7 @@ function log(m) {
|
|||||||
|
|
||||||
const httpsServer = https.createServer({
|
const httpsServer = https.createServer({
|
||||||
key,
|
key,
|
||||||
cert
|
cert,
|
||||||
}, requestListener);
|
}, requestListener);
|
||||||
|
|
||||||
httpsServer.listen(HTTPS_SERVER_PORT, () => {
|
httpsServer.listen(HTTPS_SERVER_PORT, () => {
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ function log(m) {
|
|||||||
process.stdout.write(`${(new Date()).toISOString()} ${m}\n`);
|
process.stdout.write(`${(new Date()).toISOString()} ${m}\n`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On-demand certificate generation using http-01
|
* On-demand certificate generation using http-01
|
||||||
*/
|
*/
|
||||||
@@ -52,7 +51,7 @@ async function getCertOnDemand(client, servername, attempt = 0) {
|
|||||||
/* Create CSR */
|
/* Create CSR */
|
||||||
log(`Creating CSR for ${servername}`);
|
log(`Creating CSR for ${servername}`);
|
||||||
const [key, csr] = await acme.crypto.createCsr({
|
const [key, csr] = await acme.crypto.createCsr({
|
||||||
commonName: servername
|
altNames: [servername],
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Order certificate */
|
/* Order certificate */
|
||||||
@@ -67,7 +66,7 @@ async function getCertOnDemand(client, servername, attempt = 0) {
|
|||||||
},
|
},
|
||||||
challengeRemoveFn: (authz, challenge) => {
|
challengeRemoveFn: (authz, challenge) => {
|
||||||
delete challengeResponses[challenge.token];
|
delete challengeResponses[challenge.token];
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Done, store certificate */
|
/* Done, store certificate */
|
||||||
@@ -77,7 +76,6 @@ async function getCertOnDemand(client, servername, attempt = 0) {
|
|||||||
return certificateStore[servername];
|
return certificateStore[servername];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main
|
* Main
|
||||||
*/
|
*/
|
||||||
@@ -91,10 +89,9 @@ async function getCertOnDemand(client, servername, attempt = 0) {
|
|||||||
log('Initializing ACME client');
|
log('Initializing ACME client');
|
||||||
const client = new acme.Client({
|
const client = new acme.Client({
|
||||||
directoryUrl: acme.directory.letsencrypt.staging,
|
directoryUrl: acme.directory.letsencrypt.staging,
|
||||||
accountKey: await acme.crypto.createPrivateKey()
|
accountKey: await acme.crypto.createPrivateKey(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP server
|
* HTTP server
|
||||||
*/
|
*/
|
||||||
@@ -129,7 +126,6 @@ async function getCertOnDemand(client, servername, attempt = 0) {
|
|||||||
log(`HTTP server listening on port ${HTTP_SERVER_PORT}`);
|
log(`HTTP server listening on port ${HTTP_SERVER_PORT}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTPS server
|
* HTTPS server
|
||||||
*/
|
*/
|
||||||
@@ -158,7 +154,7 @@ async function getCertOnDemand(client, servername, attempt = 0) {
|
|||||||
log(`[ERROR] ${e.message}`);
|
log(`[ERROR] ${e.message}`);
|
||||||
cb(e.message);
|
cb(e.message);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}, requestListener);
|
}, requestListener);
|
||||||
|
|
||||||
httpsServer.listen(HTTPS_SERVER_PORT, () => {
|
httpsServer.listen(HTTPS_SERVER_PORT, () => {
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ function log(m) {
|
|||||||
process.stdout.write(`${(new Date()).toISOString()} ${m}\n`);
|
process.stdout.write(`${(new Date()).toISOString()} ${m}\n`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On-demand certificate generation using tls-alpn-01
|
* On-demand certificate generation using tls-alpn-01
|
||||||
*/
|
*/
|
||||||
@@ -51,7 +50,7 @@ async function getCertOnDemand(client, servername, attempt = 0) {
|
|||||||
/* Create CSR */
|
/* Create CSR */
|
||||||
log(`Creating CSR for ${servername}`);
|
log(`Creating CSR for ${servername}`);
|
||||||
const [key, csr] = await acme.crypto.createCsr({
|
const [key, csr] = await acme.crypto.createCsr({
|
||||||
commonName: servername
|
altNames: [servername],
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Order certificate */
|
/* Order certificate */
|
||||||
@@ -66,7 +65,7 @@ async function getCertOnDemand(client, servername, attempt = 0) {
|
|||||||
},
|
},
|
||||||
challengeRemoveFn: (authz) => {
|
challengeRemoveFn: (authz) => {
|
||||||
delete alpnResponses[authz.identifier.value];
|
delete alpnResponses[authz.identifier.value];
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Done, store certificate */
|
/* Done, store certificate */
|
||||||
@@ -76,7 +75,6 @@ async function getCertOnDemand(client, servername, attempt = 0) {
|
|||||||
return certificateStore[servername];
|
return certificateStore[servername];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main
|
* Main
|
||||||
*/
|
*/
|
||||||
@@ -90,10 +88,9 @@ async function getCertOnDemand(client, servername, attempt = 0) {
|
|||||||
log('Initializing ACME client');
|
log('Initializing ACME client');
|
||||||
const client = new acme.Client({
|
const client = new acme.Client({
|
||||||
directoryUrl: acme.directory.letsencrypt.staging,
|
directoryUrl: acme.directory.letsencrypt.staging,
|
||||||
accountKey: await acme.crypto.createPrivateKey()
|
accountKey: await acme.crypto.createPrivateKey(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ALPN responder
|
* ALPN responder
|
||||||
*/
|
*/
|
||||||
@@ -118,14 +115,14 @@ async function getCertOnDemand(client, servername, attempt = 0) {
|
|||||||
log(`Found ALPN certificate for ${servername}, serving secure context`);
|
log(`Found ALPN certificate for ${servername}, serving secure context`);
|
||||||
cb(null, tls.createSecureContext({
|
cb(null, tls.createSecureContext({
|
||||||
key: alpnResponses[servername][0],
|
key: alpnResponses[servername][0],
|
||||||
cert: alpnResponses[servername][1]
|
cert: alpnResponses[servername][1],
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
log(`[ERROR] ${e.message}`);
|
log(`[ERROR] ${e.message}`);
|
||||||
cb(e.message);
|
cb(e.message);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Terminate once TLS handshake has been established */
|
/* Terminate once TLS handshake has been established */
|
||||||
@@ -137,7 +134,6 @@ async function getCertOnDemand(client, servername, attempt = 0) {
|
|||||||
log(`ALPN responder listening on port ${ALPN_RESPONDER_PORT}`);
|
log(`ALPN responder listening on port ${ALPN_RESPONDER_PORT}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTPS server
|
* HTTPS server
|
||||||
*/
|
*/
|
||||||
@@ -166,7 +162,7 @@ async function getCertOnDemand(client, servername, attempt = 0) {
|
|||||||
log(`[ERROR] ${e.message}`);
|
log(`[ERROR] ${e.message}`);
|
||||||
cb(e.message);
|
cb(e.message);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}, requestListener);
|
}, requestListener);
|
||||||
|
|
||||||
httpsServer.listen(HTTPS_SERVER_PORT, () => {
|
httpsServer.listen(HTTPS_SERVER_PORT, () => {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"description": "Simple and unopinionated ACME client",
|
"description": "Simple and unopinionated ACME client",
|
||||||
"private": false,
|
"private": false,
|
||||||
"author": "nmorsman",
|
"author": "nmorsman",
|
||||||
"version": "1.20.8",
|
"version": "1.21.0",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"types": "types/index.d.ts",
|
"types": "types/index.d.ts",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -16,24 +16,24 @@
|
|||||||
"types"
|
"types"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@peculiar/x509": "^1.9.7",
|
"@peculiar/x509": "^1.10.0",
|
||||||
"asn1js": "^3.0.5",
|
"asn1js": "^3.0.5",
|
||||||
"axios": "^1.6.5",
|
"axios": "^1.7.2",
|
||||||
"debug": "^4.1.1",
|
"debug": "^4.1.1",
|
||||||
"https-proxy-agent": "^7.0.4",
|
"https-proxy-agent": "^7.0.4",
|
||||||
"node-forge": "^1.3.1"
|
"node-forge": "^1.3.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20.11.5",
|
"@types/node": "^20.12.12",
|
||||||
"chai": "^4.4.1",
|
"chai": "^4.4.1",
|
||||||
"chai-as-promised": "^7.1.1",
|
"chai-as-promised": "^7.1.2",
|
||||||
"eslint": "^8.56.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-airbnb-base": "^15.0.0",
|
"eslint-config-airbnb-base": "^15.0.0",
|
||||||
"eslint-plugin-import": "^2.29.1",
|
"eslint-plugin-import": "^2.29.1",
|
||||||
"jsdoc-to-markdown": "^8.0.0",
|
"jsdoc-to-markdown": "^8.0.1",
|
||||||
"mocha": "^10.2.0",
|
"mocha": "^10.4.0",
|
||||||
"nock": "^13.5.0",
|
"nock": "^13.5.4",
|
||||||
"tsd": "^0.30.4",
|
"tsd": "^0.31.0",
|
||||||
"typescript": "^4.8.4",
|
"typescript": "^4.8.4",
|
||||||
"uuid": "^8.3.2"
|
"uuid": "^8.3.2"
|
||||||
},
|
},
|
||||||
@@ -59,5 +59,5 @@
|
|||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/publishlab/node-acme-client/issues"
|
"url": "https://github.com/publishlab/node-acme-client/issues"
|
||||||
},
|
},
|
||||||
"gitHead": "b258e926209fef4cc4d633b0383eb54e26c516f9"
|
"gitHead": "a31f1c7f5e71fa946de9bf0283e11d6ce049b3e9"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
const util = require('./util');
|
const util = require('./util');
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AcmeApi
|
* AcmeApi
|
||||||
*
|
*
|
||||||
@@ -18,7 +17,6 @@ class AcmeApi {
|
|||||||
this.accountUrl = accountUrl;
|
this.accountUrl = accountUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get account URL
|
* Get account URL
|
||||||
*
|
*
|
||||||
@@ -34,7 +32,6 @@ class AcmeApi {
|
|||||||
return this.accountUrl;
|
return this.accountUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ACME API request
|
* ACME API request
|
||||||
*
|
*
|
||||||
@@ -59,7 +56,6 @@ class AcmeApi {
|
|||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ACME API request by resource name helper
|
* ACME API request by resource name helper
|
||||||
*
|
*
|
||||||
@@ -78,7 +74,6 @@ class AcmeApi {
|
|||||||
return this.apiRequest(resourceUrl, payload, validStatusCodes, { includeJwsKid, includeExternalAccountBinding });
|
return this.apiRequest(resourceUrl, payload, validStatusCodes, { includeJwsKid, includeExternalAccountBinding });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Terms of Service URL if available
|
* Get Terms of Service URL if available
|
||||||
*
|
*
|
||||||
@@ -91,7 +86,6 @@ class AcmeApi {
|
|||||||
return this.http.getMetaField('termsOfService');
|
return this.http.getMetaField('termsOfService');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new account
|
* Create new account
|
||||||
*
|
*
|
||||||
@@ -104,7 +98,7 @@ class AcmeApi {
|
|||||||
async createAccount(data) {
|
async createAccount(data) {
|
||||||
const resp = await this.apiResourceRequest('newAccount', data, [200, 201], {
|
const resp = await this.apiResourceRequest('newAccount', data, [200, 201], {
|
||||||
includeJwsKid: false,
|
includeJwsKid: false,
|
||||||
includeExternalAccountBinding: (data.onlyReturnExisting !== true)
|
includeExternalAccountBinding: (data.onlyReturnExisting !== true),
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Set account URL */
|
/* Set account URL */
|
||||||
@@ -115,7 +109,6 @@ class AcmeApi {
|
|||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update account
|
* Update account
|
||||||
*
|
*
|
||||||
@@ -129,7 +122,6 @@ class AcmeApi {
|
|||||||
return this.apiRequest(this.getAccountUrl(), data, [200, 202]);
|
return this.apiRequest(this.getAccountUrl(), data, [200, 202]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update account key
|
* Update account key
|
||||||
*
|
*
|
||||||
@@ -143,7 +135,6 @@ class AcmeApi {
|
|||||||
return this.apiResourceRequest('keyChange', data, [200]);
|
return this.apiResourceRequest('keyChange', data, [200]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new order
|
* Create new order
|
||||||
*
|
*
|
||||||
@@ -157,7 +148,6 @@ class AcmeApi {
|
|||||||
return this.apiResourceRequest('newOrder', data, [201]);
|
return this.apiResourceRequest('newOrder', data, [201]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get order
|
* Get order
|
||||||
*
|
*
|
||||||
@@ -171,7 +161,6 @@ class AcmeApi {
|
|||||||
return this.apiRequest(url, null, [200]);
|
return this.apiRequest(url, null, [200]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finalize order
|
* Finalize order
|
||||||
*
|
*
|
||||||
@@ -186,7 +175,6 @@ class AcmeApi {
|
|||||||
return this.apiRequest(url, data, [200]);
|
return this.apiRequest(url, data, [200]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get identifier authorization
|
* Get identifier authorization
|
||||||
*
|
*
|
||||||
@@ -200,7 +188,6 @@ class AcmeApi {
|
|||||||
return this.apiRequest(url, null, [200]);
|
return this.apiRequest(url, null, [200]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update identifier authorization
|
* Update identifier authorization
|
||||||
*
|
*
|
||||||
@@ -215,7 +202,6 @@ class AcmeApi {
|
|||||||
return this.apiRequest(url, data, [200]);
|
return this.apiRequest(url, data, [200]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Complete challenge
|
* Complete challenge
|
||||||
*
|
*
|
||||||
@@ -230,7 +216,6 @@ class AcmeApi {
|
|||||||
return this.apiRequest(url, data, [200]);
|
return this.apiRequest(url, data, [200]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Revoke certificate
|
* Revoke certificate
|
||||||
*
|
*
|
||||||
@@ -245,6 +230,5 @@ class AcmeApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Export API */
|
/* Export API */
|
||||||
module.exports = AcmeApi;
|
module.exports = AcmeApi;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
const { readCsrDomains } = require('./crypto');
|
const { readCsrDomains } = require('./crypto');
|
||||||
const { log } = require('./logger');
|
const { log } = require('./logger');
|
||||||
|
const { wait } = require('./wait');
|
||||||
|
|
||||||
const defaultOpts = {
|
const defaultOpts = {
|
||||||
csr: null,
|
csr: null,
|
||||||
@@ -13,10 +14,9 @@ const defaultOpts = {
|
|||||||
skipChallengeVerification: false,
|
skipChallengeVerification: false,
|
||||||
challengePriority: ['http-01', 'dns-01'],
|
challengePriority: ['http-01', 'dns-01'],
|
||||||
challengeCreateFn: async () => { throw new Error('Missing challengeCreateFn()'); },
|
challengeCreateFn: async () => { throw new Error('Missing challengeCreateFn()'); },
|
||||||
challengeRemoveFn: async () => { throw new Error('Missing challengeRemoveFn()'); }
|
challengeRemoveFn: async () => { throw new Error('Missing challengeRemoveFn()'); },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ACME client auto mode
|
* ACME client auto mode
|
||||||
*
|
*
|
||||||
@@ -25,8 +25,8 @@ const defaultOpts = {
|
|||||||
* @returns {Promise<buffer>} Certificate
|
* @returns {Promise<buffer>} Certificate
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = async function(client, userOpts) {
|
module.exports = async (client, userOpts) => {
|
||||||
const opts = Object.assign({}, defaultOpts, userOpts);
|
const opts = { ...defaultOpts, ...userOpts };
|
||||||
const accountPayload = { termsOfServiceAgreed: opts.termsOfServiceAgreed };
|
const accountPayload = { termsOfServiceAgreed: opts.termsOfServiceAgreed };
|
||||||
|
|
||||||
if (!Buffer.isBuffer(opts.csr)) {
|
if (!Buffer.isBuffer(opts.csr)) {
|
||||||
@@ -36,7 +36,9 @@ module.exports = async function(client, userOpts) {
|
|||||||
if (opts.email) {
|
if (opts.email) {
|
||||||
accountPayload.contact = [`mailto:${opts.email}`];
|
accountPayload.contact = [`mailto:${opts.email}`];
|
||||||
}
|
}
|
||||||
|
if (opts.externalAccountBinding) {
|
||||||
|
accountPayload.externalAccountBinding = opts.externalAccountBinding;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register account
|
* Register account
|
||||||
@@ -53,19 +55,16 @@ module.exports = async function(client, userOpts) {
|
|||||||
await client.createAccount(accountPayload);
|
await client.createAccount(accountPayload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse domains from CSR
|
* Parse domains from CSR
|
||||||
*/
|
*/
|
||||||
|
|
||||||
log('[auto] Parsing domains from Certificate Signing Request');
|
log('[auto] Parsing domains from Certificate Signing Request');
|
||||||
const csrDomains = readCsrDomains(opts.csr);
|
const { commonName, altNames } = readCsrDomains(opts.csr);
|
||||||
const domains = [csrDomains.commonName].concat(csrDomains.altNames);
|
const uniqueDomains = Array.from(new Set([commonName].concat(altNames).filter((d) => d)));
|
||||||
const uniqueDomains = Array.from(new Set(domains));
|
|
||||||
|
|
||||||
log(`[auto] Resolved ${uniqueDomains.length} unique domains from parsing the Certificate Signing Request`);
|
log(`[auto] Resolved ${uniqueDomains.length} unique domains from parsing the Certificate Signing Request`);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Place order
|
* Place order
|
||||||
*/
|
*/
|
||||||
@@ -77,7 +76,6 @@ module.exports = async function(client, userOpts) {
|
|||||||
|
|
||||||
log(`[auto] Placed certificate order successfully, received ${authorizations.length} identity authorizations`);
|
log(`[auto] Placed certificate order successfully, received ${authorizations.length} identity authorizations`);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve and satisfy challenges
|
* Resolve and satisfy challenges
|
||||||
*/
|
*/
|
||||||
@@ -119,10 +117,23 @@ module.exports = async function(client, userOpts) {
|
|||||||
let recordItem = null;
|
let recordItem = null;
|
||||||
try {
|
try {
|
||||||
recordItem = await opts.challengeCreateFn(authz, challenge, keyAuthorization);
|
recordItem = await opts.challengeCreateFn(authz, challenge, keyAuthorization);
|
||||||
|
log(`[auto] [${d}] challengeCreateFn success`);
|
||||||
|
log(`[auto] [${d}] add challengeRemoveFn()`);
|
||||||
|
clearTasks.push(async () => {
|
||||||
|
/* Trigger challengeRemoveFn(), suppress errors */
|
||||||
|
log(`[auto] [${d}] Trigger challengeRemoveFn()`);
|
||||||
|
try {
|
||||||
|
await opts.challengeRemoveFn(authz, challenge, keyAuthorization, recordItem);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
log(`[auto] [${d}] challengeRemoveFn threw error: ${e.message}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// throw new Error('测试异常');
|
||||||
/* Challenge verification */
|
/* Challenge verification */
|
||||||
if (opts.skipChallengeVerification === true) {
|
if (opts.skipChallengeVerification === true) {
|
||||||
log(`[auto] [${d}] Skipping challenge verification since skipChallengeVerification=true`);
|
log(`[auto] [${d}] Skipping challenge verification since skipChallengeVerification=true,wait 60s`);
|
||||||
|
await wait(60 * 1000);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
log(`[auto] [${d}] Running challenge verification`);
|
log(`[auto] [${d}] Running challenge verification`);
|
||||||
@@ -140,19 +151,6 @@ module.exports = async function(client, userOpts) {
|
|||||||
log(`[auto] [${d}] challengeCreateFn threw error: ${e.message}`);
|
log(`[auto] [${d}] challengeCreateFn threw error: ${e.message}`);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
log(`[auto] [${d}] add challengeRemoveFn()`);
|
|
||||||
clearTasks.push(async () => {
|
|
||||||
/* Trigger challengeRemoveFn(), suppress errors */
|
|
||||||
log(`[auto] [${d}] Trigger challengeRemoveFn()`);
|
|
||||||
try {
|
|
||||||
await opts.challengeRemoveFn(authz, challenge, keyAuthorization, recordItem);
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
log(`[auto] [${d}] challengeRemoveFn threw error: ${e.message}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
/* Deactivate pending authz when unable to complete challenge */
|
/* Deactivate pending authz when unable to complete challenge */
|
||||||
@@ -177,21 +175,56 @@ module.exports = async function(client, userOpts) {
|
|||||||
await challengeFunc(authz);
|
await challengeFunc(authz);
|
||||||
});
|
});
|
||||||
|
|
||||||
log('开始challenge');
|
function runAllPromise(tasks) {
|
||||||
let promise = Promise.resolve();
|
let promise = Promise.resolve();
|
||||||
function runPromisesSerially(tasks) {
|
|
||||||
tasks.forEach((task) => {
|
tasks.forEach((task) => {
|
||||||
promise = promise.then(task);
|
promise = promise.then(task);
|
||||||
});
|
});
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function runPromisePa(tasks) {
|
||||||
|
const results = [];
|
||||||
|
// eslint-disable-next-line no-await-in-loop,no-restricted-syntax
|
||||||
|
for (const task of tasks) {
|
||||||
|
results.push(task());
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
await wait(10000);
|
||||||
|
}
|
||||||
|
return Promise.all(results);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await runPromisesSerially(challengePromises);
|
log('开始challenge');
|
||||||
|
await runPromisePa(challengePromises);
|
||||||
|
|
||||||
|
log('challenge结束');
|
||||||
|
|
||||||
|
// log('[auto] Waiting for challenge valid status');
|
||||||
|
// await Promise.all(challengePromises);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finalize order and download certificate
|
||||||
|
*/
|
||||||
|
|
||||||
|
log('[auto] Finalizing order and downloading certificate');
|
||||||
|
const finalized = await client.finalizeOrder(order, opts.csr);
|
||||||
|
return await client.getCertificate(finalized, opts.preferredChain);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
log('证书申请失败');
|
||||||
|
log(e);
|
||||||
|
throw new Error(`证书申请失败:${e.message}`);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
await runPromisesSerially(clearTasks);
|
log(`清理challenge痕迹,length:${clearTasks.length}`);
|
||||||
|
try {
|
||||||
|
await runAllPromise(clearTasks);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
log('清理challenge失败');
|
||||||
|
log(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// try {
|
// try {
|
||||||
@@ -201,19 +234,4 @@ module.exports = async function(client, userOpts) {
|
|||||||
// log('清理challenge');
|
// log('清理challenge');
|
||||||
// await Promise.allSettled(clearTasks);
|
// await Promise.allSettled(clearTasks);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
log('challenge结束');
|
|
||||||
|
|
||||||
// log('[auto] Waiting for challenge valid status');
|
|
||||||
// await Promise.all(challengePromises);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finalize order and download certificate
|
|
||||||
*/
|
|
||||||
|
|
||||||
log('[auto] Finalizing order and downloading certificate');
|
|
||||||
const finalized = await client.finalizeOrder(order, opts.csr);
|
|
||||||
return client.getCertificate(finalized, opts.preferredChain);
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
const pkg = require('./../package.json');
|
const pkg = require('./../package.json');
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instance
|
* Instance
|
||||||
*/
|
*/
|
||||||
@@ -19,9 +18,8 @@ instance.defaults.headers.common['User-Agent'] = `node-${pkg.name}/${pkg.version
|
|||||||
instance.defaults.acmeSettings = {
|
instance.defaults.acmeSettings = {
|
||||||
httpChallengePort: 80,
|
httpChallengePort: 80,
|
||||||
httpsChallengePort: 443,
|
httpsChallengePort: 443,
|
||||||
tlsAlpnChallengePort: 443
|
tlsAlpnChallengePort: 443,
|
||||||
};
|
};
|
||||||
|
|
||||||
// instance.defaults.proxy = {
|
// instance.defaults.proxy = {
|
||||||
// host: '192.168.34.139',
|
// host: '192.168.34.139',
|
||||||
// port: 10811
|
// port: 10811
|
||||||
@@ -35,7 +33,6 @@ instance.defaults.acmeSettings = {
|
|||||||
|
|
||||||
instance.defaults.adapter = 'http';
|
instance.defaults.adapter = 'http';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Export instance
|
* Export instance
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ const verify = require('./verify');
|
|||||||
const util = require('./util');
|
const util = require('./util');
|
||||||
const auto = require('./auto');
|
const auto = require('./auto');
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ACME states
|
* ACME states
|
||||||
*
|
*
|
||||||
@@ -24,7 +23,6 @@ const validStates = ['ready', 'valid'];
|
|||||||
const pendingStates = ['pending', 'processing'];
|
const pendingStates = ['pending', 'processing'];
|
||||||
const invalidStates = ['invalid'];
|
const invalidStates = ['invalid'];
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default options
|
* Default options
|
||||||
*
|
*
|
||||||
@@ -38,10 +36,9 @@ const defaultOpts = {
|
|||||||
externalAccountBinding: {},
|
externalAccountBinding: {},
|
||||||
backoffAttempts: 10,
|
backoffAttempts: 10,
|
||||||
backoffMin: 5000,
|
backoffMin: 5000,
|
||||||
backoffMax: 30000
|
backoffMax: 30000,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AcmeClient
|
* AcmeClient
|
||||||
*
|
*
|
||||||
@@ -61,7 +58,7 @@ const defaultOpts = {
|
|||||||
* ```js
|
* ```js
|
||||||
* const client = new acme.Client({
|
* const client = new acme.Client({
|
||||||
* directoryUrl: acme.directory.letsencrypt.staging,
|
* directoryUrl: acme.directory.letsencrypt.staging,
|
||||||
* accountKey: 'Private key goes here'
|
* accountKey: 'Private key goes here',
|
||||||
* });
|
* });
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
@@ -73,7 +70,7 @@ const defaultOpts = {
|
|||||||
* accountUrl: 'Optional account URL goes here',
|
* accountUrl: 'Optional account URL goes here',
|
||||||
* backoffAttempts: 10,
|
* backoffAttempts: 10,
|
||||||
* backoffMin: 5000,
|
* backoffMin: 5000,
|
||||||
* backoffMax: 30000
|
* backoffMax: 30000,
|
||||||
* });
|
* });
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
@@ -84,8 +81,8 @@ const defaultOpts = {
|
|||||||
* accountKey: 'Private key goes here',
|
* accountKey: 'Private key goes here',
|
||||||
* externalAccountBinding: {
|
* externalAccountBinding: {
|
||||||
* kid: 'YOUR-EAB-KID',
|
* kid: 'YOUR-EAB-KID',
|
||||||
* hmacKey: 'YOUR-EAB-HMAC-KEY'
|
* hmacKey: 'YOUR-EAB-HMAC-KEY',
|
||||||
* }
|
* },
|
||||||
* });
|
* });
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
@@ -96,19 +93,17 @@ class AcmeClient {
|
|||||||
opts.accountKey = Buffer.from(opts.accountKey);
|
opts.accountKey = Buffer.from(opts.accountKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.opts = Object.assign({}, defaultOpts, opts);
|
this.opts = { ...defaultOpts, ...opts };
|
||||||
|
|
||||||
this.backoffOpts = {
|
this.backoffOpts = {
|
||||||
attempts: this.opts.backoffAttempts,
|
attempts: this.opts.backoffAttempts,
|
||||||
min: this.opts.backoffMin,
|
min: this.opts.backoffMin,
|
||||||
max: this.opts.backoffMax
|
max: this.opts.backoffMax,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.http = new HttpClient(this.opts.directoryUrl, this.opts.accountKey, this.opts.externalAccountBinding);
|
this.http = new HttpClient(this.opts.directoryUrl, this.opts.accountKey, this.opts.externalAccountBinding);
|
||||||
this.api = new AcmeApi(this.http, this.opts.accountUrl);
|
this.api = new AcmeApi(this.http, this.opts.accountUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Terms of Service URL if available
|
* Get Terms of Service URL if available
|
||||||
*
|
*
|
||||||
@@ -128,7 +123,6 @@ class AcmeClient {
|
|||||||
return this.api.getTermsOfServiceUrl();
|
return this.api.getTermsOfServiceUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get current account URL
|
* Get current account URL
|
||||||
*
|
*
|
||||||
@@ -150,7 +144,6 @@ class AcmeClient {
|
|||||||
return this.api.getAccountUrl();
|
return this.api.getAccountUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new account
|
* Create a new account
|
||||||
*
|
*
|
||||||
@@ -162,7 +155,7 @@ class AcmeClient {
|
|||||||
* @example Create a new account
|
* @example Create a new account
|
||||||
* ```js
|
* ```js
|
||||||
* const account = await client.createAccount({
|
* const account = await client.createAccount({
|
||||||
* termsOfServiceAgreed: true
|
* termsOfServiceAgreed: true,
|
||||||
* });
|
* });
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
@@ -170,7 +163,7 @@ class AcmeClient {
|
|||||||
* ```js
|
* ```js
|
||||||
* const account = await client.createAccount({
|
* const account = await client.createAccount({
|
||||||
* termsOfServiceAgreed: true,
|
* termsOfServiceAgreed: true,
|
||||||
* contact: ['mailto:test@example.com']
|
* contact: ['mailto:test@example.com'],
|
||||||
* });
|
* });
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
@@ -196,7 +189,6 @@ class AcmeClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update existing account
|
* Update existing account
|
||||||
*
|
*
|
||||||
@@ -208,7 +200,7 @@ class AcmeClient {
|
|||||||
* @example Update existing account
|
* @example Update existing account
|
||||||
* ```js
|
* ```js
|
||||||
* const account = await client.updateAccount({
|
* const account = await client.updateAccount({
|
||||||
* contact: ['mailto:foo@example.com']
|
* contact: ['mailto:foo@example.com'],
|
||||||
* });
|
* });
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
@@ -236,7 +228,6 @@ class AcmeClient {
|
|||||||
return resp.data;
|
return resp.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update account private key
|
* Update account private key
|
||||||
*
|
*
|
||||||
@@ -261,7 +252,7 @@ class AcmeClient {
|
|||||||
const accountUrl = this.api.getAccountUrl();
|
const accountUrl = this.api.getAccountUrl();
|
||||||
|
|
||||||
/* Create new HTTP and API clients using new key */
|
/* Create new HTTP and API clients using new key */
|
||||||
const newHttpClient = new HttpClient(this.opts.directoryUrl, newAccountKey);
|
const newHttpClient = new HttpClient(this.opts.directoryUrl, newAccountKey, this.opts.externalAccountBinding);
|
||||||
const newApiClient = new AcmeApi(newHttpClient, accountUrl);
|
const newApiClient = new AcmeApi(newHttpClient, accountUrl);
|
||||||
|
|
||||||
/* Get old JWK */
|
/* Get old JWK */
|
||||||
@@ -282,7 +273,6 @@ class AcmeClient {
|
|||||||
return resp.data;
|
return resp.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new order
|
* Create a new order
|
||||||
*
|
*
|
||||||
@@ -296,8 +286,8 @@ class AcmeClient {
|
|||||||
* const order = await client.createOrder({
|
* const order = await client.createOrder({
|
||||||
* identifiers: [
|
* identifiers: [
|
||||||
* { type: 'dns', value: 'example.com' },
|
* { type: 'dns', value: 'example.com' },
|
||||||
* { type: 'dns', value: 'test.example.com' }
|
* { type: 'dns', value: 'test.example.com' },
|
||||||
* ]
|
* ],
|
||||||
* });
|
* });
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
@@ -314,7 +304,6 @@ class AcmeClient {
|
|||||||
return resp.data;
|
return resp.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refresh order object from CA
|
* Refresh order object from CA
|
||||||
*
|
*
|
||||||
@@ -376,7 +365,6 @@ class AcmeClient {
|
|||||||
return resp.data;
|
return resp.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get identifier authorizations from order
|
* Get identifier authorizations from order
|
||||||
*
|
*
|
||||||
@@ -406,7 +394,6 @@ class AcmeClient {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deactivate identifier authorization
|
* Deactivate identifier authorization
|
||||||
*
|
*
|
||||||
@@ -427,10 +414,7 @@ class AcmeClient {
|
|||||||
throw new Error('Unable to deactivate identifier authorization, URL not found');
|
throw new Error('Unable to deactivate identifier authorization, URL not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = {
|
const data = { status: 'deactivated' };
|
||||||
status: 'deactivated'
|
|
||||||
};
|
|
||||||
|
|
||||||
const resp = await this.api.updateAuthorization(authz.url, data);
|
const resp = await this.api.updateAuthorization(authz.url, data);
|
||||||
|
|
||||||
/* Add URL to response */
|
/* Add URL to response */
|
||||||
@@ -438,7 +422,6 @@ class AcmeClient {
|
|||||||
return resp.data;
|
return resp.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get key authorization for ACME challenge
|
* Get key authorization for ACME challenge
|
||||||
*
|
*
|
||||||
@@ -480,7 +463,6 @@ class AcmeClient {
|
|||||||
throw new Error(`Unable to produce key authorization, unknown challenge type: ${challenge.type}`);
|
throw new Error(`Unable to produce key authorization, unknown challenge type: ${challenge.type}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify that ACME challenge is satisfied
|
* Verify that ACME challenge is satisfied
|
||||||
*
|
*
|
||||||
@@ -515,7 +497,6 @@ class AcmeClient {
|
|||||||
return util.retry(verifyFn, this.backoffOpts);
|
return util.retry(verifyFn, this.backoffOpts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify CA that challenge has been completed
|
* Notify CA that challenge has been completed
|
||||||
*
|
*
|
||||||
@@ -536,7 +517,6 @@ class AcmeClient {
|
|||||||
return resp.data;
|
return resp.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wait for ACME provider to verify status on a order, authorization or challenge
|
* Wait for ACME provider to verify status on a order, authorization or challenge
|
||||||
*
|
*
|
||||||
@@ -593,7 +573,6 @@ class AcmeClient {
|
|||||||
return util.retry(verifyFn, this.backoffOpts);
|
return util.retry(verifyFn, this.backoffOpts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get certificate from ACME order
|
* Get certificate from ACME order
|
||||||
*
|
*
|
||||||
@@ -640,7 +619,6 @@ class AcmeClient {
|
|||||||
return resp.data;
|
return resp.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Revoke certificate
|
* Revoke certificate
|
||||||
*
|
*
|
||||||
@@ -660,7 +638,7 @@ class AcmeClient {
|
|||||||
* ```js
|
* ```js
|
||||||
* const certificate = { ... }; // Previously created certificate
|
* const certificate = { ... }; // Previously created certificate
|
||||||
* const result = await client.revokeCertificate(certificate, {
|
* const result = await client.revokeCertificate(certificate, {
|
||||||
* reason: 4
|
* reason: 4,
|
||||||
* });
|
* });
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
@@ -671,7 +649,6 @@ class AcmeClient {
|
|||||||
return resp.data;
|
return resp.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Auto mode
|
* Auto mode
|
||||||
*
|
*
|
||||||
@@ -689,7 +666,7 @@ class AcmeClient {
|
|||||||
* @example Order a certificate using auto mode
|
* @example Order a certificate using auto mode
|
||||||
* ```js
|
* ```js
|
||||||
* const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
|
* const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
|
||||||
* commonName: 'test.example.com'
|
* altNames: ['test.example.com'],
|
||||||
* });
|
* });
|
||||||
*
|
*
|
||||||
* const certificate = await client.auto({
|
* const certificate = await client.auto({
|
||||||
@@ -701,14 +678,14 @@ class AcmeClient {
|
|||||||
* },
|
* },
|
||||||
* challengeRemoveFn: async (authz, challenge, keyAuthorization) => {
|
* challengeRemoveFn: async (authz, challenge, keyAuthorization) => {
|
||||||
* // Clean up challenge here
|
* // Clean up challenge here
|
||||||
* }
|
* },
|
||||||
* });
|
* });
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @example Order a certificate using auto mode with preferred chain
|
* @example Order a certificate using auto mode with preferred chain
|
||||||
* ```js
|
* ```js
|
||||||
* const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
|
* const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
|
||||||
* commonName: 'test.example.com'
|
* altNames: ['test.example.com'],
|
||||||
* });
|
* });
|
||||||
*
|
*
|
||||||
* const certificate = await client.auto({
|
* const certificate = await client.auto({
|
||||||
@@ -717,7 +694,7 @@ class AcmeClient {
|
|||||||
* termsOfServiceAgreed: true,
|
* termsOfServiceAgreed: true,
|
||||||
* preferredChain: 'DST Root CA X3',
|
* preferredChain: 'DST Root CA X3',
|
||||||
* challengeCreateFn: async () => {},
|
* challengeCreateFn: async () => {},
|
||||||
* challengeRemoveFn: async () => {}
|
* challengeRemoveFn: async () => {},
|
||||||
* });
|
* });
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
@@ -727,6 +704,5 @@ class AcmeClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Export client */
|
/* Export client */
|
||||||
module.exports = AcmeClient;
|
module.exports = AcmeClient;
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ const forge = require('node-forge');
|
|||||||
|
|
||||||
const generateKeyPair = promisify(forge.pki.rsa.generateKeyPair);
|
const generateKeyPair = promisify(forge.pki.rsa.generateKeyPair);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to parse forge object from PEM encoded string
|
* Attempt to parse forge object from PEM encoded string
|
||||||
*
|
*
|
||||||
@@ -54,7 +53,6 @@ function forgeObjectFromPem(input) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse domain names from a certificate or CSR
|
* Parse domain names from a certificate or CSR
|
||||||
*
|
*
|
||||||
@@ -93,11 +91,10 @@ function parseDomains(obj) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
commonName,
|
commonName,
|
||||||
altNames
|
altNames,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a private RSA key
|
* Generate a private RSA key
|
||||||
*
|
*
|
||||||
@@ -123,7 +120,6 @@ async function createPrivateKey(size = 2048) {
|
|||||||
|
|
||||||
exports.createPrivateKey = createPrivateKey;
|
exports.createPrivateKey = createPrivateKey;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create public key from a private RSA key
|
* Create public key from a private RSA key
|
||||||
*
|
*
|
||||||
@@ -136,14 +132,13 @@ exports.createPrivateKey = createPrivateKey;
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports.createPublicKey = async function(key) {
|
exports.createPublicKey = async (key) => {
|
||||||
const privateKey = forge.pki.privateKeyFromPem(key);
|
const privateKey = forge.pki.privateKeyFromPem(key);
|
||||||
const publicKey = forge.pki.rsa.setPublicKey(privateKey.n, privateKey.e);
|
const publicKey = forge.pki.rsa.setPublicKey(privateKey.n, privateKey.e);
|
||||||
const pemKey = forge.pki.publicKeyToPem(publicKey);
|
const pemKey = forge.pki.publicKeyToPem(publicKey);
|
||||||
return Buffer.from(pemKey);
|
return Buffer.from(pemKey);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse body of PEM encoded object from buffer or string
|
* Parse body of PEM encoded object from buffer or string
|
||||||
* If multiple objects are chained, the first body will be returned
|
* If multiple objects are chained, the first body will be returned
|
||||||
@@ -157,7 +152,6 @@ exports.getPemBody = (str) => {
|
|||||||
return forge.util.encode64(msg.body);
|
return forge.util.encode64(msg.body);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Split chain of PEM encoded objects from buffer or string into array
|
* Split chain of PEM encoded objects from buffer or string into array
|
||||||
*
|
*
|
||||||
@@ -167,7 +161,6 @@ exports.getPemBody = (str) => {
|
|||||||
|
|
||||||
exports.splitPemChain = (str) => forge.pem.decode(str).map(forge.pem.encode);
|
exports.splitPemChain = (str) => forge.pem.decode(str).map(forge.pem.encode);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get modulus
|
* Get modulus
|
||||||
*
|
*
|
||||||
@@ -182,7 +175,7 @@ exports.splitPemChain = (str) => forge.pem.decode(str).map(forge.pem.encode);
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports.getModulus = async function(input) {
|
exports.getModulus = async (input) => {
|
||||||
if (!Buffer.isBuffer(input)) {
|
if (!Buffer.isBuffer(input)) {
|
||||||
input = Buffer.from(input);
|
input = Buffer.from(input);
|
||||||
}
|
}
|
||||||
@@ -191,7 +184,6 @@ exports.getModulus = async function(input) {
|
|||||||
return Buffer.from(forge.util.hexToBytes(obj.n.toString(16)), 'binary');
|
return Buffer.from(forge.util.hexToBytes(obj.n.toString(16)), 'binary');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get public exponent
|
* Get public exponent
|
||||||
*
|
*
|
||||||
@@ -206,7 +198,7 @@ exports.getModulus = async function(input) {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports.getPublicExponent = async function(input) {
|
exports.getPublicExponent = async (input) => {
|
||||||
if (!Buffer.isBuffer(input)) {
|
if (!Buffer.isBuffer(input)) {
|
||||||
input = Buffer.from(input);
|
input = Buffer.from(input);
|
||||||
}
|
}
|
||||||
@@ -215,7 +207,6 @@ exports.getPublicExponent = async function(input) {
|
|||||||
return Buffer.from(forge.util.hexToBytes(obj.e.toString(16)), 'binary');
|
return Buffer.from(forge.util.hexToBytes(obj.e.toString(16)), 'binary');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read domains from a Certificate Signing Request
|
* Read domains from a Certificate Signing Request
|
||||||
*
|
*
|
||||||
@@ -231,7 +222,7 @@ exports.getPublicExponent = async function(input) {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports.readCsrDomains = async function(csr) {
|
exports.readCsrDomains = async (csr) => {
|
||||||
if (!Buffer.isBuffer(csr)) {
|
if (!Buffer.isBuffer(csr)) {
|
||||||
csr = Buffer.from(csr);
|
csr = Buffer.from(csr);
|
||||||
}
|
}
|
||||||
@@ -240,7 +231,6 @@ exports.readCsrDomains = async function(csr) {
|
|||||||
return parseDomains(obj);
|
return parseDomains(obj);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read information from a certificate
|
* Read information from a certificate
|
||||||
*
|
*
|
||||||
@@ -260,7 +250,7 @@ exports.readCsrDomains = async function(csr) {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports.readCertificateInfo = async function(cert) {
|
exports.readCertificateInfo = async (cert) => {
|
||||||
if (!Buffer.isBuffer(cert)) {
|
if (!Buffer.isBuffer(cert)) {
|
||||||
cert = Buffer.from(cert);
|
cert = Buffer.from(cert);
|
||||||
}
|
}
|
||||||
@@ -270,15 +260,14 @@ exports.readCertificateInfo = async function(cert) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
issuer: {
|
issuer: {
|
||||||
commonName: issuerCn ? issuerCn.value : null
|
commonName: issuerCn ? issuerCn.value : null,
|
||||||
},
|
},
|
||||||
domains: parseDomains(obj),
|
domains: parseDomains(obj),
|
||||||
notAfter: obj.validity.notAfter,
|
notAfter: obj.validity.notAfter,
|
||||||
notBefore: obj.validity.notBefore
|
notBefore: obj.validity.notBefore,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine ASN.1 type for CSR subject short name
|
* Determine ASN.1 type for CSR subject short name
|
||||||
* Note: https://datatracker.ietf.org/doc/html/rfc5280
|
* Note: https://datatracker.ietf.org/doc/html/rfc5280
|
||||||
@@ -299,7 +288,6 @@ function getCsrValueTagClass(shortName) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create array of short names and values for Certificate Signing Request subjects
|
* Create array of short names and values for Certificate Signing Request subjects
|
||||||
*
|
*
|
||||||
@@ -319,7 +307,6 @@ function createCsrSubject(subjectObj) {
|
|||||||
}, []);
|
}, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create array of alt names for Certificate Signing Requests
|
* Create array of alt names for Certificate Signing Requests
|
||||||
* Note: https://github.com/digitalbazaar/forge/blob/dfdde475677a8a25c851e33e8f81dca60d90cfb9/lib/x509.js#L1444-L1454
|
* Note: https://github.com/digitalbazaar/forge/blob/dfdde475677a8a25c851e33e8f81dca60d90cfb9/lib/x509.js#L1444-L1454
|
||||||
@@ -336,7 +323,6 @@ function formatCsrAltNames(altNames) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a Certificate Signing Request
|
* Create a Certificate Signing Request
|
||||||
*
|
*
|
||||||
@@ -356,29 +342,30 @@ function formatCsrAltNames(altNames) {
|
|||||||
* @example Create a Certificate Signing Request
|
* @example Create a Certificate Signing Request
|
||||||
* ```js
|
* ```js
|
||||||
* const [certificateKey, certificateRequest] = await acme.forge.createCsr({
|
* const [certificateKey, certificateRequest] = await acme.forge.createCsr({
|
||||||
* commonName: 'test.example.com'
|
* altNames: ['test.example.com'],
|
||||||
* });
|
* });
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @example Certificate Signing Request with both common and alternative names
|
* @example Certificate Signing Request with both common and alternative names
|
||||||
|
* > *Warning*: Certificate subject common name has been [deprecated](https://letsencrypt.org/docs/glossary/#def-CN) and its use is [discouraged](https://cabforum.org/uploads/BRv1.2.3.pdf).
|
||||||
* ```js
|
* ```js
|
||||||
* const [certificateKey, certificateRequest] = await acme.forge.createCsr({
|
* const [certificateKey, certificateRequest] = await acme.forge.createCsr({
|
||||||
* keySize: 4096,
|
* keySize: 4096,
|
||||||
* commonName: 'test.example.com',
|
* commonName: 'test.example.com',
|
||||||
* altNames: ['foo.example.com', 'bar.example.com']
|
* altNames: ['foo.example.com', 'bar.example.com'],
|
||||||
* });
|
* });
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @example Certificate Signing Request with additional information
|
* @example Certificate Signing Request with additional information
|
||||||
* ```js
|
* ```js
|
||||||
* const [certificateKey, certificateRequest] = await acme.forge.createCsr({
|
* const [certificateKey, certificateRequest] = await acme.forge.createCsr({
|
||||||
* commonName: 'test.example.com',
|
* altNames: ['test.example.com'],
|
||||||
* country: 'US',
|
* country: 'US',
|
||||||
* state: 'California',
|
* state: 'California',
|
||||||
* locality: 'Los Angeles',
|
* locality: 'Los Angeles',
|
||||||
* organization: 'The Company Inc.',
|
* organization: 'The Company Inc.',
|
||||||
* organizationUnit: 'IT Department',
|
* organizationUnit: 'IT Department',
|
||||||
* emailAddress: 'contact@example.com'
|
* emailAddress: 'contact@example.com',
|
||||||
* });
|
* });
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
@@ -387,11 +374,11 @@ function formatCsrAltNames(altNames) {
|
|||||||
* const certificateKey = await acme.forge.createPrivateKey();
|
* const certificateKey = await acme.forge.createPrivateKey();
|
||||||
*
|
*
|
||||||
* const [, certificateRequest] = await acme.forge.createCsr({
|
* const [, certificateRequest] = await acme.forge.createCsr({
|
||||||
* commonName: 'test.example.com'
|
* altNames: ['test.example.com'],
|
||||||
* }, certificateKey);
|
* }, certificateKey);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports.createCsr = async function(data, key = null) {
|
exports.createCsr = async (data, key = null) => {
|
||||||
if (!key) {
|
if (!key) {
|
||||||
key = await createPrivateKey(data.keySize);
|
key = await createPrivateKey(data.keySize);
|
||||||
}
|
}
|
||||||
@@ -423,7 +410,7 @@ exports.createCsr = async function(data, key = null) {
|
|||||||
L: data.locality,
|
L: data.locality,
|
||||||
O: data.organization,
|
O: data.organization,
|
||||||
OU: data.organizationUnit,
|
OU: data.organizationUnit,
|
||||||
E: data.emailAddress
|
E: data.emailAddress,
|
||||||
});
|
});
|
||||||
|
|
||||||
csr.setSubject(subject);
|
csr.setSubject(subject);
|
||||||
@@ -434,8 +421,8 @@ exports.createCsr = async function(data, key = null) {
|
|||||||
name: 'extensionRequest',
|
name: 'extensionRequest',
|
||||||
extensions: [{
|
extensions: [{
|
||||||
name: 'subjectAltName',
|
name: 'subjectAltName',
|
||||||
altNames: formatCsrAltNames(data.altNames)
|
altNames: formatCsrAltNames(data.altNames),
|
||||||
}]
|
}],
|
||||||
}]);
|
}]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ const subjectAltNameOID = '2.5.29.17';
|
|||||||
/* id-pe-acmeIdentifier - https://datatracker.ietf.org/doc/html/rfc8737#section-6.1 */
|
/* id-pe-acmeIdentifier - https://datatracker.ietf.org/doc/html/rfc8737#section-6.1 */
|
||||||
const alpnAcmeIdentifierOID = '1.3.6.1.5.5.7.1.31';
|
const alpnAcmeIdentifierOID = '1.3.6.1.5.5.7.1.31';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine key type and info by attempting to derive public key
|
* Determine key type and info by attempting to derive public key
|
||||||
*
|
*
|
||||||
@@ -35,7 +34,7 @@ function getKeyInfo(keyPem) {
|
|||||||
const result = {
|
const result = {
|
||||||
isRSA: false,
|
isRSA: false,
|
||||||
isECDSA: false,
|
isECDSA: false,
|
||||||
publicKey: crypto.createPublicKey(keyPem)
|
publicKey: crypto.createPublicKey(keyPem),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (result.publicKey.asymmetricKeyType === 'rsa') {
|
if (result.publicKey.asymmetricKeyType === 'rsa') {
|
||||||
@@ -51,7 +50,6 @@ function getKeyInfo(keyPem) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a private RSA key
|
* Generate a private RSA key
|
||||||
*
|
*
|
||||||
@@ -74,8 +72,8 @@ async function createPrivateRsaKey(modulusLength = 2048) {
|
|||||||
modulusLength,
|
modulusLength,
|
||||||
privateKeyEncoding: {
|
privateKeyEncoding: {
|
||||||
type: 'pkcs8',
|
type: 'pkcs8',
|
||||||
format: 'pem'
|
format: 'pem',
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return Buffer.from(pair.privateKey);
|
return Buffer.from(pair.privateKey);
|
||||||
@@ -83,7 +81,6 @@ async function createPrivateRsaKey(modulusLength = 2048) {
|
|||||||
|
|
||||||
exports.createPrivateRsaKey = createPrivateRsaKey;
|
exports.createPrivateRsaKey = createPrivateRsaKey;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Alias of `createPrivateRsaKey()`
|
* Alias of `createPrivateRsaKey()`
|
||||||
*
|
*
|
||||||
@@ -92,7 +89,6 @@ exports.createPrivateRsaKey = createPrivateRsaKey;
|
|||||||
|
|
||||||
exports.createPrivateKey = createPrivateRsaKey;
|
exports.createPrivateKey = createPrivateRsaKey;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a private ECDSA key
|
* Generate a private ECDSA key
|
||||||
*
|
*
|
||||||
@@ -115,14 +111,13 @@ exports.createPrivateEcdsaKey = async (namedCurve = 'P-256') => {
|
|||||||
namedCurve,
|
namedCurve,
|
||||||
privateKeyEncoding: {
|
privateKeyEncoding: {
|
||||||
type: 'pkcs8',
|
type: 'pkcs8',
|
||||||
format: 'pem'
|
format: 'pem',
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return Buffer.from(pair.privateKey);
|
return Buffer.from(pair.privateKey);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a public key derived from a RSA or ECDSA key
|
* Get a public key derived from a RSA or ECDSA key
|
||||||
*
|
*
|
||||||
@@ -140,13 +135,12 @@ exports.getPublicKey = (keyPem) => {
|
|||||||
|
|
||||||
const publicKey = info.publicKey.export({
|
const publicKey = info.publicKey.export({
|
||||||
type: info.isECDSA ? 'spki' : 'pkcs1',
|
type: info.isECDSA ? 'spki' : 'pkcs1',
|
||||||
format: 'pem'
|
format: 'pem',
|
||||||
});
|
});
|
||||||
|
|
||||||
return Buffer.from(publicKey);
|
return Buffer.from(publicKey);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a JSON Web Key derived from a RSA or ECDSA key
|
* Get a JSON Web Key derived from a RSA or ECDSA key
|
||||||
*
|
*
|
||||||
@@ -163,7 +157,7 @@ exports.getPublicKey = (keyPem) => {
|
|||||||
|
|
||||||
function getJwk(keyPem) {
|
function getJwk(keyPem) {
|
||||||
const jwk = crypto.createPublicKey(keyPem).export({
|
const jwk = crypto.createPublicKey(keyPem).export({
|
||||||
format: 'jwk'
|
format: 'jwk',
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Sort keys */
|
/* Sort keys */
|
||||||
@@ -175,7 +169,6 @@ function getJwk(keyPem) {
|
|||||||
|
|
||||||
exports.getJwk = getJwk;
|
exports.getJwk = getJwk;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Produce CryptoKeyPair and signing algorithm from a PEM encoded private key
|
* Produce CryptoKeyPair and signing algorithm from a PEM encoded private key
|
||||||
*
|
*
|
||||||
@@ -191,7 +184,7 @@ async function getWebCryptoKeyPair(keyPem) {
|
|||||||
/* Signing algorithm */
|
/* Signing algorithm */
|
||||||
const sigalg = {
|
const sigalg = {
|
||||||
name: 'RSASSA-PKCS1-v1_5',
|
name: 'RSASSA-PKCS1-v1_5',
|
||||||
hash: { name: 'SHA-256' }
|
hash: { name: 'SHA-256' },
|
||||||
};
|
};
|
||||||
|
|
||||||
if (info.isECDSA) {
|
if (info.isECDSA) {
|
||||||
@@ -215,7 +208,6 @@ async function getWebCryptoKeyPair(keyPem) {
|
|||||||
return [{ privateKey, publicKey }, sigalg];
|
return [{ privateKey, publicKey }, sigalg];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Split chain of PEM encoded objects from string into array
|
* Split chain of PEM encoded objects from string into array
|
||||||
*
|
*
|
||||||
@@ -235,7 +227,6 @@ function splitPemChain(chainPem) {
|
|||||||
|
|
||||||
exports.splitPemChain = splitPemChain;
|
exports.splitPemChain = splitPemChain;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse body of PEM encoded object and return a Base64URL string
|
* Parse body of PEM encoded object and return a Base64URL string
|
||||||
* If multiple objects are chained, the first body will be returned
|
* If multiple objects are chained, the first body will be returned
|
||||||
@@ -256,7 +247,6 @@ exports.getPemBodyAsB64u = (pem) => {
|
|||||||
return Buffer.from(dec).toString('base64url');
|
return Buffer.from(dec).toString('base64url');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse domains from a certificate or CSR
|
* Parse domains from a certificate or CSR
|
||||||
*
|
*
|
||||||
@@ -277,11 +267,10 @@ function parseDomains(input) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
commonName,
|
commonName,
|
||||||
altNames
|
altNames,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read domains from a Certificate Signing Request
|
* Read domains from a Certificate Signing Request
|
||||||
*
|
*
|
||||||
@@ -307,7 +296,6 @@ exports.readCsrDomains = (csrPem) => {
|
|||||||
return parseDomains(csr);
|
return parseDomains(csr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read information from a certificate
|
* Read information from a certificate
|
||||||
* If multiple certificates are chained, the first will be read
|
* If multiple certificates are chained, the first will be read
|
||||||
@@ -338,15 +326,14 @@ exports.readCertificateInfo = (certPem) => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
issuer: {
|
issuer: {
|
||||||
commonName: cert.issuerName.getField('CN').pop() || null
|
commonName: cert.issuerName.getField('CN').pop() || null,
|
||||||
},
|
},
|
||||||
domains: parseDomains(cert),
|
domains: parseDomains(cert),
|
||||||
notBefore: cert.notBefore,
|
notBefore: cert.notBefore,
|
||||||
notAfter: cert.notAfter
|
notAfter: cert.notAfter,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine ASN.1 character string type for CSR subject field name
|
* Determine ASN.1 character string type for CSR subject field name
|
||||||
*
|
*
|
||||||
@@ -369,7 +356,6 @@ function getCsrAsn1CharStringType(field) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create array of subject fields for a Certificate Signing Request
|
* Create array of subject fields for a Certificate Signing Request
|
||||||
*
|
*
|
||||||
@@ -391,7 +377,6 @@ function createCsrSubject(input) {
|
|||||||
}, []);
|
}, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create x509 subject alternate name extension
|
* Create x509 subject alternate name extension
|
||||||
*
|
*
|
||||||
@@ -409,7 +394,6 @@ function createSubjectAltNameExtension(altNames) {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a Certificate Signing Request
|
* Create a Certificate Signing Request
|
||||||
*
|
*
|
||||||
@@ -429,29 +413,30 @@ function createSubjectAltNameExtension(altNames) {
|
|||||||
* @example Create a Certificate Signing Request
|
* @example Create a Certificate Signing Request
|
||||||
* ```js
|
* ```js
|
||||||
* const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
|
* const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
|
||||||
* commonName: 'test.example.com'
|
* altNames: ['test.example.com'],
|
||||||
* });
|
* });
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @example Certificate Signing Request with both common and alternative names
|
* @example Certificate Signing Request with both common and alternative names
|
||||||
|
* > *Warning*: Certificate subject common name has been [deprecated](https://letsencrypt.org/docs/glossary/#def-CN) and its use is [discouraged](https://cabforum.org/uploads/BRv1.2.3.pdf).
|
||||||
* ```js
|
* ```js
|
||||||
* const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
|
* const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
|
||||||
* keySize: 4096,
|
* keySize: 4096,
|
||||||
* commonName: 'test.example.com',
|
* commonName: 'test.example.com',
|
||||||
* altNames: ['foo.example.com', 'bar.example.com']
|
* altNames: ['foo.example.com', 'bar.example.com'],
|
||||||
* });
|
* });
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @example Certificate Signing Request with additional information
|
* @example Certificate Signing Request with additional information
|
||||||
* ```js
|
* ```js
|
||||||
* const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
|
* const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
|
||||||
* commonName: 'test.example.com',
|
* altNames: ['test.example.com'],
|
||||||
* country: 'US',
|
* country: 'US',
|
||||||
* state: 'California',
|
* state: 'California',
|
||||||
* locality: 'Los Angeles',
|
* locality: 'Los Angeles',
|
||||||
* organization: 'The Company Inc.',
|
* organization: 'The Company Inc.',
|
||||||
* organizationUnit: 'IT Department',
|
* organizationUnit: 'IT Department',
|
||||||
* emailAddress: 'contact@example.com'
|
* emailAddress: 'contact@example.com',
|
||||||
* });
|
* });
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
@@ -460,8 +445,9 @@ function createSubjectAltNameExtension(altNames) {
|
|||||||
* const certificateKey = await acme.crypto.createPrivateEcdsaKey();
|
* const certificateKey = await acme.crypto.createPrivateEcdsaKey();
|
||||||
*
|
*
|
||||||
* const [, certificateRequest] = await acme.crypto.createCsr({
|
* const [, certificateRequest] = await acme.crypto.createCsr({
|
||||||
* commonName: 'test.example.com'
|
* altNames: ['test.example.com'],
|
||||||
* }, certificateKey);
|
* }, certificateKey);
|
||||||
|
* ```
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports.createCsr = async (data, keyPem = null) => {
|
exports.createCsr = async (data, keyPem = null) => {
|
||||||
@@ -489,7 +475,7 @@ exports.createCsr = async (data, keyPem = null) => {
|
|||||||
new x509.KeyUsagesExtension(x509.KeyUsageFlags.digitalSignature | x509.KeyUsageFlags.keyEncipherment), // eslint-disable-line no-bitwise
|
new x509.KeyUsagesExtension(x509.KeyUsageFlags.digitalSignature | x509.KeyUsageFlags.keyEncipherment), // eslint-disable-line no-bitwise
|
||||||
|
|
||||||
/* https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6 */
|
/* https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6 */
|
||||||
createSubjectAltNameExtension(data.altNames)
|
createSubjectAltNameExtension(data.altNames),
|
||||||
];
|
];
|
||||||
|
|
||||||
/* Create CSR */
|
/* Create CSR */
|
||||||
@@ -504,8 +490,8 @@ exports.createCsr = async (data, keyPem = null) => {
|
|||||||
L: data.locality,
|
L: data.locality,
|
||||||
O: data.organization,
|
O: data.organization,
|
||||||
OU: data.organizationUnit,
|
OU: data.organizationUnit,
|
||||||
E: data.emailAddress
|
E: data.emailAddress,
|
||||||
})
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Done */
|
/* Done */
|
||||||
@@ -513,7 +499,6 @@ exports.createCsr = async (data, keyPem = null) => {
|
|||||||
return [keyPem, Buffer.from(pem)];
|
return [keyPem, Buffer.from(pem)];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a self-signed ALPN certificate for TLS-ALPN-01 challenges
|
* Create a self-signed ALPN certificate for TLS-ALPN-01 challenges
|
||||||
*
|
*
|
||||||
@@ -533,6 +518,7 @@ exports.createCsr = async (data, keyPem = null) => {
|
|||||||
* ```js
|
* ```js
|
||||||
* const alpnKey = await acme.crypto.createPrivateEcdsaKey();
|
* const alpnKey = await acme.crypto.createPrivateEcdsaKey();
|
||||||
* const [, alpnCertificate] = await acme.crypto.createAlpnCertificate(authz, keyAuthorization, alpnKey);
|
* const [, alpnCertificate] = await acme.crypto.createAlpnCertificate(authz, keyAuthorization, alpnKey);
|
||||||
|
* ```
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports.createAlpnCertificate = async (authz, keyAuthorization, keyPem = null) => {
|
exports.createAlpnCertificate = async (authz, keyAuthorization, keyPem = null) => {
|
||||||
@@ -564,7 +550,7 @@ exports.createAlpnCertificate = async (authz, keyAuthorization, keyPem = null) =
|
|||||||
await x509.SubjectKeyIdentifierExtension.create(keys.publicKey),
|
await x509.SubjectKeyIdentifierExtension.create(keys.publicKey),
|
||||||
|
|
||||||
/* https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6 */
|
/* https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6 */
|
||||||
createSubjectAltNameExtension([commonName])
|
createSubjectAltNameExtension([commonName]),
|
||||||
];
|
];
|
||||||
|
|
||||||
/* ALPN extension */
|
/* ALPN extension */
|
||||||
@@ -581,8 +567,8 @@ exports.createAlpnCertificate = async (authz, keyAuthorization, keyPem = null) =
|
|||||||
notBefore: now,
|
notBefore: now,
|
||||||
notAfter: now,
|
notAfter: now,
|
||||||
name: createCsrSubject({
|
name: createCsrSubject({
|
||||||
CN: commonName
|
CN: commonName,
|
||||||
})
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Done */
|
/* Done */
|
||||||
@@ -590,7 +576,6 @@ exports.createAlpnCertificate = async (authz, keyAuthorization, keyPem = null) =
|
|||||||
return [keyPem, Buffer.from(pem)];
|
return [keyPem, Buffer.from(pem)];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate that a ALPN certificate contains the expected key authorization
|
* Validate that a ALPN certificate contains the expected key authorization
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ class HttpClient {
|
|||||||
this.jwk = null;
|
this.jwk = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP request
|
* HTTP request
|
||||||
*
|
*
|
||||||
@@ -70,7 +69,6 @@ class HttpClient {
|
|||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure provider directory exists
|
* Ensure provider directory exists
|
||||||
*
|
*
|
||||||
@@ -95,7 +93,6 @@ class HttpClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get JSON Web Key
|
* Get JSON Web Key
|
||||||
*
|
*
|
||||||
@@ -110,7 +107,6 @@ class HttpClient {
|
|||||||
return this.jwk;
|
return this.jwk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get nonce from directory API endpoint
|
* Get nonce from directory API endpoint
|
||||||
*
|
*
|
||||||
@@ -130,7 +126,6 @@ class HttpClient {
|
|||||||
return resp.headers['replay-nonce'];
|
return resp.headers['replay-nonce'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get URL for a directory resource
|
* Get URL for a directory resource
|
||||||
*
|
*
|
||||||
@@ -148,7 +143,6 @@ class HttpClient {
|
|||||||
return this.directory[resource];
|
return this.directory[resource];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get directory meta field
|
* Get directory meta field
|
||||||
*
|
*
|
||||||
@@ -166,7 +160,6 @@ class HttpClient {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare HTTP request body for signature
|
* Prepare HTTP request body for signature
|
||||||
*
|
*
|
||||||
@@ -199,11 +192,10 @@ class HttpClient {
|
|||||||
/* Body */
|
/* Body */
|
||||||
return {
|
return {
|
||||||
payload: payload ? Buffer.from(JSON.stringify(payload)).toString('base64url') : '',
|
payload: payload ? Buffer.from(JSON.stringify(payload)).toString('base64url') : '',
|
||||||
protected: Buffer.from(JSON.stringify(header)).toString('base64url')
|
protected: Buffer.from(JSON.stringify(header)).toString('base64url'),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create JWS HTTP request body using HMAC
|
* Create JWS HTTP request body using HMAC
|
||||||
*
|
*
|
||||||
@@ -226,7 +218,6 @@ class HttpClient {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create JWS HTTP request body using RSA or ECC
|
* Create JWS HTTP request body using RSA or ECC
|
||||||
*
|
*
|
||||||
@@ -267,13 +258,12 @@ class HttpClient {
|
|||||||
result.signature = signer.sign({
|
result.signature = signer.sign({
|
||||||
key: this.accountKey,
|
key: this.accountKey,
|
||||||
padding: RSA_PKCS1_PADDING,
|
padding: RSA_PKCS1_PADDING,
|
||||||
dsaEncoding: 'ieee-p1363'
|
dsaEncoding: 'ieee-p1363',
|
||||||
}, 'base64url');
|
}, 'base64url');
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signed HTTP request
|
* Signed HTTP request
|
||||||
*
|
*
|
||||||
@@ -309,7 +299,7 @@ class HttpClient {
|
|||||||
const data = this.createSignedBody(url, payload, { nonce, kid });
|
const data = this.createSignedBody(url, payload, { nonce, kid });
|
||||||
const resp = await this.request(url, 'post', { data });
|
const resp = await this.request(url, 'post', { data });
|
||||||
|
|
||||||
/* Retry on bad nonce - https://datatracker.ietf.org/doc/html/draft-ietf-acme-acme-10#section-6.4 */
|
/* Retry on bad nonce - https://datatracker.ietf.org/doc/html/rfc8555#section-6.5 */
|
||||||
if (resp.data && resp.data.type && (resp.status === 400) && (resp.data.type === 'urn:ietf:params:acme:error:badNonce') && (attempts < this.maxBadNonceRetries)) {
|
if (resp.data && resp.data.type && (resp.status === 400) && (resp.data.type === 'urn:ietf:params:acme:error:badNonce') && (attempts < this.maxBadNonceRetries)) {
|
||||||
nonce = resp.headers['replay-nonce'] || null;
|
nonce = resp.headers['replay-nonce'] || null;
|
||||||
attempts += 1;
|
attempts += 1;
|
||||||
@@ -323,6 +313,5 @@ class HttpClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Export client */
|
/* Export client */
|
||||||
module.exports = HttpClient;
|
module.exports = HttpClient;
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
exports.Client = require('./client');
|
exports.Client = require('./client');
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Directory URLs
|
* Directory URLs
|
||||||
*/
|
*/
|
||||||
@@ -12,18 +11,18 @@ exports.Client = require('./client');
|
|||||||
exports.directory = {
|
exports.directory = {
|
||||||
buypass: {
|
buypass: {
|
||||||
staging: 'https://api.test4.buypass.no/acme/directory',
|
staging: 'https://api.test4.buypass.no/acme/directory',
|
||||||
production: 'https://api.buypass.com/acme/directory'
|
production: 'https://api.buypass.com/acme/directory',
|
||||||
},
|
},
|
||||||
letsencrypt: {
|
letsencrypt: {
|
||||||
staging: 'https://acme-staging-v02.api.letsencrypt.org/directory',
|
staging: 'https://acme-staging-v02.api.letsencrypt.org/directory',
|
||||||
production: 'https://acme-v02.api.letsencrypt.org/directory'
|
production: 'https://acme-v02.api.letsencrypt.org/directory',
|
||||||
},
|
},
|
||||||
zerossl: {
|
zerossl: {
|
||||||
production: 'https://acme.zerossl.com/v2/DV90'
|
staging: 'https://acme.zerossl.com/v2/DV90',
|
||||||
}
|
production: 'https://acme.zerossl.com/v2/DV90',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Crypto
|
* Crypto
|
||||||
*/
|
*/
|
||||||
@@ -31,14 +30,12 @@ exports.directory = {
|
|||||||
exports.crypto = require('./crypto');
|
exports.crypto = require('./crypto');
|
||||||
exports.forge = require('./crypto/forge');
|
exports.forge = require('./crypto/forge');
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Axios
|
* Axios
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports.axios = require('./axios');
|
exports.axios = require('./axios');
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logger
|
* Logger
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ const debug = require('debug')('acme-client');
|
|||||||
|
|
||||||
let logger = () => {};
|
let logger = () => {};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set logger function
|
* Set logger function
|
||||||
*
|
*
|
||||||
@@ -17,11 +16,10 @@ exports.setLogger = (fn) => {
|
|||||||
logger = fn;
|
logger = fn;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log message
|
* Log message
|
||||||
*
|
*
|
||||||
* @param {string} Message
|
* @param {string} msg Message
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports.log = (msg) => {
|
exports.log = (msg) => {
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ const dns = require('dns').promises;
|
|||||||
const { readCertificateInfo, splitPemChain } = require('./crypto');
|
const { readCertificateInfo, splitPemChain } = require('./crypto');
|
||||||
const { log } = require('./logger');
|
const { log } = require('./logger');
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exponential backoff
|
* Exponential backoff
|
||||||
*
|
*
|
||||||
@@ -26,7 +25,6 @@ class Backoff {
|
|||||||
this.attempts = 0;
|
this.attempts = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get backoff duration
|
* Get backoff duration
|
||||||
*
|
*
|
||||||
@@ -40,7 +38,6 @@ class Backoff {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retry promise
|
* Retry promise
|
||||||
*
|
*
|
||||||
@@ -70,7 +67,6 @@ async function retryPromise(fn, attempts, backoff) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retry promise
|
* Retry promise
|
||||||
*
|
*
|
||||||
@@ -87,7 +83,6 @@ function retry(fn, { attempts = 5, min = 5000, max = 30000 } = {}) {
|
|||||||
return retryPromise(fn, attempts, backoff);
|
return retryPromise(fn, attempts, backoff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse URLs from link header
|
* Parse URLs from link header
|
||||||
*
|
*
|
||||||
@@ -107,7 +102,6 @@ function parseLinkHeader(header, rel = 'alternate') {
|
|||||||
return results.filter((r) => r);
|
return results.filter((r) => r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find certificate chain with preferred issuer common name
|
* Find certificate chain with preferred issuer common name
|
||||||
* - If issuer is found in multiple chains, the closest to root wins
|
* - If issuer is found in multiple chains, the closest to root wins
|
||||||
@@ -157,7 +151,6 @@ function findCertificateChainForIssuer(chains, issuer) {
|
|||||||
return chains[0];
|
return chains[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find and format error in response object
|
* Find and format error in response object
|
||||||
*
|
*
|
||||||
@@ -178,7 +171,6 @@ function formatResponseError(resp) {
|
|||||||
return result.replace(/\n/g, '');
|
return result.replace(/\n/g, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve root domain name by looking for SOA record
|
* Resolve root domain name by looking for SOA record
|
||||||
*
|
*
|
||||||
@@ -204,7 +196,6 @@ async function resolveDomainBySoaRecord(recordName) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get DNS resolver using domains authoritative NS records
|
* Get DNS resolver using domains authoritative NS records
|
||||||
*
|
*
|
||||||
@@ -245,7 +236,6 @@ async function getAuthoritativeDnsResolver(recordName) {
|
|||||||
return resolver;
|
return resolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to retrieve TLS ALPN certificate from peer
|
* Attempt to retrieve TLS ALPN certificate from peer
|
||||||
*
|
*
|
||||||
@@ -267,7 +257,7 @@ async function retrieveTlsAlpnCertificate(host, port, timeout = 30000) {
|
|||||||
port,
|
port,
|
||||||
servername: host,
|
servername: host,
|
||||||
rejectUnauthorized: false,
|
rejectUnauthorized: false,
|
||||||
ALPNProtocols: ['acme-tls/1']
|
ALPNProtocols: ['acme-tls/1'],
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.setTimeout(timeout);
|
socket.setTimeout(timeout);
|
||||||
@@ -299,7 +289,6 @@ async function retrieveTlsAlpnCertificate(host, port, timeout = 30000) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Export utils
|
* Export utils
|
||||||
*/
|
*/
|
||||||
@@ -310,5 +299,5 @@ module.exports = {
|
|||||||
findCertificateChainForIssuer,
|
findCertificateChainForIssuer,
|
||||||
formatResponseError,
|
formatResponseError,
|
||||||
getAuthoritativeDnsResolver,
|
getAuthoritativeDnsResolver,
|
||||||
retrieveTlsAlpnCertificate
|
retrieveTlsAlpnCertificate,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ const axios = require('./axios');
|
|||||||
const util = require('./util');
|
const util = require('./util');
|
||||||
const { isAlpnCertificateAuthorizationValid } = require('./crypto');
|
const { isAlpnCertificateAuthorizationValid } = require('./crypto');
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify ACME HTTP challenge
|
* Verify ACME HTTP challenge
|
||||||
*
|
*
|
||||||
@@ -43,25 +42,24 @@ async function verifyHttpChallenge(authz, challenge, keyAuthorization, suffix =
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Walk DNS until TXT records are found
|
* Walk DNS until TXT records are found
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async function walkDnsChallengeRecord(recordName, resolver = dns) {
|
async function walkDnsChallengeRecord(recordName, resolver = dns) {
|
||||||
/* Resolve CNAME record first */
|
/* Resolve CNAME record first */
|
||||||
try {
|
// try {
|
||||||
log(`Checking name for CNAME records: ${recordName}`);
|
// log(`Checking name for CNAME records: ${recordName}`);
|
||||||
const cnameRecords = await resolver.resolveCname(recordName);
|
// const cnameRecords = await resolver.resolveCname(recordName);
|
||||||
|
//
|
||||||
if (cnameRecords.length) {
|
// if (cnameRecords.length) {
|
||||||
log(`CNAME record found at ${recordName}, new challenge record name: ${cnameRecords[0]}`);
|
// log(`CNAME record found at ${recordName}, new challenge record name: ${cnameRecords[0]}`);
|
||||||
return walkDnsChallengeRecord(cnameRecords[0]);
|
// return walkDnsChallengeRecord(cnameRecords[0]);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
catch (e) {
|
// catch (e) {
|
||||||
log(`No CNAME records found for name: ${recordName}`);
|
// log(`No CNAME records found for name: ${recordName}`);
|
||||||
}
|
// }
|
||||||
|
|
||||||
/* Resolve TXT records */
|
/* Resolve TXT records */
|
||||||
try {
|
try {
|
||||||
@@ -81,7 +79,6 @@ async function walkDnsChallengeRecord(recordName, resolver = dns) {
|
|||||||
throw new Error(`No TXT records found for name: ${recordName}`);
|
throw new Error(`No TXT records found for name: ${recordName}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify ACME DNS challenge
|
* Verify ACME DNS challenge
|
||||||
*
|
*
|
||||||
@@ -121,7 +118,6 @@ async function verifyDnsChallenge(authz, challenge, keyAuthorization, prefix = '
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify ACME TLS ALPN challenge
|
* Verify ACME TLS ALPN challenge
|
||||||
*
|
*
|
||||||
@@ -149,7 +145,6 @@ async function verifyTlsAlpnChallenge(authz, challenge, keyAuthorization) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Export API
|
* Export API
|
||||||
*/
|
*/
|
||||||
@@ -157,5 +152,5 @@ async function verifyTlsAlpnChallenge(authz, challenge, keyAuthorization) {
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
'http-01': verifyHttpChallenge,
|
'http-01': verifyHttpChallenge,
|
||||||
'dns-01': verifyDnsChallenge,
|
'dns-01': verifyDnsChallenge,
|
||||||
'tls-alpn-01': verifyTlsAlpnChallenge
|
'tls-alpn-01': verifyTlsAlpnChallenge,
|
||||||
};
|
};
|
||||||
|
|||||||
9
packages/core/acme-client/src/wait.js
Normal file
9
packages/core/acme-client/src/wait.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
async function wait(ms) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
setTimeout(resolve, ms);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
wait
|
||||||
|
};
|
||||||
@@ -16,7 +16,6 @@ const httpPort = axios.defaults.acmeSettings.httpChallengePort || 80;
|
|||||||
const httpsPort = axios.defaults.acmeSettings.httpsChallengePort || 443;
|
const httpsPort = axios.defaults.acmeSettings.httpsChallengePort || 443;
|
||||||
const tlsAlpnPort = axios.defaults.acmeSettings.tlsAlpnChallengePort || 443;
|
const tlsAlpnPort = axios.defaults.acmeSettings.tlsAlpnChallengePort || 443;
|
||||||
|
|
||||||
|
|
||||||
describe('pebble', () => {
|
describe('pebble', () => {
|
||||||
const httpsAgent = new https.Agent({ rejectUnauthorized: false });
|
const httpsAgent = new https.Agent({ rejectUnauthorized: false });
|
||||||
|
|
||||||
@@ -39,18 +38,16 @@ describe('pebble', () => {
|
|||||||
const testTlsAlpn01ChallengeHost = `${uuid()}.${domainName}`;
|
const testTlsAlpn01ChallengeHost = `${uuid()}.${domainName}`;
|
||||||
const testTlsAlpn01ChallengeValue = uuid();
|
const testTlsAlpn01ChallengeValue = uuid();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pebble CTS required
|
* Pebble CTS required
|
||||||
*/
|
*/
|
||||||
|
|
||||||
before(function() {
|
before(function () {
|
||||||
if (!cts.isEnabled()) {
|
if (!cts.isEnabled()) {
|
||||||
this.skip();
|
this.skip();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DNS mocking
|
* DNS mocking
|
||||||
*/
|
*/
|
||||||
@@ -92,7 +89,6 @@ describe('pebble', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP-01 challenge response
|
* HTTP-01 challenge response
|
||||||
*/
|
*/
|
||||||
@@ -118,7 +114,6 @@ describe('pebble', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTPS-01 challenge response
|
* HTTPS-01 challenge response
|
||||||
*/
|
*/
|
||||||
@@ -143,7 +138,7 @@ describe('pebble', () => {
|
|||||||
/* Assert HTTP 302 */
|
/* Assert HTTP 302 */
|
||||||
const resp = await axios.get(`http://${testHttps01ChallengeHost}:${httpPort}/.well-known/acme-challenge/${testHttps01ChallengeToken}`, {
|
const resp = await axios.get(`http://${testHttps01ChallengeHost}:${httpPort}/.well-known/acme-challenge/${testHttps01ChallengeToken}`, {
|
||||||
maxRedirects: 0,
|
maxRedirects: 0,
|
||||||
validateStatus: null
|
validateStatus: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.strictEqual(resp.status, 302);
|
assert.strictEqual(resp.status, 302);
|
||||||
@@ -165,7 +160,6 @@ describe('pebble', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DNS-01 challenge response
|
* DNS-01 challenge response
|
||||||
*/
|
*/
|
||||||
@@ -188,7 +182,6 @@ describe('pebble', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TLS-ALPN-01 challenge response
|
* TLS-ALPN-01 challenge response
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ const axios = require('./../src/axios');
|
|||||||
const HttpClient = require('./../src/http');
|
const HttpClient = require('./../src/http');
|
||||||
const pkg = require('./../package.json');
|
const pkg = require('./../package.json');
|
||||||
|
|
||||||
|
|
||||||
describe('http', () => {
|
describe('http', () => {
|
||||||
let testClient;
|
let testClient;
|
||||||
|
|
||||||
@@ -20,7 +19,6 @@ describe('http', () => {
|
|||||||
const defaultUaEndpoint = `http://${uuid()}.example.com`;
|
const defaultUaEndpoint = `http://${uuid()}.example.com`;
|
||||||
const customUaEndpoint = `http://${uuid()}.example.com`;
|
const customUaEndpoint = `http://${uuid()}.example.com`;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP mocking
|
* HTTP mocking
|
||||||
*/
|
*/
|
||||||
@@ -43,7 +41,6 @@ describe('http', () => {
|
|||||||
axios.defaults.headers.common['User-Agent'] = defaultUserAgent;
|
axios.defaults.headers.common['User-Agent'] = defaultUserAgent;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize
|
* Initialize
|
||||||
*/
|
*/
|
||||||
@@ -52,7 +49,6 @@ describe('http', () => {
|
|||||||
testClient = new HttpClient();
|
testClient = new HttpClient();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP verbs
|
* HTTP verbs
|
||||||
*/
|
*/
|
||||||
@@ -65,7 +61,6 @@ describe('http', () => {
|
|||||||
assert.strictEqual(resp.data, 'ok');
|
assert.strictEqual(resp.data, 'ok');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User-Agent
|
* User-Agent
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
const { assert } = require('chai');
|
const { assert } = require('chai');
|
||||||
const logger = require('./../src/logger');
|
const logger = require('./../src/logger');
|
||||||
|
|
||||||
|
|
||||||
describe('logger', () => {
|
describe('logger', () => {
|
||||||
let lastLogMessage = null;
|
let lastLogMessage = null;
|
||||||
|
|
||||||
@@ -13,7 +12,6 @@ describe('logger', () => {
|
|||||||
lastLogMessage = msg;
|
lastLogMessage = msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logger
|
* Logger
|
||||||
*/
|
*/
|
||||||
@@ -23,7 +21,6 @@ describe('logger', () => {
|
|||||||
assert.isNull(lastLogMessage);
|
assert.isNull(lastLogMessage);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should log with custom logger', () => {
|
it('should log with custom logger', () => {
|
||||||
logger.setLogger(customLoggerFn);
|
logger.setLogger(customLoggerFn);
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ const verify = require('./../src/verify');
|
|||||||
|
|
||||||
const domainName = process.env.ACME_DOMAIN_NAME || 'example.com';
|
const domainName = process.env.ACME_DOMAIN_NAME || 'example.com';
|
||||||
|
|
||||||
|
|
||||||
describe('verify', () => {
|
describe('verify', () => {
|
||||||
const challengeTypes = ['http-01', 'dns-01'];
|
const challengeTypes = ['http-01', 'dns-01'];
|
||||||
|
|
||||||
@@ -30,18 +29,16 @@ describe('verify', () => {
|
|||||||
const testTlsAlpn01Challenge = { type: 'dns-01', status: 'pending', token: uuid() };
|
const testTlsAlpn01Challenge = { type: 'dns-01', status: 'pending', token: uuid() };
|
||||||
const testTlsAlpn01Key = uuid();
|
const testTlsAlpn01Key = uuid();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pebble CTS required
|
* Pebble CTS required
|
||||||
*/
|
*/
|
||||||
|
|
||||||
before(function() {
|
before(function () {
|
||||||
if (!cts.isEnabled()) {
|
if (!cts.isEnabled()) {
|
||||||
this.skip();
|
this.skip();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* API
|
* API
|
||||||
*/
|
*/
|
||||||
@@ -50,7 +47,6 @@ describe('verify', () => {
|
|||||||
assert.containsAllKeys(verify, challengeTypes);
|
assert.containsAllKeys(verify, challengeTypes);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* http-01
|
* http-01
|
||||||
*/
|
*/
|
||||||
@@ -81,7 +77,6 @@ describe('verify', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https-01
|
* https-01
|
||||||
*/
|
*/
|
||||||
@@ -102,7 +97,6 @@ describe('verify', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dns-01
|
* dns-01
|
||||||
*/
|
*/
|
||||||
@@ -133,7 +127,6 @@ describe('verify', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tls-alpn-01
|
* tls-alpn-01
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -9,10 +9,9 @@ const spec = require('./spec');
|
|||||||
const forge = require('./../src/crypto/forge');
|
const forge = require('./../src/crypto/forge');
|
||||||
|
|
||||||
const cryptoEngines = {
|
const cryptoEngines = {
|
||||||
forge
|
forge,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
describe('crypto-legacy', () => {
|
describe('crypto-legacy', () => {
|
||||||
let testPemKey;
|
let testPemKey;
|
||||||
let testCert;
|
let testCert;
|
||||||
@@ -28,7 +27,6 @@ describe('crypto-legacy', () => {
|
|||||||
const testCertPath = path.join(__dirname, 'fixtures', 'certificate.crt');
|
const testCertPath = path.join(__dirname, 'fixtures', 'certificate.crt');
|
||||||
const testSanCertPath = path.join(__dirname, 'fixtures', 'san-certificate.crt');
|
const testSanCertPath = path.join(__dirname, 'fixtures', 'san-certificate.crt');
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fixtures
|
* Fixtures
|
||||||
*/
|
*/
|
||||||
@@ -50,7 +48,6 @@ describe('crypto-legacy', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Engines
|
* Engines
|
||||||
*/
|
*/
|
||||||
@@ -62,7 +59,6 @@ describe('crypto-legacy', () => {
|
|||||||
let testNonCnCsr;
|
let testNonCnCsr;
|
||||||
let testNonAsciiCsr;
|
let testNonAsciiCsr;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Key generation
|
* Key generation
|
||||||
*/
|
*/
|
||||||
@@ -83,14 +79,13 @@ describe('crypto-legacy', () => {
|
|||||||
publicKeyStore.push(key.toString().replace(/[\r\n]/gm, ''));
|
publicKeyStore.push(key.toString().replace(/[\r\n]/gm, ''));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Certificate Signing Request
|
* Certificate Signing Request
|
||||||
*/
|
*/
|
||||||
|
|
||||||
it('should generate a csr', async () => {
|
it('should generate a csr', async () => {
|
||||||
const [key, csr] = await engine.createCsr({
|
const [key, csr] = await engine.createCsr({
|
||||||
commonName: testCsrDomain
|
commonName: testCsrDomain,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.isTrue(Buffer.isBuffer(key));
|
assert.isTrue(Buffer.isBuffer(key));
|
||||||
@@ -102,7 +97,7 @@ describe('crypto-legacy', () => {
|
|||||||
it('should generate a san csr', async () => {
|
it('should generate a san csr', async () => {
|
||||||
const [key, csr] = await engine.createCsr({
|
const [key, csr] = await engine.createCsr({
|
||||||
commonName: testSanCsrDomains[0],
|
commonName: testSanCsrDomains[0],
|
||||||
altNames: testSanCsrDomains.slice(1, testSanCsrDomains.length)
|
altNames: testSanCsrDomains.slice(1, testSanCsrDomains.length),
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.isTrue(Buffer.isBuffer(key));
|
assert.isTrue(Buffer.isBuffer(key));
|
||||||
@@ -113,7 +108,7 @@ describe('crypto-legacy', () => {
|
|||||||
|
|
||||||
it('should generate a csr without common name', async () => {
|
it('should generate a csr without common name', async () => {
|
||||||
const [key, csr] = await engine.createCsr({
|
const [key, csr] = await engine.createCsr({
|
||||||
altNames: testSanCsrDomains
|
altNames: testSanCsrDomains,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.isTrue(Buffer.isBuffer(key));
|
assert.isTrue(Buffer.isBuffer(key));
|
||||||
@@ -126,7 +121,7 @@ describe('crypto-legacy', () => {
|
|||||||
const [key, csr] = await engine.createCsr({
|
const [key, csr] = await engine.createCsr({
|
||||||
commonName: testCsrDomain,
|
commonName: testCsrDomain,
|
||||||
organization: '大安區',
|
organization: '大安區',
|
||||||
organizationUnit: '中文部門'
|
organizationUnit: '中文部門',
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.isTrue(Buffer.isBuffer(key));
|
assert.isTrue(Buffer.isBuffer(key));
|
||||||
@@ -167,7 +162,6 @@ describe('crypto-legacy', () => {
|
|||||||
assert.deepStrictEqual(result.altNames, [testCsrDomain]);
|
assert.deepStrictEqual(result.altNames, [testCsrDomain]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Certificate
|
* Certificate
|
||||||
*/
|
*/
|
||||||
@@ -188,7 +182,6 @@ describe('crypto-legacy', () => {
|
|||||||
assert.deepEqual(info.domains.altNames, testSanCsrDomains.slice(1, testSanCsrDomains.length));
|
assert.deepEqual(info.domains.altNames, testSanCsrDomains.slice(1, testSanCsrDomains.length));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PEM utils
|
* PEM utils
|
||||||
*/
|
*/
|
||||||
@@ -214,7 +207,6 @@ describe('crypto-legacy', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modulus and exponent
|
* Modulus and exponent
|
||||||
*/
|
*/
|
||||||
@@ -246,7 +238,6 @@ describe('crypto-legacy', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify identical results
|
* Verify identical results
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ dGVzdGluZ3Rlc3Rpbmd0ZXN0aW5ndGVzdGluZ3Rlc3Rpbmd0ZXN0aW5ndGVzdGluZ3Rlc3Rpbmd0ZXN0
|
|||||||
-----END TEST-----
|
-----END TEST-----
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
||||||
describe('crypto', () => {
|
describe('crypto', () => {
|
||||||
const testCsrDomain = 'example.com';
|
const testCsrDomain = 'example.com';
|
||||||
const testSanCsrDomains = ['example.com', 'test.example.com', 'abc.example.com'];
|
const testSanCsrDomains = ['example.com', 'test.example.com', 'abc.example.com'];
|
||||||
@@ -58,7 +57,6 @@ describe('crypto', () => {
|
|||||||
const testCertPath = path.join(__dirname, 'fixtures', 'certificate.crt');
|
const testCertPath = path.join(__dirname, 'fixtures', 'certificate.crt');
|
||||||
const testSanCertPath = path.join(__dirname, 'fixtures', 'san-certificate.crt');
|
const testSanCertPath = path.join(__dirname, 'fixtures', 'san-certificate.crt');
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Key types
|
* Key types
|
||||||
*/
|
*/
|
||||||
@@ -68,24 +66,23 @@ describe('crypto', () => {
|
|||||||
createKeyFns: {
|
createKeyFns: {
|
||||||
s1024: () => crypto.createPrivateRsaKey(1024),
|
s1024: () => crypto.createPrivateRsaKey(1024),
|
||||||
s2048: () => crypto.createPrivateRsaKey(),
|
s2048: () => crypto.createPrivateRsaKey(),
|
||||||
s4096: () => crypto.createPrivateRsaKey(4096)
|
s4096: () => crypto.createPrivateRsaKey(4096),
|
||||||
},
|
},
|
||||||
jwkSpecFn: spec.jwk.rsa
|
jwkSpecFn: spec.jwk.rsa,
|
||||||
},
|
},
|
||||||
ecdsa: {
|
ecdsa: {
|
||||||
createKeyFns: {
|
createKeyFns: {
|
||||||
p256: () => crypto.createPrivateEcdsaKey(),
|
p256: () => crypto.createPrivateEcdsaKey(),
|
||||||
p384: () => crypto.createPrivateEcdsaKey('P-384'),
|
p384: () => crypto.createPrivateEcdsaKey('P-384'),
|
||||||
p521: () => crypto.createPrivateEcdsaKey('P-521')
|
p521: () => crypto.createPrivateEcdsaKey('P-521'),
|
||||||
},
|
},
|
||||||
jwkSpecFn: spec.jwk.ecdsa
|
jwkSpecFn: spec.jwk.ecdsa,
|
||||||
}
|
},
|
||||||
}).forEach(([name, { createKeyFns, jwkSpecFn }]) => {
|
}).forEach(([name, { createKeyFns, jwkSpecFn }]) => {
|
||||||
describe(name, () => {
|
describe(name, () => {
|
||||||
const testPrivateKeys = {};
|
const testPrivateKeys = {};
|
||||||
const testPublicKeys = {};
|
const testPublicKeys = {};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterate through all generator variations
|
* Iterate through all generator variations
|
||||||
*/
|
*/
|
||||||
@@ -97,7 +94,6 @@ describe('crypto', () => {
|
|||||||
let testNonAsciiCsr;
|
let testNonAsciiCsr;
|
||||||
let testAlpnCertificate;
|
let testAlpnCertificate;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keys and JWK
|
* Keys and JWK
|
||||||
*/
|
*/
|
||||||
@@ -132,14 +128,13 @@ describe('crypto', () => {
|
|||||||
jwkSpecFn(jwk);
|
jwkSpecFn(jwk);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Certificate Signing Request
|
* Certificate Signing Request
|
||||||
*/
|
*/
|
||||||
|
|
||||||
it(`${n}/should generate a csr`, async () => {
|
it(`${n}/should generate a csr`, async () => {
|
||||||
const [key, csr] = await crypto.createCsr({
|
const [key, csr] = await crypto.createCsr({
|
||||||
commonName: testCsrDomain
|
commonName: testCsrDomain,
|
||||||
}, testPrivateKeys[n]);
|
}, testPrivateKeys[n]);
|
||||||
|
|
||||||
assert.isTrue(Buffer.isBuffer(key));
|
assert.isTrue(Buffer.isBuffer(key));
|
||||||
@@ -151,7 +146,7 @@ describe('crypto', () => {
|
|||||||
it(`${n}/should generate a san csr`, async () => {
|
it(`${n}/should generate a san csr`, async () => {
|
||||||
const [key, csr] = await crypto.createCsr({
|
const [key, csr] = await crypto.createCsr({
|
||||||
commonName: testSanCsrDomains[0],
|
commonName: testSanCsrDomains[0],
|
||||||
altNames: testSanCsrDomains.slice(1, testSanCsrDomains.length)
|
altNames: testSanCsrDomains.slice(1, testSanCsrDomains.length),
|
||||||
}, testPrivateKeys[n]);
|
}, testPrivateKeys[n]);
|
||||||
|
|
||||||
assert.isTrue(Buffer.isBuffer(key));
|
assert.isTrue(Buffer.isBuffer(key));
|
||||||
@@ -162,7 +157,7 @@ describe('crypto', () => {
|
|||||||
|
|
||||||
it(`${n}/should generate a csr without common name`, async () => {
|
it(`${n}/should generate a csr without common name`, async () => {
|
||||||
const [key, csr] = await crypto.createCsr({
|
const [key, csr] = await crypto.createCsr({
|
||||||
altNames: testSanCsrDomains
|
altNames: testSanCsrDomains,
|
||||||
}, testPrivateKeys[n]);
|
}, testPrivateKeys[n]);
|
||||||
|
|
||||||
assert.isTrue(Buffer.isBuffer(key));
|
assert.isTrue(Buffer.isBuffer(key));
|
||||||
@@ -175,7 +170,7 @@ describe('crypto', () => {
|
|||||||
const [key, csr] = await crypto.createCsr({
|
const [key, csr] = await crypto.createCsr({
|
||||||
commonName: testCsrDomain,
|
commonName: testCsrDomain,
|
||||||
organization: '大安區',
|
organization: '大安區',
|
||||||
organizationUnit: '中文部門'
|
organizationUnit: '中文部門',
|
||||||
}, testPrivateKeys[n]);
|
}, testPrivateKeys[n]);
|
||||||
|
|
||||||
assert.isTrue(Buffer.isBuffer(key));
|
assert.isTrue(Buffer.isBuffer(key));
|
||||||
@@ -186,7 +181,7 @@ describe('crypto', () => {
|
|||||||
|
|
||||||
it(`${n}/should generate a csr with key as string`, async () => {
|
it(`${n}/should generate a csr with key as string`, async () => {
|
||||||
const [key, csr] = await crypto.createCsr({
|
const [key, csr] = await crypto.createCsr({
|
||||||
commonName: testCsrDomain
|
commonName: testCsrDomain,
|
||||||
}, testPrivateKeys[n].toString());
|
}, testPrivateKeys[n].toString());
|
||||||
|
|
||||||
assert.isTrue(Buffer.isBuffer(key));
|
assert.isTrue(Buffer.isBuffer(key));
|
||||||
@@ -195,11 +190,10 @@ describe('crypto', () => {
|
|||||||
|
|
||||||
it(`${n}/should throw with invalid key`, async () => {
|
it(`${n}/should throw with invalid key`, async () => {
|
||||||
await assert.isRejected(crypto.createCsr({
|
await assert.isRejected(crypto.createCsr({
|
||||||
commonName: testCsrDomain
|
commonName: testCsrDomain,
|
||||||
}, testPublicKeys[n]));
|
}, testPublicKeys[n]));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Domain and info resolver
|
* Domain and info resolver
|
||||||
*/
|
*/
|
||||||
@@ -243,7 +237,6 @@ describe('crypto', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ALPN
|
* ALPN
|
||||||
*/
|
*/
|
||||||
@@ -284,7 +277,6 @@ describe('crypto', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Common functionality
|
* Common functionality
|
||||||
*/
|
*/
|
||||||
@@ -294,7 +286,6 @@ describe('crypto', () => {
|
|||||||
let testCert;
|
let testCert;
|
||||||
let testSanCert;
|
let testSanCert;
|
||||||
|
|
||||||
|
|
||||||
it('should read private key fixture', async () => {
|
it('should read private key fixture', async () => {
|
||||||
testPemKey = await fs.readFile(testKeyPath);
|
testPemKey = await fs.readFile(testKeyPath);
|
||||||
assert.isTrue(Buffer.isBuffer(testPemKey));
|
assert.isTrue(Buffer.isBuffer(testPemKey));
|
||||||
@@ -310,21 +301,19 @@ describe('crypto', () => {
|
|||||||
assert.isTrue(Buffer.isBuffer(testSanCert));
|
assert.isTrue(Buffer.isBuffer(testSanCert));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CSR with auto-generated key
|
* CSR with auto-generated key
|
||||||
*/
|
*/
|
||||||
|
|
||||||
it('should generate a csr with default key', async () => {
|
it('should generate a csr with default key', async () => {
|
||||||
const [key, csr] = await crypto.createCsr({
|
const [key, csr] = await crypto.createCsr({
|
||||||
commonName: testCsrDomain
|
commonName: testCsrDomain,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.isTrue(Buffer.isBuffer(key));
|
assert.isTrue(Buffer.isBuffer(key));
|
||||||
assert.isTrue(Buffer.isBuffer(csr));
|
assert.isTrue(Buffer.isBuffer(csr));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Certificate
|
* Certificate
|
||||||
*/
|
*/
|
||||||
@@ -352,7 +341,6 @@ describe('crypto', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ALPN
|
* ALPN
|
||||||
*/
|
*/
|
||||||
@@ -365,7 +353,6 @@ describe('crypto', () => {
|
|||||||
assert.isTrue(Buffer.isBuffer(cert));
|
assert.isTrue(Buffer.isBuffer(cert));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PEM utils
|
* PEM utils
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -20,35 +20,32 @@ const clientOpts = {
|
|||||||
directoryUrl,
|
directoryUrl,
|
||||||
backoffAttempts: 5,
|
backoffAttempts: 5,
|
||||||
backoffMin: 1000,
|
backoffMin: 1000,
|
||||||
backoffMax: 5000
|
backoffMax: 5000,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (capEabEnabled && process.env.ACME_EAB_KID && process.env.ACME_EAB_HMAC_KEY) {
|
if (capEabEnabled && process.env.ACME_EAB_KID && process.env.ACME_EAB_HMAC_KEY) {
|
||||||
clientOpts.externalAccountBinding = {
|
clientOpts.externalAccountBinding = {
|
||||||
kid: process.env.ACME_EAB_KID,
|
kid: process.env.ACME_EAB_KID,
|
||||||
hmacKey: process.env.ACME_EAB_HMAC_KEY
|
hmacKey: process.env.ACME_EAB_HMAC_KEY,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
describe('client', () => {
|
describe('client', () => {
|
||||||
const testDomain = `${uuid()}.${domainName}`;
|
const testDomain = `${uuid()}.${domainName}`;
|
||||||
const testDomainAlpn = `${uuid()}.${domainName}`;
|
const testDomainAlpn = `${uuid()}.${domainName}`;
|
||||||
const testDomainWildcard = `*.${testDomain}`;
|
const testDomainWildcard = `*.${testDomain}`;
|
||||||
const testContact = `mailto:test-${uuid()}@nope.com`;
|
const testContact = `mailto:test-${uuid()}@nope.com`;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pebble CTS required
|
* Pebble CTS required
|
||||||
*/
|
*/
|
||||||
|
|
||||||
before(function() {
|
before(function () {
|
||||||
if (!cts.isEnabled()) {
|
if (!cts.isEnabled()) {
|
||||||
this.skip();
|
this.skip();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Key types
|
* Key types
|
||||||
*/
|
*/
|
||||||
@@ -58,18 +55,18 @@ describe('client', () => {
|
|||||||
createKeyFn: () => acme.crypto.createPrivateRsaKey(),
|
createKeyFn: () => acme.crypto.createPrivateRsaKey(),
|
||||||
createKeyAltFns: {
|
createKeyAltFns: {
|
||||||
s1024: () => acme.crypto.createPrivateRsaKey(1024),
|
s1024: () => acme.crypto.createPrivateRsaKey(1024),
|
||||||
s4096: () => acme.crypto.createPrivateRsaKey(4096)
|
s4096: () => acme.crypto.createPrivateRsaKey(4096),
|
||||||
},
|
},
|
||||||
jwkSpecFn: spec.jwk.rsa
|
jwkSpecFn: spec.jwk.rsa,
|
||||||
},
|
},
|
||||||
ecdsa: {
|
ecdsa: {
|
||||||
createKeyFn: () => acme.crypto.createPrivateEcdsaKey(),
|
createKeyFn: () => acme.crypto.createPrivateEcdsaKey(),
|
||||||
createKeyAltFns: {
|
createKeyAltFns: {
|
||||||
p384: () => acme.crypto.createPrivateEcdsaKey('P-384'),
|
p384: () => acme.crypto.createPrivateEcdsaKey('P-384'),
|
||||||
p521: () => acme.crypto.createPrivateEcdsaKey('P-521')
|
p521: () => acme.crypto.createPrivateEcdsaKey('P-521'),
|
||||||
},
|
},
|
||||||
jwkSpecFn: spec.jwk.ecdsa
|
jwkSpecFn: spec.jwk.ecdsa,
|
||||||
}
|
},
|
||||||
}).forEach(([name, { createKeyFn, createKeyAltFns, jwkSpecFn }]) => {
|
}).forEach(([name, { createKeyFn, createKeyAltFns, jwkSpecFn }]) => {
|
||||||
describe(name, () => {
|
describe(name, () => {
|
||||||
let testIssuers;
|
let testIssuers;
|
||||||
@@ -97,7 +94,6 @@ describe('client', () => {
|
|||||||
let testCertificateAlpn;
|
let testCertificateAlpn;
|
||||||
let testCertificateWildcard;
|
let testCertificateWildcard;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fixtures
|
* Fixtures
|
||||||
*/
|
*/
|
||||||
@@ -114,11 +110,11 @@ describe('client', () => {
|
|||||||
|
|
||||||
it('should generate certificate signing request', async () => {
|
it('should generate certificate signing request', async () => {
|
||||||
[, testCsr] = await acme.crypto.createCsr({ commonName: testDomain }, await createKeyFn());
|
[, testCsr] = await acme.crypto.createCsr({ commonName: testDomain }, await createKeyFn());
|
||||||
[, testCsrAlpn] = await acme.crypto.createCsr({ commonName: testDomainAlpn }, await createKeyFn());
|
[, testCsrAlpn] = await acme.crypto.createCsr({ altNames: [testDomainAlpn] }, await createKeyFn());
|
||||||
[, testCsrWildcard] = await acme.crypto.createCsr({ commonName: testDomainWildcard }, await createKeyFn());
|
[, testCsrWildcard] = await acme.crypto.createCsr({ altNames: [testDomainWildcard] }, await createKeyFn());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should resolve certificate issuers [ACME_CAP_ALTERNATE_CERT_ROOTS]', async function() {
|
it('should resolve certificate issuers [ACME_CAP_ALTERNATE_CERT_ROOTS]', async function () {
|
||||||
if (!capAlternateCertRoots) {
|
if (!capAlternateCertRoots) {
|
||||||
this.skip();
|
this.skip();
|
||||||
}
|
}
|
||||||
@@ -134,7 +130,6 @@ describe('client', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize clients
|
* Initialize clients
|
||||||
*/
|
*/
|
||||||
@@ -142,7 +137,7 @@ describe('client', () => {
|
|||||||
it('should initialize client', () => {
|
it('should initialize client', () => {
|
||||||
testClient = new acme.Client({
|
testClient = new acme.Client({
|
||||||
...clientOpts,
|
...clientOpts,
|
||||||
accountKey: testAccountKey
|
accountKey: testAccountKey,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -151,12 +146,11 @@ describe('client', () => {
|
|||||||
jwkSpecFn(jwk);
|
jwkSpecFn(jwk);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Terms of Service
|
* Terms of Service
|
||||||
*/
|
*/
|
||||||
|
|
||||||
it('should produce tos url [ACME_CAP_META_TOS_FIELD]', async function() {
|
it('should produce tos url [ACME_CAP_META_TOS_FIELD]', async function () {
|
||||||
if (!capMetaTosField) {
|
if (!capMetaTosField) {
|
||||||
this.skip();
|
this.skip();
|
||||||
}
|
}
|
||||||
@@ -165,7 +159,7 @@ describe('client', () => {
|
|||||||
assert.isString(tos);
|
assert.isString(tos);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not produce tos url [!ACME_CAP_META_TOS_FIELD]', async function() {
|
it('should not produce tos url [!ACME_CAP_META_TOS_FIELD]', async function () {
|
||||||
if (capMetaTosField) {
|
if (capMetaTosField) {
|
||||||
this.skip();
|
this.skip();
|
||||||
}
|
}
|
||||||
@@ -174,12 +168,11 @@ describe('client', () => {
|
|||||||
assert.isNull(tos);
|
assert.isNull(tos);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create account
|
* Create account
|
||||||
*/
|
*/
|
||||||
|
|
||||||
it('should refuse account creation without tos [ACME_CAP_META_TOS_FIELD]', async function() {
|
it('should refuse account creation without tos [ACME_CAP_META_TOS_FIELD]', async function () {
|
||||||
if (!capMetaTosField) {
|
if (!capMetaTosField) {
|
||||||
this.skip();
|
this.skip();
|
||||||
}
|
}
|
||||||
@@ -187,7 +180,7 @@ describe('client', () => {
|
|||||||
await assert.isRejected(testClient.createAccount());
|
await assert.isRejected(testClient.createAccount());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should refuse account creation without eab [ACME_CAP_EAB_ENABLED]', async function() {
|
it('should refuse account creation without eab [ACME_CAP_EAB_ENABLED]', async function () {
|
||||||
if (!capEabEnabled) {
|
if (!capEabEnabled) {
|
||||||
this.skip();
|
this.skip();
|
||||||
}
|
}
|
||||||
@@ -195,17 +188,17 @@ describe('client', () => {
|
|||||||
const client = new acme.Client({
|
const client = new acme.Client({
|
||||||
...clientOpts,
|
...clientOpts,
|
||||||
accountKey: testAccountKey,
|
accountKey: testAccountKey,
|
||||||
externalAccountBinding: null
|
externalAccountBinding: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
await assert.isRejected(client.createAccount({
|
await assert.isRejected(client.createAccount({
|
||||||
termsOfServiceAgreed: true
|
termsOfServiceAgreed: true,
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create an account', async () => {
|
it('should create an account', async () => {
|
||||||
testAccount = await testClient.createAccount({
|
testAccount = await testClient.createAccount({
|
||||||
termsOfServiceAgreed: true
|
termsOfServiceAgreed: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
spec.rfc8555.account(testAccount);
|
spec.rfc8555.account(testAccount);
|
||||||
@@ -217,7 +210,6 @@ describe('client', () => {
|
|||||||
assert.isString(testAccountUrl);
|
assert.isString(testAccountUrl);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create account with alternate key sizes
|
* Create account with alternate key sizes
|
||||||
*/
|
*/
|
||||||
@@ -226,11 +218,11 @@ describe('client', () => {
|
|||||||
it(`should create account with key=${k}`, async () => {
|
it(`should create account with key=${k}`, async () => {
|
||||||
const client = new acme.Client({
|
const client = new acme.Client({
|
||||||
...clientOpts,
|
...clientOpts,
|
||||||
accountKey: await altKeyFn()
|
accountKey: await altKeyFn(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const account = await client.createAccount({
|
const account = await client.createAccount({
|
||||||
termsOfServiceAgreed: true
|
termsOfServiceAgreed: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
spec.rfc8555.account(account);
|
spec.rfc8555.account(account);
|
||||||
@@ -238,7 +230,6 @@ describe('client', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find existing account using secondary client
|
* Find existing account using secondary client
|
||||||
*/
|
*/
|
||||||
@@ -246,22 +237,22 @@ describe('client', () => {
|
|||||||
it('should throw when trying to find account using invalid account key', async () => {
|
it('should throw when trying to find account using invalid account key', async () => {
|
||||||
const client = new acme.Client({
|
const client = new acme.Client({
|
||||||
...clientOpts,
|
...clientOpts,
|
||||||
accountKey: testAccountSecondaryKey
|
accountKey: testAccountSecondaryKey,
|
||||||
});
|
});
|
||||||
|
|
||||||
await assert.isRejected(client.createAccount({
|
await assert.isRejected(client.createAccount({
|
||||||
onlyReturnExisting: true
|
onlyReturnExisting: true,
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should find existing account using account key', async () => {
|
it('should find existing account using account key', async () => {
|
||||||
const client = new acme.Client({
|
const client = new acme.Client({
|
||||||
...clientOpts,
|
...clientOpts,
|
||||||
accountKey: testAccountKey
|
accountKey: testAccountKey,
|
||||||
});
|
});
|
||||||
|
|
||||||
const account = await client.createAccount({
|
const account = await client.createAccount({
|
||||||
onlyReturnExisting: true
|
onlyReturnExisting: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
spec.rfc8555.account(account);
|
spec.rfc8555.account(account);
|
||||||
@@ -269,7 +260,6 @@ describe('client', () => {
|
|||||||
assert.deepStrictEqual(account.key, testAccount.key);
|
assert.deepStrictEqual(account.key, testAccount.key);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Account URL
|
* Account URL
|
||||||
*/
|
*/
|
||||||
@@ -278,7 +268,7 @@ describe('client', () => {
|
|||||||
const client = new acme.Client({
|
const client = new acme.Client({
|
||||||
...clientOpts,
|
...clientOpts,
|
||||||
accountKey: testAccountKey,
|
accountKey: testAccountKey,
|
||||||
accountUrl: 'https://acme-staging-v02.api.letsencrypt.org/acme/acct/1'
|
accountUrl: 'https://acme-staging-v02.api.letsencrypt.org/acme/acct/1',
|
||||||
});
|
});
|
||||||
|
|
||||||
await assert.isRejected(client.updateAccount());
|
await assert.isRejected(client.updateAccount());
|
||||||
@@ -288,11 +278,11 @@ describe('client', () => {
|
|||||||
const client = new acme.Client({
|
const client = new acme.Client({
|
||||||
...clientOpts,
|
...clientOpts,
|
||||||
accountKey: testAccountKey,
|
accountKey: testAccountKey,
|
||||||
accountUrl: testAccountUrl
|
accountUrl: testAccountUrl,
|
||||||
});
|
});
|
||||||
|
|
||||||
const account = await client.createAccount({
|
const account = await client.createAccount({
|
||||||
onlyReturnExisting: true
|
onlyReturnExisting: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
spec.rfc8555.account(account);
|
spec.rfc8555.account(account);
|
||||||
@@ -300,7 +290,6 @@ describe('client', () => {
|
|||||||
assert.deepStrictEqual(account.key, testAccount.key);
|
assert.deepStrictEqual(account.key, testAccount.key);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update account contact info
|
* Update account contact info
|
||||||
*/
|
*/
|
||||||
@@ -316,12 +305,11 @@ describe('client', () => {
|
|||||||
assert.include(account.contact, testContact);
|
assert.include(account.contact, testContact);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change account private key
|
* Change account private key
|
||||||
*/
|
*/
|
||||||
|
|
||||||
it('should change account private key [ACME_CAP_UPDATE_ACCOUNT_KEY]', async function() {
|
it('should change account private key [ACME_CAP_UPDATE_ACCOUNT_KEY]', async function () {
|
||||||
if (!capUpdateAccountKey) {
|
if (!capUpdateAccountKey) {
|
||||||
this.skip();
|
this.skip();
|
||||||
}
|
}
|
||||||
@@ -329,7 +317,7 @@ describe('client', () => {
|
|||||||
await testClient.updateAccountKey(testAccountSecondaryKey);
|
await testClient.updateAccountKey(testAccountSecondaryKey);
|
||||||
|
|
||||||
const account = await testClient.createAccount({
|
const account = await testClient.createAccount({
|
||||||
onlyReturnExisting: true
|
onlyReturnExisting: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
spec.rfc8555.account(account);
|
spec.rfc8555.account(account);
|
||||||
@@ -337,7 +325,6 @@ describe('client', () => {
|
|||||||
assert.notDeepEqual(account.key, testAccount.key);
|
assert.notDeepEqual(account.key, testAccount.key);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new certificate order
|
* Create new certificate order
|
||||||
*/
|
*/
|
||||||
@@ -357,7 +344,6 @@ describe('client', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get status of existing certificate order
|
* Get status of existing certificate order
|
||||||
*/
|
*/
|
||||||
@@ -371,7 +357,6 @@ describe('client', () => {
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get identifier authorization
|
* Get identifier authorization
|
||||||
*/
|
*/
|
||||||
@@ -401,7 +386,6 @@ describe('client', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate challenge key authorization
|
* Generate challenge key authorization
|
||||||
*/
|
*/
|
||||||
@@ -418,7 +402,6 @@ describe('client', () => {
|
|||||||
[testKeyAuthorization, testKeyAuthorizationAlpn, testKeyAuthorizationWildcard].forEach((k) => assert.isString(k));
|
[testKeyAuthorization, testKeyAuthorizationAlpn, testKeyAuthorizationWildcard].forEach((k) => assert.isString(k));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deactivate identifier authorization
|
* Deactivate identifier authorization
|
||||||
*/
|
*/
|
||||||
@@ -427,8 +410,8 @@ describe('client', () => {
|
|||||||
const order = await testClient.createOrder({
|
const order = await testClient.createOrder({
|
||||||
identifiers: [
|
identifiers: [
|
||||||
{ type: 'dns', value: `${uuid()}.${domainName}` },
|
{ type: 'dns', value: `${uuid()}.${domainName}` },
|
||||||
{ type: 'dns', value: `${uuid()}.${domainName}` }
|
{ type: 'dns', value: `${uuid()}.${domainName}` },
|
||||||
]
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const authzCollection = await testClient.getAuthorizations(order);
|
const authzCollection = await testClient.getAuthorizations(order);
|
||||||
@@ -445,7 +428,6 @@ describe('client', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify satisfied challenge
|
* Verify satisfied challenge
|
||||||
*/
|
*/
|
||||||
@@ -460,7 +442,6 @@ describe('client', () => {
|
|||||||
await testClient.verifyChallenge(testAuthzWildcard, testChallengeWildcard);
|
await testClient.verifyChallenge(testAuthzWildcard, testChallengeWildcard);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Complete challenge
|
* Complete challenge
|
||||||
*/
|
*/
|
||||||
@@ -474,7 +455,6 @@ describe('client', () => {
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wait for valid challenge
|
* Wait for valid challenge
|
||||||
*/
|
*/
|
||||||
@@ -483,7 +463,6 @@ describe('client', () => {
|
|||||||
await Promise.all([testChallenge, testChallengeAlpn, testChallengeWildcard].map(async (c) => testClient.waitForValidStatus(c)));
|
await Promise.all([testChallenge, testChallengeAlpn, testChallengeWildcard].map(async (c) => testClient.waitForValidStatus(c)));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finalize order
|
* Finalize order
|
||||||
*/
|
*/
|
||||||
@@ -500,7 +479,6 @@ describe('client', () => {
|
|||||||
assert.strictEqual(testOrderWildcard.url, finalizeWildcard.url);
|
assert.strictEqual(testOrderWildcard.url, finalizeWildcard.url);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wait for valid order
|
* Wait for valid order
|
||||||
*/
|
*/
|
||||||
@@ -509,7 +487,6 @@ describe('client', () => {
|
|||||||
await Promise.all([testOrder, testOrderAlpn, testOrderWildcard].map(async (o) => testClient.waitForValidStatus(o)));
|
await Promise.all([testOrder, testOrderAlpn, testOrderWildcard].map(async (o) => testClient.waitForValidStatus(o)));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get certificate
|
* Get certificate
|
||||||
*/
|
*/
|
||||||
@@ -525,7 +502,7 @@ describe('client', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get alternate certificate chain [ACME_CAP_ALTERNATE_CERT_ROOTS]', async function() {
|
it('should get alternate certificate chain [ACME_CAP_ALTERNATE_CERT_ROOTS]', async function () {
|
||||||
if (!capAlternateCertRoots) {
|
if (!capAlternateCertRoots) {
|
||||||
this.skip();
|
this.skip();
|
||||||
}
|
}
|
||||||
@@ -539,7 +516,7 @@ describe('client', () => {
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get default chain with invalid preference [ACME_CAP_ALTERNATE_CERT_ROOTS]', async function() {
|
it('should get default chain with invalid preference [ACME_CAP_ALTERNATE_CERT_ROOTS]', async function () {
|
||||||
if (!capAlternateCertRoots) {
|
if (!capAlternateCertRoots) {
|
||||||
this.skip();
|
this.skip();
|
||||||
}
|
}
|
||||||
@@ -551,7 +528,6 @@ describe('client', () => {
|
|||||||
assert.strictEqual(testIssuers[0], info.issuer.commonName);
|
assert.strictEqual(testIssuers[0], info.issuer.commonName);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Revoke certificate
|
* Revoke certificate
|
||||||
*/
|
*/
|
||||||
@@ -568,7 +544,6 @@ describe('client', () => {
|
|||||||
await assert.isRejected(testClient.getCertificate(testOrderWildcard));
|
await assert.isRejected(testClient.getCertificate(testOrderWildcard));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deactivate account
|
* Deactivate account
|
||||||
*/
|
*/
|
||||||
@@ -581,7 +556,6 @@ describe('client', () => {
|
|||||||
assert.strictEqual(account.status, 'deactivated');
|
assert.strictEqual(account.status, 'deactivated');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify that no new orders can be made
|
* Verify that no new orders can be made
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -18,17 +18,16 @@ const clientOpts = {
|
|||||||
directoryUrl,
|
directoryUrl,
|
||||||
backoffAttempts: 5,
|
backoffAttempts: 5,
|
||||||
backoffMin: 1000,
|
backoffMin: 1000,
|
||||||
backoffMax: 5000
|
backoffMax: 5000,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (capEabEnabled && process.env.ACME_EAB_KID && process.env.ACME_EAB_HMAC_KEY) {
|
if (capEabEnabled && process.env.ACME_EAB_KID && process.env.ACME_EAB_HMAC_KEY) {
|
||||||
clientOpts.externalAccountBinding = {
|
clientOpts.externalAccountBinding = {
|
||||||
kid: process.env.ACME_EAB_KID,
|
kid: process.env.ACME_EAB_KID,
|
||||||
hmacKey: process.env.ACME_EAB_HMAC_KEY
|
hmacKey: process.env.ACME_EAB_HMAC_KEY,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
describe('client.auto', () => {
|
describe('client.auto', () => {
|
||||||
const testDomain = `${uuid()}.${domainName}`;
|
const testDomain = `${uuid()}.${domainName}`;
|
||||||
const testHttpDomain = `${uuid()}.${domainName}`;
|
const testHttpDomain = `${uuid()}.${domainName}`;
|
||||||
@@ -40,21 +39,19 @@ describe('client.auto', () => {
|
|||||||
const testSanDomains = [
|
const testSanDomains = [
|
||||||
`${uuid()}.${domainName}`,
|
`${uuid()}.${domainName}`,
|
||||||
`${uuid()}.${domainName}`,
|
`${uuid()}.${domainName}`,
|
||||||
`${uuid()}.${domainName}`
|
`${uuid()}.${domainName}`,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pebble CTS required
|
* Pebble CTS required
|
||||||
*/
|
*/
|
||||||
|
|
||||||
before(function() {
|
before(function () {
|
||||||
if (!cts.isEnabled()) {
|
if (!cts.isEnabled()) {
|
||||||
this.skip();
|
this.skip();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Key types
|
* Key types
|
||||||
*/
|
*/
|
||||||
@@ -64,16 +61,16 @@ describe('client.auto', () => {
|
|||||||
createKeyFn: () => acme.crypto.createPrivateRsaKey(),
|
createKeyFn: () => acme.crypto.createPrivateRsaKey(),
|
||||||
createKeyAltFns: {
|
createKeyAltFns: {
|
||||||
s1024: () => acme.crypto.createPrivateRsaKey(1024),
|
s1024: () => acme.crypto.createPrivateRsaKey(1024),
|
||||||
s4096: () => acme.crypto.createPrivateRsaKey(4096)
|
s4096: () => acme.crypto.createPrivateRsaKey(4096),
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
ecdsa: {
|
ecdsa: {
|
||||||
createKeyFn: () => acme.crypto.createPrivateEcdsaKey(),
|
createKeyFn: () => acme.crypto.createPrivateEcdsaKey(),
|
||||||
createKeyAltFns: {
|
createKeyAltFns: {
|
||||||
p384: () => acme.crypto.createPrivateEcdsaKey('P-384'),
|
p384: () => acme.crypto.createPrivateEcdsaKey('P-384'),
|
||||||
p521: () => acme.crypto.createPrivateEcdsaKey('P-521')
|
p521: () => acme.crypto.createPrivateEcdsaKey('P-521'),
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}).forEach(([name, { createKeyFn, createKeyAltFns }]) => {
|
}).forEach(([name, { createKeyFn, createKeyAltFns }]) => {
|
||||||
describe(name, () => {
|
describe(name, () => {
|
||||||
let testIssuers;
|
let testIssuers;
|
||||||
@@ -82,12 +79,11 @@ describe('client.auto', () => {
|
|||||||
let testSanCertificate;
|
let testSanCertificate;
|
||||||
let testWildcardCertificate;
|
let testWildcardCertificate;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fixtures
|
* Fixtures
|
||||||
*/
|
*/
|
||||||
|
|
||||||
it('should resolve certificate issuers [ACME_CAP_ALTERNATE_CERT_ROOTS]', async function() {
|
it('should resolve certificate issuers [ACME_CAP_ALTERNATE_CERT_ROOTS]', async function () {
|
||||||
if (!capAlternateCertRoots) {
|
if (!capAlternateCertRoots) {
|
||||||
this.skip();
|
this.skip();
|
||||||
}
|
}
|
||||||
@@ -103,7 +99,6 @@ describe('client.auto', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize client
|
* Initialize client
|
||||||
*/
|
*/
|
||||||
@@ -111,31 +106,30 @@ describe('client.auto', () => {
|
|||||||
it('should initialize client', async () => {
|
it('should initialize client', async () => {
|
||||||
testClient = new acme.Client({
|
testClient = new acme.Client({
|
||||||
...clientOpts,
|
...clientOpts,
|
||||||
accountKey: await createKeyFn()
|
accountKey: await createKeyFn(),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invalid challenge response
|
* Invalid challenge response
|
||||||
*/
|
*/
|
||||||
|
|
||||||
it('should throw on invalid challenge response', async () => {
|
it('should throw on invalid challenge response', async () => {
|
||||||
const [, csr] = await acme.crypto.createCsr({
|
const [, csr] = await acme.crypto.createCsr({
|
||||||
commonName: `${uuid()}.${domainName}`
|
commonName: `${uuid()}.${domainName}`,
|
||||||
}, await createKeyFn());
|
}, await createKeyFn());
|
||||||
|
|
||||||
await assert.isRejected(testClient.auto({
|
await assert.isRejected(testClient.auto({
|
||||||
csr,
|
csr,
|
||||||
termsOfServiceAgreed: true,
|
termsOfServiceAgreed: true,
|
||||||
challengeCreateFn: cts.challengeNoopFn,
|
challengeCreateFn: cts.challengeNoopFn,
|
||||||
challengeRemoveFn: cts.challengeNoopFn
|
challengeRemoveFn: cts.challengeNoopFn,
|
||||||
}), /^authorization not found/i);
|
}), /^authorization not found/i);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw on invalid challenge response with opts.skipChallengeVerification=true', async () => {
|
it('should throw on invalid challenge response with opts.skipChallengeVerification=true', async () => {
|
||||||
const [, csr] = await acme.crypto.createCsr({
|
const [, csr] = await acme.crypto.createCsr({
|
||||||
commonName: `${uuid()}.${domainName}`
|
commonName: `${uuid()}.${domainName}`,
|
||||||
}, await createKeyFn());
|
}, await createKeyFn());
|
||||||
|
|
||||||
await assert.isRejected(testClient.auto({
|
await assert.isRejected(testClient.auto({
|
||||||
@@ -143,38 +137,37 @@ describe('client.auto', () => {
|
|||||||
termsOfServiceAgreed: true,
|
termsOfServiceAgreed: true,
|
||||||
skipChallengeVerification: true,
|
skipChallengeVerification: true,
|
||||||
challengeCreateFn: cts.challengeNoopFn,
|
challengeCreateFn: cts.challengeNoopFn,
|
||||||
challengeRemoveFn: cts.challengeNoopFn
|
challengeRemoveFn: cts.challengeNoopFn,
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Challenge function exceptions
|
* Challenge function exceptions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
it('should throw on challengeCreate exception', async () => {
|
it('should throw on challengeCreate exception', async () => {
|
||||||
const [, csr] = await acme.crypto.createCsr({
|
const [, csr] = await acme.crypto.createCsr({
|
||||||
commonName: `${uuid()}.${domainName}`
|
commonName: `${uuid()}.${domainName}`,
|
||||||
}, await createKeyFn());
|
}, await createKeyFn());
|
||||||
|
|
||||||
await assert.isRejected(testClient.auto({
|
await assert.isRejected(testClient.auto({
|
||||||
csr,
|
csr,
|
||||||
termsOfServiceAgreed: true,
|
termsOfServiceAgreed: true,
|
||||||
challengeCreateFn: cts.challengeThrowFn,
|
challengeCreateFn: cts.challengeThrowFn,
|
||||||
challengeRemoveFn: cts.challengeNoopFn
|
challengeRemoveFn: cts.challengeNoopFn,
|
||||||
}), /^oops$/);
|
}), /^oops$/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not throw on challengeRemove exception', async () => {
|
it('should not throw on challengeRemove exception', async () => {
|
||||||
const [, csr] = await acme.crypto.createCsr({
|
const [, csr] = await acme.crypto.createCsr({
|
||||||
commonName: `${uuid()}.${domainName}`
|
commonName: `${uuid()}.${domainName}`,
|
||||||
}, await createKeyFn());
|
}, await createKeyFn());
|
||||||
|
|
||||||
const cert = await testClient.auto({
|
const cert = await testClient.auto({
|
||||||
csr,
|
csr,
|
||||||
termsOfServiceAgreed: true,
|
termsOfServiceAgreed: true,
|
||||||
challengeCreateFn: cts.challengeCreateFn,
|
challengeCreateFn: cts.challengeCreateFn,
|
||||||
challengeRemoveFn: cts.challengeThrowFn
|
challengeRemoveFn: cts.challengeThrowFn,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.isString(cert);
|
assert.isString(cert);
|
||||||
@@ -188,8 +181,8 @@ describe('client.auto', () => {
|
|||||||
`${uuid()}.${domainName}`,
|
`${uuid()}.${domainName}`,
|
||||||
`${uuid()}.${domainName}`,
|
`${uuid()}.${domainName}`,
|
||||||
`${uuid()}.${domainName}`,
|
`${uuid()}.${domainName}`,
|
||||||
`${uuid()}.${domainName}`
|
`${uuid()}.${domainName}`,
|
||||||
]
|
],
|
||||||
}, await createKeyFn());
|
}, await createKeyFn());
|
||||||
|
|
||||||
await assert.isRejected(testClient.auto({
|
await assert.isRejected(testClient.auto({
|
||||||
@@ -205,28 +198,27 @@ describe('client.auto', () => {
|
|||||||
results.push(true);
|
results.push(true);
|
||||||
return cts.challengeCreateFn(...args);
|
return cts.challengeCreateFn(...args);
|
||||||
},
|
},
|
||||||
challengeRemoveFn: cts.challengeRemoveFn
|
challengeRemoveFn: cts.challengeRemoveFn,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
assert.strictEqual(results.length, 5);
|
assert.strictEqual(results.length, 5);
|
||||||
assert.deepStrictEqual(results, [false, false, false, true, true]);
|
assert.deepStrictEqual(results, [false, false, false, true, true]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Order certificates
|
* Order certificates
|
||||||
*/
|
*/
|
||||||
|
|
||||||
it('should order certificate', async () => {
|
it('should order certificate', async () => {
|
||||||
const [, csr] = await acme.crypto.createCsr({
|
const [, csr] = await acme.crypto.createCsr({
|
||||||
commonName: testDomain
|
commonName: testDomain,
|
||||||
}, await createKeyFn());
|
}, await createKeyFn());
|
||||||
|
|
||||||
const cert = await testClient.auto({
|
const cert = await testClient.auto({
|
||||||
csr,
|
csr,
|
||||||
termsOfServiceAgreed: true,
|
termsOfServiceAgreed: true,
|
||||||
challengeCreateFn: cts.challengeCreateFn,
|
challengeCreateFn: cts.challengeCreateFn,
|
||||||
challengeRemoveFn: cts.challengeRemoveFn
|
challengeRemoveFn: cts.challengeRemoveFn,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.isString(cert);
|
assert.isString(cert);
|
||||||
@@ -235,7 +227,7 @@ describe('client.auto', () => {
|
|||||||
|
|
||||||
it('should order certificate using http-01', async () => {
|
it('should order certificate using http-01', async () => {
|
||||||
const [, csr] = await acme.crypto.createCsr({
|
const [, csr] = await acme.crypto.createCsr({
|
||||||
commonName: testHttpDomain
|
commonName: testHttpDomain,
|
||||||
}, await createKeyFn());
|
}, await createKeyFn());
|
||||||
|
|
||||||
const cert = await testClient.auto({
|
const cert = await testClient.auto({
|
||||||
@@ -243,7 +235,7 @@ describe('client.auto', () => {
|
|||||||
termsOfServiceAgreed: true,
|
termsOfServiceAgreed: true,
|
||||||
challengeCreateFn: cts.assertHttpChallengeCreateFn,
|
challengeCreateFn: cts.assertHttpChallengeCreateFn,
|
||||||
challengeRemoveFn: cts.challengeRemoveFn,
|
challengeRemoveFn: cts.challengeRemoveFn,
|
||||||
challengePriority: ['http-01']
|
challengePriority: ['http-01'],
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.isString(cert);
|
assert.isString(cert);
|
||||||
@@ -251,7 +243,7 @@ describe('client.auto', () => {
|
|||||||
|
|
||||||
it('should order certificate using https-01', async () => {
|
it('should order certificate using https-01', async () => {
|
||||||
const [, csr] = await acme.crypto.createCsr({
|
const [, csr] = await acme.crypto.createCsr({
|
||||||
commonName: testHttpsDomain
|
commonName: testHttpsDomain,
|
||||||
}, await createKeyFn());
|
}, await createKeyFn());
|
||||||
|
|
||||||
const cert = await testClient.auto({
|
const cert = await testClient.auto({
|
||||||
@@ -259,7 +251,7 @@ describe('client.auto', () => {
|
|||||||
termsOfServiceAgreed: true,
|
termsOfServiceAgreed: true,
|
||||||
challengeCreateFn: cts.assertHttpsChallengeCreateFn,
|
challengeCreateFn: cts.assertHttpsChallengeCreateFn,
|
||||||
challengeRemoveFn: cts.challengeRemoveFn,
|
challengeRemoveFn: cts.challengeRemoveFn,
|
||||||
challengePriority: ['http-01']
|
challengePriority: ['http-01'],
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.isString(cert);
|
assert.isString(cert);
|
||||||
@@ -267,7 +259,7 @@ describe('client.auto', () => {
|
|||||||
|
|
||||||
it('should order certificate using dns-01', async () => {
|
it('should order certificate using dns-01', async () => {
|
||||||
const [, csr] = await acme.crypto.createCsr({
|
const [, csr] = await acme.crypto.createCsr({
|
||||||
commonName: testDnsDomain
|
commonName: testDnsDomain,
|
||||||
}, await createKeyFn());
|
}, await createKeyFn());
|
||||||
|
|
||||||
const cert = await testClient.auto({
|
const cert = await testClient.auto({
|
||||||
@@ -275,7 +267,7 @@ describe('client.auto', () => {
|
|||||||
termsOfServiceAgreed: true,
|
termsOfServiceAgreed: true,
|
||||||
challengeCreateFn: cts.assertDnsChallengeCreateFn,
|
challengeCreateFn: cts.assertDnsChallengeCreateFn,
|
||||||
challengeRemoveFn: cts.challengeRemoveFn,
|
challengeRemoveFn: cts.challengeRemoveFn,
|
||||||
challengePriority: ['dns-01']
|
challengePriority: ['dns-01'],
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.isString(cert);
|
assert.isString(cert);
|
||||||
@@ -283,7 +275,7 @@ describe('client.auto', () => {
|
|||||||
|
|
||||||
it('should order certificate using tls-alpn-01', async () => {
|
it('should order certificate using tls-alpn-01', async () => {
|
||||||
const [, csr] = await acme.crypto.createCsr({
|
const [, csr] = await acme.crypto.createCsr({
|
||||||
commonName: testAlpnDomain
|
commonName: testAlpnDomain,
|
||||||
}, await createKeyFn());
|
}, await createKeyFn());
|
||||||
|
|
||||||
const cert = await testClient.auto({
|
const cert = await testClient.auto({
|
||||||
@@ -291,7 +283,7 @@ describe('client.auto', () => {
|
|||||||
termsOfServiceAgreed: true,
|
termsOfServiceAgreed: true,
|
||||||
challengeCreateFn: cts.assertTlsAlpnChallengeCreateFn,
|
challengeCreateFn: cts.assertTlsAlpnChallengeCreateFn,
|
||||||
challengeRemoveFn: cts.challengeRemoveFn,
|
challengeRemoveFn: cts.challengeRemoveFn,
|
||||||
challengePriority: ['tls-alpn-01']
|
challengePriority: ['tls-alpn-01'],
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.isString(cert);
|
assert.isString(cert);
|
||||||
@@ -299,15 +291,14 @@ describe('client.auto', () => {
|
|||||||
|
|
||||||
it('should order san certificate', async () => {
|
it('should order san certificate', async () => {
|
||||||
const [, csr] = await acme.crypto.createCsr({
|
const [, csr] = await acme.crypto.createCsr({
|
||||||
commonName: testSanDomains[0],
|
altNames: testSanDomains,
|
||||||
altNames: testSanDomains
|
|
||||||
}, await createKeyFn());
|
}, await createKeyFn());
|
||||||
|
|
||||||
const cert = await testClient.auto({
|
const cert = await testClient.auto({
|
||||||
csr,
|
csr,
|
||||||
termsOfServiceAgreed: true,
|
termsOfServiceAgreed: true,
|
||||||
challengeCreateFn: cts.challengeCreateFn,
|
challengeCreateFn: cts.challengeCreateFn,
|
||||||
challengeRemoveFn: cts.challengeRemoveFn
|
challengeRemoveFn: cts.challengeRemoveFn,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.isString(cert);
|
assert.isString(cert);
|
||||||
@@ -316,15 +307,14 @@ describe('client.auto', () => {
|
|||||||
|
|
||||||
it('should order wildcard certificate', async () => {
|
it('should order wildcard certificate', async () => {
|
||||||
const [, csr] = await acme.crypto.createCsr({
|
const [, csr] = await acme.crypto.createCsr({
|
||||||
commonName: testWildcardDomain,
|
altNames: [testWildcardDomain, `*.${testWildcardDomain}`],
|
||||||
altNames: [`*.${testWildcardDomain}`]
|
|
||||||
}, await createKeyFn());
|
}, await createKeyFn());
|
||||||
|
|
||||||
const cert = await testClient.auto({
|
const cert = await testClient.auto({
|
||||||
csr,
|
csr,
|
||||||
termsOfServiceAgreed: true,
|
termsOfServiceAgreed: true,
|
||||||
challengeCreateFn: cts.challengeCreateFn,
|
challengeCreateFn: cts.challengeCreateFn,
|
||||||
challengeRemoveFn: cts.challengeRemoveFn
|
challengeRemoveFn: cts.challengeRemoveFn,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.isString(cert);
|
assert.isString(cert);
|
||||||
@@ -333,7 +323,7 @@ describe('client.auto', () => {
|
|||||||
|
|
||||||
it('should order certificate with opts.skipChallengeVerification=true', async () => {
|
it('should order certificate with opts.skipChallengeVerification=true', async () => {
|
||||||
const [, csr] = await acme.crypto.createCsr({
|
const [, csr] = await acme.crypto.createCsr({
|
||||||
commonName: `${uuid()}.${domainName}`
|
commonName: `${uuid()}.${domainName}`,
|
||||||
}, await createKeyFn());
|
}, await createKeyFn());
|
||||||
|
|
||||||
const cert = await testClient.auto({
|
const cert = await testClient.auto({
|
||||||
@@ -341,20 +331,20 @@ describe('client.auto', () => {
|
|||||||
termsOfServiceAgreed: true,
|
termsOfServiceAgreed: true,
|
||||||
skipChallengeVerification: true,
|
skipChallengeVerification: true,
|
||||||
challengeCreateFn: cts.challengeCreateFn,
|
challengeCreateFn: cts.challengeCreateFn,
|
||||||
challengeRemoveFn: cts.challengeRemoveFn
|
challengeRemoveFn: cts.challengeRemoveFn,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.isString(cert);
|
assert.isString(cert);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should order alternate certificate chain [ACME_CAP_ALTERNATE_CERT_ROOTS]', async function() {
|
it('should order alternate certificate chain [ACME_CAP_ALTERNATE_CERT_ROOTS]', async function () {
|
||||||
if (!capAlternateCertRoots) {
|
if (!capAlternateCertRoots) {
|
||||||
this.skip();
|
this.skip();
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all(testIssuers.map(async (issuer) => {
|
await Promise.all(testIssuers.map(async (issuer) => {
|
||||||
const [, csr] = await acme.crypto.createCsr({
|
const [, csr] = await acme.crypto.createCsr({
|
||||||
commonName: `${uuid()}.${domainName}`
|
commonName: `${uuid()}.${domainName}`,
|
||||||
}, await createKeyFn());
|
}, await createKeyFn());
|
||||||
|
|
||||||
const cert = await testClient.auto({
|
const cert = await testClient.auto({
|
||||||
@@ -362,7 +352,7 @@ describe('client.auto', () => {
|
|||||||
termsOfServiceAgreed: true,
|
termsOfServiceAgreed: true,
|
||||||
preferredChain: issuer,
|
preferredChain: issuer,
|
||||||
challengeCreateFn: cts.challengeCreateFn,
|
challengeCreateFn: cts.challengeCreateFn,
|
||||||
challengeRemoveFn: cts.challengeRemoveFn
|
challengeRemoveFn: cts.challengeRemoveFn,
|
||||||
});
|
});
|
||||||
|
|
||||||
const rootCert = acme.crypto.splitPemChain(cert).pop();
|
const rootCert = acme.crypto.splitPemChain(cert).pop();
|
||||||
@@ -372,13 +362,13 @@ describe('client.auto', () => {
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get default chain with invalid preference [ACME_CAP_ALTERNATE_CERT_ROOTS]', async function() {
|
it('should get default chain with invalid preference [ACME_CAP_ALTERNATE_CERT_ROOTS]', async function () {
|
||||||
if (!capAlternateCertRoots) {
|
if (!capAlternateCertRoots) {
|
||||||
this.skip();
|
this.skip();
|
||||||
}
|
}
|
||||||
|
|
||||||
const [, csr] = await acme.crypto.createCsr({
|
const [, csr] = await acme.crypto.createCsr({
|
||||||
commonName: `${uuid()}.${domainName}`
|
commonName: `${uuid()}.${domainName}`,
|
||||||
}, await createKeyFn());
|
}, await createKeyFn());
|
||||||
|
|
||||||
const cert = await testClient.auto({
|
const cert = await testClient.auto({
|
||||||
@@ -386,7 +376,7 @@ describe('client.auto', () => {
|
|||||||
termsOfServiceAgreed: true,
|
termsOfServiceAgreed: true,
|
||||||
preferredChain: uuid(),
|
preferredChain: uuid(),
|
||||||
challengeCreateFn: cts.challengeCreateFn,
|
challengeCreateFn: cts.challengeCreateFn,
|
||||||
challengeRemoveFn: cts.challengeRemoveFn
|
challengeRemoveFn: cts.challengeRemoveFn,
|
||||||
});
|
});
|
||||||
|
|
||||||
const rootCert = acme.crypto.splitPemChain(cert).pop();
|
const rootCert = acme.crypto.splitPemChain(cert).pop();
|
||||||
@@ -395,7 +385,6 @@ describe('client.auto', () => {
|
|||||||
assert.strictEqual(testIssuers[0], info.issuer.commonName);
|
assert.strictEqual(testIssuers[0], info.issuer.commonName);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Order certificate with alternate key sizes
|
* Order certificate with alternate key sizes
|
||||||
*/
|
*/
|
||||||
@@ -403,21 +392,20 @@ describe('client.auto', () => {
|
|||||||
Object.entries(createKeyAltFns).forEach(([k, altKeyFn]) => {
|
Object.entries(createKeyAltFns).forEach(([k, altKeyFn]) => {
|
||||||
it(`should order certificate with key=${k}`, async () => {
|
it(`should order certificate with key=${k}`, async () => {
|
||||||
const [, csr] = await acme.crypto.createCsr({
|
const [, csr] = await acme.crypto.createCsr({
|
||||||
commonName: testDomain
|
commonName: testDomain,
|
||||||
}, await altKeyFn());
|
}, await altKeyFn());
|
||||||
|
|
||||||
const cert = await testClient.auto({
|
const cert = await testClient.auto({
|
||||||
csr,
|
csr,
|
||||||
termsOfServiceAgreed: true,
|
termsOfServiceAgreed: true,
|
||||||
challengeCreateFn: cts.challengeCreateFn,
|
challengeCreateFn: cts.challengeCreateFn,
|
||||||
challengeRemoveFn: cts.challengeRemoveFn
|
challengeRemoveFn: cts.challengeRemoveFn,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.isString(cert);
|
assert.isString(cert);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read certificates
|
* Read certificates
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ const axios = require('./../src/axios');
|
|||||||
const apiBaseUrl = process.env.ACME_CHALLTESTSRV_URL || null;
|
const apiBaseUrl = process.env.ACME_CHALLTESTSRV_URL || null;
|
||||||
const httpsPort = axios.defaults.acmeSettings.httpsChallengePort || 443;
|
const httpsPort = axios.defaults.acmeSettings.httpsChallengePort || 443;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send request
|
* Send request
|
||||||
*/
|
*/
|
||||||
@@ -21,20 +20,18 @@ async function request(apiPath, data = {}) {
|
|||||||
await axios.request({
|
await axios.request({
|
||||||
url: `${apiBaseUrl}/${apiPath}`,
|
url: `${apiBaseUrl}/${apiPath}`,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data,
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* State
|
* State
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports.isEnabled = () => !!apiBaseUrl;
|
exports.isEnabled = () => !!apiBaseUrl;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DNS
|
* DNS
|
||||||
*/
|
*/
|
||||||
@@ -42,7 +39,6 @@ exports.isEnabled = () => !!apiBaseUrl;
|
|||||||
exports.addDnsARecord = async (host, addresses) => request('add-a', { host, addresses });
|
exports.addDnsARecord = async (host, addresses) => request('add-a', { host, addresses });
|
||||||
exports.setDnsCnameRecord = async (host, target) => request('set-cname', { host, target });
|
exports.setDnsCnameRecord = async (host, target) => request('set-cname', { host, target });
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Challenge response
|
* Challenge response
|
||||||
*/
|
*/
|
||||||
@@ -55,7 +51,7 @@ async function addHttps01ChallengeResponse(token, content, targetHostname) {
|
|||||||
await addHttp01ChallengeResponse(token, content);
|
await addHttp01ChallengeResponse(token, content);
|
||||||
return request('add-redirect', {
|
return request('add-redirect', {
|
||||||
path: `/.well-known/acme-challenge/${token}`,
|
path: `/.well-known/acme-challenge/${token}`,
|
||||||
targetURL: `https://${targetHostname}:${httpsPort}/.well-known/acme-challenge/${token}`
|
targetURL: `https://${targetHostname}:${httpsPort}/.well-known/acme-challenge/${token}`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +68,6 @@ exports.addHttps01ChallengeResponse = addHttps01ChallengeResponse;
|
|||||||
exports.addDns01ChallengeResponse = addDns01ChallengeResponse;
|
exports.addDns01ChallengeResponse = addDns01ChallengeResponse;
|
||||||
exports.addTlsAlpn01ChallengeResponse = addTlsAlpn01ChallengeResponse;
|
exports.addTlsAlpn01ChallengeResponse = addTlsAlpn01ChallengeResponse;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Challenge response mock functions
|
* Challenge response mock functions
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ const util = require('./../src/util');
|
|||||||
|
|
||||||
const pebbleManagementUrl = process.env.ACME_PEBBLE_MANAGEMENT_URL || null;
|
const pebbleManagementUrl = process.env.ACME_PEBBLE_MANAGEMENT_URL || null;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pebble
|
* Pebble
|
||||||
*/
|
*/
|
||||||
@@ -26,7 +25,6 @@ async function getPebbleCertIssuers() {
|
|||||||
return info.map((i) => i.issuer.commonName);
|
return info.map((i) => i.issuer.commonName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get certificate issuers
|
* Get certificate issuers
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -7,14 +7,12 @@ const chai = require('chai');
|
|||||||
const chaiAsPromised = require('chai-as-promised');
|
const chaiAsPromised = require('chai-as-promised');
|
||||||
const axios = require('./../src/axios');
|
const axios = require('./../src/axios');
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add promise support to Chai
|
* Add promise support to Chai
|
||||||
*/
|
*/
|
||||||
|
|
||||||
chai.use(chaiAsPromised);
|
chai.use(chaiAsPromised);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Challenge test server ports
|
* Challenge test server ports
|
||||||
*/
|
*/
|
||||||
@@ -31,7 +29,6 @@ if (process.env.ACME_TLSALPN_PORT) {
|
|||||||
axios.defaults.acmeSettings.tlsAlpnChallengePort = process.env.ACME_TLSALPN_PORT;
|
axios.defaults.acmeSettings.tlsAlpnChallengePort = process.env.ACME_TLSALPN_PORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* External account binding
|
* External account binding
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ const { assert } = require('chai');
|
|||||||
const spec = {};
|
const spec = {};
|
||||||
module.exports = spec;
|
module.exports = spec;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ACME
|
* ACME
|
||||||
*/
|
*/
|
||||||
@@ -120,7 +119,6 @@ spec.rfc8555.challenge = (obj) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Crypto
|
* Crypto
|
||||||
*/
|
*/
|
||||||
@@ -150,7 +148,6 @@ spec.crypto.certificateInfo = (obj) => {
|
|||||||
assert.strictEqual(Object.prototype.toString.call(obj.notAfter), '[object Date]');
|
assert.strictEqual(Object.prototype.toString.call(obj.notAfter), '[object Date]');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JWK
|
* JWK
|
||||||
*/
|
*/
|
||||||
|
|||||||
7
packages/core/acme-client/types/index.d.ts
vendored
7
packages/core/acme-client/types/index.d.ts
vendored
@@ -15,7 +15,6 @@ export type PublicKeyString = string;
|
|||||||
export type CertificateString = string;
|
export type CertificateString = string;
|
||||||
export type CsrString = string;
|
export type CsrString = string;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Augmented ACME interfaces
|
* Augmented ACME interfaces
|
||||||
*/
|
*/
|
||||||
@@ -28,7 +27,6 @@ export interface Authorization extends rfc8555.Authorization {
|
|||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Client
|
* Client
|
||||||
*/
|
*/
|
||||||
@@ -80,7 +78,6 @@ export class Client {
|
|||||||
auto(opts: ClientAutoOptions): Promise<string>;
|
auto(opts: ClientAutoOptions): Promise<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Directory URLs
|
* Directory URLs
|
||||||
*/
|
*/
|
||||||
@@ -95,11 +92,11 @@ export const directory: {
|
|||||||
production: string
|
production: string
|
||||||
},
|
},
|
||||||
zerossl: {
|
zerossl: {
|
||||||
|
staging: string,
|
||||||
production: string
|
production: string
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Crypto
|
* Crypto
|
||||||
*/
|
*/
|
||||||
@@ -177,14 +174,12 @@ export interface CryptoLegacyInterface {
|
|||||||
|
|
||||||
export const forge: CryptoLegacyInterface;
|
export const forge: CryptoLegacyInterface;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Axios
|
* Axios
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const axios: AxiosInstance;
|
export const axios: AxiosInstance;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logger
|
* Logger
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
import * as acme from 'acme-client';
|
import * as acme from 'acme-client';
|
||||||
|
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
/* Client */
|
/* Client */
|
||||||
const accountKey = await acme.crypto.createPrivateKey();
|
const accountKey = await acme.crypto.createPrivateKey();
|
||||||
|
|||||||
4
packages/core/acme-client/types/rfc8555.d.ts
vendored
4
packages/core/acme-client/types/rfc8555.d.ts
vendored
@@ -27,7 +27,6 @@ export interface AccountUpdateRequest {
|
|||||||
termsOfServiceAgreed?: boolean;
|
termsOfServiceAgreed?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Order
|
* Order
|
||||||
*
|
*
|
||||||
@@ -53,7 +52,6 @@ export interface OrderCreateRequest {
|
|||||||
notAfter?: string;
|
notAfter?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authorization
|
* Authorization
|
||||||
*
|
*
|
||||||
@@ -73,7 +71,6 @@ export interface Identifier {
|
|||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Challenge
|
* Challenge
|
||||||
*
|
*
|
||||||
@@ -102,7 +99,6 @@ export interface DnsChallenge extends ChallengeAbstract {
|
|||||||
|
|
||||||
export type Challenge = HttpChallenge | DnsChallenge;
|
export type Challenge = HttpChallenge | DnsChallenge;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Certificate
|
* Certificate
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -3,6 +3,46 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
# [1.21.0](https://github.com/certd/certd/compare/v1.20.17...v1.21.0) (2024-07-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/pipeline
|
||||||
|
|
||||||
|
## [1.20.17](https://github.com/certd/certd/compare/v1.20.16...v1.20.17) (2024-07-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/pipeline
|
||||||
|
|
||||||
|
## [1.20.16](https://github.com/certd/certd/compare/v1.20.15...v1.20.16) (2024-07-01)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/pipeline
|
||||||
|
|
||||||
|
## [1.20.15](https://github.com/certd/certd/compare/v1.20.14...v1.20.15) (2024-06-28)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/pipeline
|
||||||
|
|
||||||
|
## [1.20.14](https://github.com/certd/certd/compare/v1.20.13...v1.20.14) (2024-06-23)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/pipeline
|
||||||
|
|
||||||
|
## [1.20.13](https://github.com/certd/certd/compare/v1.20.12...v1.20.13) (2024-06-18)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/pipeline
|
||||||
|
|
||||||
|
## [1.20.12](https://github.com/certd/certd/compare/v1.20.10...v1.20.12) (2024-06-17)
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 支持cloudflare域名 ([fbb9a47](https://github.com/certd/certd/commit/fbb9a47e8f7bb805289b9ee64bd46ffee0f01c06))
|
||||||
|
|
||||||
|
## [1.20.10](https://github.com/certd/certd/compare/v1.20.9...v1.20.10) (2024-05-30)
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 优化文件下载包名 ([d9eb927](https://github.com/certd/certd/commit/d9eb927b0a1445feab08b1958aa9ea80637a5ae6))
|
||||||
|
|
||||||
|
## [1.20.9](https://github.com/certd/certd/compare/v1.20.8...v1.20.9) (2024-03-22)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/pipeline
|
||||||
|
|
||||||
## [1.20.8](https://github.com/certd/certd/compare/v1.20.7...v1.20.8) (2024-03-22)
|
## [1.20.8](https://github.com/certd/certd/compare/v1.20.7...v1.20.8) (2024-03-22)
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/pipeline
|
**Note:** Version bump only for package @certd/pipeline
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@certd/pipeline",
|
"name": "@certd/pipeline",
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "1.20.8",
|
"version": "1.21.0",
|
||||||
"main": "./src/index.ts",
|
"main": "./src/index.ts",
|
||||||
"module": "./src/index.ts",
|
"module": "./src/index.ts",
|
||||||
"types": "./src/index.ts",
|
"types": "./src/index.ts",
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
"qs": "^6.11.2"
|
"qs": "^6.11.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@certd/acme-client": "^1.20.8",
|
"@certd/acme-client": "workspace:^1.21.0",
|
||||||
"@rollup/plugin-commonjs": "^23.0.4",
|
"@rollup/plugin-commonjs": "^23.0.4",
|
||||||
"@rollup/plugin-json": "^6.0.0",
|
"@rollup/plugin-json": "^6.0.0",
|
||||||
"@rollup/plugin-node-resolve": "^15.0.1",
|
"@rollup/plugin-node-resolve": "^15.0.1",
|
||||||
@@ -57,5 +57,5 @@
|
|||||||
"vite": "^4.3.8",
|
"vite": "^4.3.8",
|
||||||
"vue-tsc": "^1.6.5"
|
"vue-tsc": "^1.6.5"
|
||||||
},
|
},
|
||||||
"gitHead": "b258e926209fef4cc4d633b0383eb54e26c516f9"
|
"gitHead": "a31f1c7f5e71fa946de9bf0283e11d6ce049b3e9"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Registry } from "../registry";
|
import { Registry } from "../registry";
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
export const accessRegistry = new Registry();
|
export const accessRegistry = new Registry("access");
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { ContextFactory, IContext } from "./context";
|
|||||||
import { IStorage } from "./storage";
|
import { IStorage } from "./storage";
|
||||||
import { logger } from "../utils/util.log";
|
import { logger } from "../utils/util.log";
|
||||||
import { Logger } from "log4js";
|
import { Logger } from "log4js";
|
||||||
import { request } from "../utils/util.request";
|
import { createAxiosService } from "../utils/util.request";
|
||||||
import { IAccessService } from "../access";
|
import { IAccessService } from "../access";
|
||||||
import { RegistryItem } from "../registry";
|
import { RegistryItem } from "../registry";
|
||||||
import { Decorator } from "../decorator";
|
import { Decorator } from "../decorator";
|
||||||
@@ -213,11 +213,12 @@ export class Executor {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const http = createAxiosService({ logger: currentLogger });
|
||||||
const taskCtx: TaskInstanceContext = {
|
const taskCtx: TaskInstanceContext = {
|
||||||
pipeline: this.pipeline,
|
pipeline: this.pipeline,
|
||||||
step,
|
step,
|
||||||
lastStatus,
|
lastStatus,
|
||||||
http: request,
|
http,
|
||||||
logger: currentLogger,
|
logger: currentLogger,
|
||||||
accessService: this.options.accessService,
|
accessService: this.options.accessService,
|
||||||
emailService: this.options.emailService,
|
emailService: this.options.emailService,
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { fileUtils } from "../utils/util.file";
|
import { fileUtils } from "../utils";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
|
import { logger } from "../utils";
|
||||||
|
|
||||||
export type FileStoreOptions = {
|
export type FileStoreOptions = {
|
||||||
rootDir?: string;
|
rootDir?: string;
|
||||||
@@ -30,6 +31,7 @@ export class FileStore {
|
|||||||
const localPath = this.buildFilePath(filename);
|
const localPath = this.buildFilePath(filename);
|
||||||
|
|
||||||
fs.writeFileSync(localPath, file);
|
fs.writeFileSync(localPath, file);
|
||||||
|
logger.info(`写入文件:${localPath}`);
|
||||||
return localPath;
|
return localPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { IAccessService } from "../access";
|
|||||||
import { IEmailService } from "../service";
|
import { IEmailService } from "../service";
|
||||||
import { IContext } from "../core";
|
import { IContext } from "../core";
|
||||||
import { AxiosInstance } from "axios";
|
import { AxiosInstance } from "axios";
|
||||||
|
import { logger } from "../utils";
|
||||||
|
|
||||||
export enum ContextScope {
|
export enum ContextScope {
|
||||||
global,
|
global,
|
||||||
@@ -89,6 +90,7 @@ export abstract class AbstractTaskPlugin implements ITaskPlugin {
|
|||||||
}
|
}
|
||||||
saveFile(filename: string, file: Buffer) {
|
saveFile(filename: string, file: Buffer) {
|
||||||
const filePath = this.ctx.fileStore.writeFile(filename, file);
|
const filePath = this.ctx.fileStore.writeFile(filename, file);
|
||||||
|
logger.info(`saveFile:${filePath}`);
|
||||||
this._result.files!.push({
|
this._result.files!.push({
|
||||||
id: this.randomFileId(),
|
id: this.randomFileId(),
|
||||||
filename,
|
filename,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Registry } from "../registry";
|
import { Registry } from "../registry";
|
||||||
import { AbstractTaskPlugin } from "./api";
|
import { AbstractTaskPlugin } from "./api";
|
||||||
|
|
||||||
export const pluginRegistry = new Registry<AbstractTaskPlugin>();
|
export const pluginRegistry = new Registry<AbstractTaskPlugin>("plugin");
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { logger } from "../utils";
|
||||||
|
|
||||||
export type Registrable = {
|
export type Registrable = {
|
||||||
name: string;
|
name: string;
|
||||||
title: string;
|
title: string;
|
||||||
@@ -9,15 +11,21 @@ export type RegistryItem<T> = {
|
|||||||
target: T;
|
target: T;
|
||||||
};
|
};
|
||||||
export class Registry<T> {
|
export class Registry<T> {
|
||||||
|
type = "";
|
||||||
storage: {
|
storage: {
|
||||||
[key: string]: RegistryItem<T>;
|
[key: string]: RegistryItem<T>;
|
||||||
} = {};
|
} = {};
|
||||||
|
|
||||||
|
constructor(type: string) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
register(key: string, value: RegistryItem<T>) {
|
register(key: string, value: RegistryItem<T>) {
|
||||||
if (!key || value == null) {
|
if (!key || value == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.storage[key] = value;
|
this.storage[key] = value;
|
||||||
|
logger.info(`注册插件:${this.type}:${key}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
get(name: string): RegistryItem<T> {
|
get(name: string): RegistryItem<T> {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import sleep from "./util.sleep";
|
import sleep from "./util.sleep";
|
||||||
import { request } from "./util.request";
|
import { request } from "./util.request";
|
||||||
export * from "./util.log";
|
export * from "./util.log";
|
||||||
|
export * from "./util.file";
|
||||||
export const utils = {
|
export const utils = {
|
||||||
sleep,
|
sleep,
|
||||||
http: request,
|
http: request,
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ import axios from "axios";
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import qs from "qs";
|
import qs from "qs";
|
||||||
import { logger } from "./util.log";
|
import { logger } from "./util.log";
|
||||||
|
import { Logger } from "log4js";
|
||||||
/**
|
/**
|
||||||
* @description 创建请求实例
|
* @description 创建请求实例
|
||||||
*/
|
*/
|
||||||
function createService() {
|
export function createAxiosService({ logger }: { logger: Logger }) {
|
||||||
// 创建一个 axios 实例
|
// 创建一个 axios 实例
|
||||||
const service = axios.create();
|
const service = axios.create();
|
||||||
// 请求拦截
|
// 请求拦截
|
||||||
@@ -18,18 +19,19 @@ function createService() {
|
|||||||
}); // 序列化请求参数
|
}); // 序列化请求参数
|
||||||
delete config.formData;
|
delete config.formData;
|
||||||
}
|
}
|
||||||
|
logger.info(`http request:${config.url},method:${config.method}`);
|
||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
(error: Error) => {
|
(error: Error) => {
|
||||||
// 发送失败
|
// 发送失败
|
||||||
logger.error(error);
|
logger.error("接口请求失败:", error);
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
// 响应拦截
|
// 响应拦截
|
||||||
service.interceptors.response.use(
|
service.interceptors.response.use(
|
||||||
(response: any) => {
|
(response: any) => {
|
||||||
logger.info("http response:", JSON.stringify(response.data));
|
logger.info("http response:", JSON.stringify(response?.data));
|
||||||
return response.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
(error: any) => {
|
(error: any) => {
|
||||||
@@ -48,11 +50,14 @@ function createService() {
|
|||||||
// case 505: error.message = 'HTTP版本不受支持'; break
|
// case 505: error.message = 'HTTP版本不受支持'; break
|
||||||
// default: break
|
// default: break
|
||||||
// }
|
// }
|
||||||
logger.error("请求出错:", error.response.config.url, error);
|
logger.error(`请求出错:url:${error?.response?.config.url},method:${error.response.config.method},status:${error?.response?.status}`);
|
||||||
|
logger.info("返回数据:", JSON.stringify(error?.response?.data));
|
||||||
|
delete error.config;
|
||||||
|
delete error.response;
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const request = createService();
|
export const request = createAxiosService({ logger });
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"parser": "@typescript-eslint/parser",
|
|
||||||
"plugins": [
|
|
||||||
"@typescript-eslint"
|
|
||||||
],
|
|
||||||
"extends": [
|
|
||||||
"plugin:@typescript-eslint/recommended",
|
|
||||||
"plugin:prettier/recommended",
|
|
||||||
"prettier"
|
|
||||||
],
|
|
||||||
"env": {
|
|
||||||
"mocha": true
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"@typescript-eslint/no-var-requires": "off",
|
|
||||||
"@typescript-eslint/ban-ts-comment": "off",
|
|
||||||
"@typescript-eslint/ban-ts-ignore": "off",
|
|
||||||
"@typescript-eslint/no-explicit-any": "off",
|
|
||||||
"@typescript-eslint/no-empty-function": "off",
|
|
||||||
// "no-unused-expressions": "off",
|
|
||||||
"max-len": [0, 160, 2, { "ignoreUrls": true }]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
26
packages/plugins/plugin-aliyun/.gitignore
vendored
26
packages/plugins/plugin-aliyun/.gitignore
vendored
@@ -1,26 +0,0 @@
|
|||||||
# Logs
|
|
||||||
logs
|
|
||||||
*.log
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
pnpm-debug.log*
|
|
||||||
lerna-debug.log*
|
|
||||||
|
|
||||||
node_modules
|
|
||||||
dist
|
|
||||||
dist-ssr
|
|
||||||
*.local
|
|
||||||
|
|
||||||
# Editor directories and files
|
|
||||||
.vscode/*
|
|
||||||
!.vscode/extensions.json
|
|
||||||
.idea
|
|
||||||
.DS_Store
|
|
||||||
*.suo
|
|
||||||
*.ntvs*
|
|
||||||
*.njsproj
|
|
||||||
*.sln
|
|
||||||
*.sw?
|
|
||||||
|
|
||||||
test/user.secret.ts
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"extension": ["ts"],
|
|
||||||
"spec": "test/**/*.test.ts",
|
|
||||||
"require": "ts-node/register"
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
node_modules
|
|
||||||
src
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"printWidth": 160
|
|
||||||
}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
# Change Log
|
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
||||||
|
|
||||||
## [1.20.8](https://github.com/certd/certd/compare/v1.20.7...v1.20.8) (2024-03-22)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-aliyun
|
|
||||||
|
|
||||||
## [1.20.7](https://github.com/certd/certd/compare/v1.20.6...v1.20.7) (2024-03-22)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-aliyun
|
|
||||||
|
|
||||||
## [1.20.6](https://github.com/certd/certd/compare/v1.20.5...v1.20.6) (2024-03-21)
|
|
||||||
|
|
||||||
### Performance Improvements
|
|
||||||
|
|
||||||
* 插件贡献文档及示例 ([72fb20a](https://github.com/certd/certd/commit/72fb20abf3ba5bdd862575d2907703a52fd7eb17))
|
|
||||||
|
|
||||||
## [1.20.5](https://github.com/certd/certd/compare/v1.20.2...v1.20.5) (2024-03-11)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-aliyun
|
|
||||||
|
|
||||||
## [1.20.2](https://github.com/certd/certd/compare/v1.2.1...v1.20.2) (2024-02-28)
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* 临时修复阿里云domainlist接口返回域名列表不全的问题,后续还需要增加翻页查询 ([849c145](https://github.com/certd/certd/commit/849c145926984762bd9dbec87bd91cd047fc0855))
|
|
||||||
|
|
||||||
## [1.2.1](https://github.com/certd/certd/compare/v1.2.0...v1.2.1) (2023-12-12)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-aliyun
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-aliyun
|
|
||||||
|
|
||||||
# [1.2.0](https://github.com/certd/certd/compare/v1.1.6...v1.2.0) (2023-10-27)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-aliyun
|
|
||||||
|
|
||||||
## [1.1.6](https://github.com/certd/certd/compare/v1.1.5...v1.1.6) (2023-07-10)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-aliyun
|
|
||||||
|
|
||||||
## [1.1.5](https://github.com/certd/certd/compare/v1.1.4...v1.1.5) (2023-07-03)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-aliyun
|
|
||||||
|
|
||||||
## [1.1.4](https://github.com/certd/certd/compare/v1.1.3...v1.1.4) (2023-07-03)
|
|
||||||
|
|
||||||
### Performance Improvements
|
|
||||||
|
|
||||||
* timeout ([3eeb1f7](https://github.com/certd/certd/commit/3eeb1f77aa2922f3545f3d2067f561d95621d54f))
|
|
||||||
|
|
||||||
## [1.1.3](https://github.com/certd/certd/compare/v1.1.2...v1.1.3) (2023-07-03)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-aliyun
|
|
||||||
|
|
||||||
## [1.1.2](https://github.com/certd/certd/compare/v1.1.1...v1.1.2) (2023-07-03)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-aliyun
|
|
||||||
|
|
||||||
## [1.1.1](https://github.com/certd/certd/compare/v1.1.0...v1.1.1) (2023-06-28)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-aliyun
|
|
||||||
|
|
||||||
# [1.1.0](https://github.com/certd/certd/compare/v1.0.6...v1.1.0) (2023-06-28)
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* save files ([671d273](https://github.com/certd/certd/commit/671d273e2f9136d16896536b0ca127cf372f1619))
|
|
||||||
|
|
||||||
## [1.0.6](https://github.com/certd/certd/compare/v1.0.5...v1.0.6) (2023-05-25)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-aliyun
|
|
||||||
|
|
||||||
## [1.0.5](https://github.com/certd/certd/compare/v1.0.4...v1.0.5) (2023-05-25)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-aliyun
|
|
||||||
|
|
||||||
## [1.0.4](https://github.com/certd/certd/compare/v1.0.3...v1.0.4) (2023-05-25)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-aliyun
|
|
||||||
|
|
||||||
## [1.0.3](https://github.com/certd/certd/compare/v1.0.2...v1.0.3) (2023-05-25)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-aliyun
|
|
||||||
|
|
||||||
## [1.0.2](https://github.com/certd/certd/compare/v1.0.1...v1.0.2) (2023-05-24)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-aliyun
|
|
||||||
|
|
||||||
## [1.0.1](https://github.com/certd/certd/compare/v1.0.0...v1.0.1) (2023-05-24)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-aliyun
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
# Vue 3 + TypeScript + Vite
|
|
||||||
|
|
||||||
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
|
||||||
|
|
||||||
## Recommended IDE Setup
|
|
||||||
|
|
||||||
- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar)
|
|
||||||
|
|
||||||
## Type Support For `.vue` Imports in TS
|
|
||||||
|
|
||||||
Since TypeScript cannot handle type information for `.vue` imports, they are shimmed to be a generic Vue component type by default. In most cases this is fine if you don't really care about component prop types outside of templates. However, if you wish to get actual prop types in `.vue` imports (for example to get props validation when using manual `h(...)` calls), you can enable Volar's Take Over mode by following these steps:
|
|
||||||
|
|
||||||
1. Run `Extensions: Show Built-in Extensions` from VS Code's command palette, look for `TypeScript and JavaScript Language Features`, then right click and select `Disable (Workspace)`. By default, Take Over mode will enable itself if the default TypeScript extension is disabled.
|
|
||||||
2. Reload the VS Code window by running `Developer: Reload Window` from the command palette.
|
|
||||||
|
|
||||||
You can learn more about Take Over mode [here](https://github.com/johnsoncodehk/volar/discussions/471).
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@certd/plugin-aliyun",
|
|
||||||
"private": false,
|
|
||||||
"version": "1.20.8",
|
|
||||||
"main": "./src/index.ts",
|
|
||||||
"module": "./src/index.ts",
|
|
||||||
"types": "./src/index.ts",
|
|
||||||
"publishConfig": {
|
|
||||||
"main": "./dist/bundle.js",
|
|
||||||
"module": "./dist/bundle.mjs",
|
|
||||||
"types": "./dist/d/index.d.ts"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"dev": "vite",
|
|
||||||
"build1": "vue-tsc --noEmit && vite build",
|
|
||||||
"build": "rollup -c",
|
|
||||||
"preview": "vite preview"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@alicloud/cs20151215": "^3.0.3",
|
|
||||||
"@alicloud/openapi-client": "^0.4.0",
|
|
||||||
"@alicloud/pop-core": "^1.7.10",
|
|
||||||
"node-forge": "^0.10.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@certd/acme-client": "^1.20.8",
|
|
||||||
"@certd/pipeline": "^1.20.8",
|
|
||||||
"@certd/plugin-cert": "^1.20.8",
|
|
||||||
"@certd/plugin-util": "^1.20.8",
|
|
||||||
"@rollup/plugin-commonjs": "^23.0.4",
|
|
||||||
"@rollup/plugin-json": "^6.0.0",
|
|
||||||
"@rollup/plugin-node-resolve": "^15.0.1",
|
|
||||||
"@rollup/plugin-terser": "^0.4.3",
|
|
||||||
"@rollup/plugin-typescript": "^11.0.0",
|
|
||||||
"@types/chai": "^4.3.3",
|
|
||||||
"@types/lodash": "^4.14.186",
|
|
||||||
"@types/mocha": "^10.0.0",
|
|
||||||
"@types/node-forge": "^1.3.0",
|
|
||||||
"@typescript-eslint/eslint-plugin": "^5.38.1",
|
|
||||||
"@typescript-eslint/parser": "^5.38.1",
|
|
||||||
"chai": "^4.3.6",
|
|
||||||
"dayjs": "^1.11.6",
|
|
||||||
"eslint": "^8.24.0",
|
|
||||||
"eslint-config-prettier": "^8.5.0",
|
|
||||||
"eslint-plugin-import": "^2.26.0",
|
|
||||||
"eslint-plugin-node": "^11.1.0",
|
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
|
||||||
"lodash": "^4.17.21",
|
|
||||||
"log4js": "^6.7.1",
|
|
||||||
"mocha": "^10.1.0",
|
|
||||||
"prettier": "^2.8.8",
|
|
||||||
"rollup": "^3.7.4",
|
|
||||||
"rollup-plugin-typescript2": "^0.34.1",
|
|
||||||
"rollup-plugin-visualizer": "^5.8.2",
|
|
||||||
"ts-node": "^10.9.1",
|
|
||||||
"tslib": "^2.5.2",
|
|
||||||
"typescript": "^4.8.4",
|
|
||||||
"vite": "^3.1.0",
|
|
||||||
"vue-tsc": "^0.38.9"
|
|
||||||
},
|
|
||||||
"gitHead": "b258e926209fef4cc4d633b0383eb54e26c516f9"
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
const resolve = require("@rollup/plugin-node-resolve");
|
|
||||||
const commonjs = require("@rollup/plugin-commonjs");
|
|
||||||
//const Typescript = require("rollup-plugin-typescript2");
|
|
||||||
const Typescript = require("@rollup/plugin-typescript");
|
|
||||||
const json = require("@rollup/plugin-json");
|
|
||||||
const terser = require("@rollup/plugin-terser");
|
|
||||||
module.exports = {
|
|
||||||
input: "src/index.ts",
|
|
||||||
output: {
|
|
||||||
file: "dist/bundle.js",
|
|
||||||
format: "cjs",
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
// 解析第三方依赖
|
|
||||||
resolve(),
|
|
||||||
// 识别 commonjs 模式第三方依赖
|
|
||||||
commonjs(),
|
|
||||||
Typescript({
|
|
||||||
target: "esnext",
|
|
||||||
rootDir: "src",
|
|
||||||
declaration: true,
|
|
||||||
declarationDir: "dist/d",
|
|
||||||
exclude: ["./node_modules/**", "./src/**/*.vue"],
|
|
||||||
allowSyntheticDefaultImports: true,
|
|
||||||
}),
|
|
||||||
json(),
|
|
||||||
terser(),
|
|
||||||
],
|
|
||||||
external: [
|
|
||||||
"vue",
|
|
||||||
"lodash",
|
|
||||||
"dayjs",
|
|
||||||
"@certd/acme-client",
|
|
||||||
"@certd/pipeline",
|
|
||||||
"@certd/plugin-cert",
|
|
||||||
"@certd/plugin-aliyun",
|
|
||||||
"@certd/plugin-tencent",
|
|
||||||
"@certd/plugin-huawei",
|
|
||||||
"@certd/plugin-host",
|
|
||||||
"@certd/plugin-tencent",
|
|
||||||
"@certd/plugin-util",
|
|
||||||
],
|
|
||||||
};
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
import { IsAccess, AccessInput } from "@certd/pipeline";
|
|
||||||
|
|
||||||
@IsAccess({
|
|
||||||
name: "aliyun",
|
|
||||||
title: "阿里云授权",
|
|
||||||
desc: "",
|
|
||||||
})
|
|
||||||
export class AliyunAccess {
|
|
||||||
@AccessInput({
|
|
||||||
title: "accessKeyId",
|
|
||||||
component: {
|
|
||||||
placeholder: "accessKeyId",
|
|
||||||
},
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
accessKeyId = "";
|
|
||||||
@AccessInput({
|
|
||||||
title: "accessKeySecret",
|
|
||||||
component: {
|
|
||||||
placeholder: "accessKeySecret",
|
|
||||||
},
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
accessKeySecret = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
new AliyunAccess();
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export * from "./aliyun-access";
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
import Core from "@alicloud/pop-core";
|
|
||||||
import _ from "lodash";
|
|
||||||
import { CreateRecordOptions, IDnsProvider, IsDnsProvider, RemoveRecordOptions } from "@certd/plugin-cert";
|
|
||||||
import { Autowire, ILogger } from "@certd/pipeline";
|
|
||||||
import { AliyunAccess } from "../access";
|
|
||||||
|
|
||||||
@IsDnsProvider({
|
|
||||||
name: "aliyun",
|
|
||||||
title: "阿里云",
|
|
||||||
desc: "阿里云DNS解析提供商",
|
|
||||||
accessType: "aliyun",
|
|
||||||
})
|
|
||||||
export class AliyunDnsProvider implements IDnsProvider {
|
|
||||||
client: any;
|
|
||||||
@Autowire()
|
|
||||||
access!: AliyunAccess;
|
|
||||||
@Autowire()
|
|
||||||
logger!: ILogger;
|
|
||||||
async onInstance() {
|
|
||||||
const access: any = this.access;
|
|
||||||
this.client = new Core({
|
|
||||||
accessKeyId: access.accessKeyId,
|
|
||||||
accessKeySecret: access.accessKeySecret,
|
|
||||||
endpoint: "https://alidns.aliyuncs.com",
|
|
||||||
apiVersion: "2015-01-09",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async getDomainList() {
|
|
||||||
const params = {
|
|
||||||
RegionId: "cn-hangzhou",
|
|
||||||
PageSize: 100,
|
|
||||||
};
|
|
||||||
|
|
||||||
const requestOption = {
|
|
||||||
method: "POST",
|
|
||||||
};
|
|
||||||
|
|
||||||
const ret = await this.client.request("DescribeDomains", params, requestOption);
|
|
||||||
return ret.Domains.Domain;
|
|
||||||
}
|
|
||||||
|
|
||||||
async matchDomain(dnsRecord: string) {
|
|
||||||
const list = await this.getDomainList();
|
|
||||||
let domain = null;
|
|
||||||
const domainList = [];
|
|
||||||
for (const item of list) {
|
|
||||||
domainList.push(item.DomainName);
|
|
||||||
if (_.endsWith(dnsRecord, item.DomainName)) {
|
|
||||||
domain = item.DomainName;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!domain) {
|
|
||||||
throw new Error(`can not find Domain :${dnsRecord} ,list: ${JSON.stringify(domainList)}`);
|
|
||||||
}
|
|
||||||
return domain;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getRecords(domain: string, rr: string, value: string) {
|
|
||||||
const params: any = {
|
|
||||||
RegionId: "cn-hangzhou",
|
|
||||||
DomainName: domain,
|
|
||||||
RRKeyWord: rr,
|
|
||||||
ValueKeyWord: undefined,
|
|
||||||
};
|
|
||||||
if (value) {
|
|
||||||
params.ValueKeyWord = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
const requestOption = {
|
|
||||||
method: "POST",
|
|
||||||
};
|
|
||||||
|
|
||||||
const ret = await this.client.request("DescribeDomainRecords", params, requestOption);
|
|
||||||
return ret.DomainRecords.Record;
|
|
||||||
}
|
|
||||||
|
|
||||||
async createRecord(options: CreateRecordOptions): Promise<any> {
|
|
||||||
const { fullRecord, value, type } = options;
|
|
||||||
this.logger.info("添加域名解析:", fullRecord, value);
|
|
||||||
const domain = await this.matchDomain(fullRecord);
|
|
||||||
const rr = fullRecord.replace("." + domain, "");
|
|
||||||
|
|
||||||
const params = {
|
|
||||||
RegionId: "cn-hangzhou",
|
|
||||||
DomainName: domain,
|
|
||||||
RR: rr,
|
|
||||||
Type: type,
|
|
||||||
Value: value,
|
|
||||||
// Line: 'oversea' // 海外
|
|
||||||
};
|
|
||||||
|
|
||||||
const requestOption = {
|
|
||||||
method: "POST",
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
const ret = await this.client.request("AddDomainRecord", params, requestOption);
|
|
||||||
this.logger.info("添加域名解析成功:", value, value, ret.RecordId);
|
|
||||||
return ret.RecordId;
|
|
||||||
} catch (e: any) {
|
|
||||||
if (e.code === "DomainRecordDuplicate") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.logger.info("添加域名解析出错", e);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async removeRecord(options: RemoveRecordOptions): Promise<any> {
|
|
||||||
const { fullRecord, value, record } = options;
|
|
||||||
const params = {
|
|
||||||
RegionId: "cn-hangzhou",
|
|
||||||
RecordId: record,
|
|
||||||
};
|
|
||||||
|
|
||||||
const requestOption = {
|
|
||||||
method: "POST",
|
|
||||||
};
|
|
||||||
|
|
||||||
const ret = await this.client.request("DeleteDomainRecord", params, requestOption);
|
|
||||||
this.logger.info("删除域名解析成功:", fullRecord, value, ret.RecordId);
|
|
||||||
return ret.RecordId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
new AliyunDnsProvider();
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
import "./aliyun-dns-provider";
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
export * from "./access/index";
|
|
||||||
export * from "./dns-provider/index";
|
|
||||||
export * from "./plugin/index";
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput } from "@certd/pipeline";
|
|
||||||
import dayjs from "dayjs";
|
|
||||||
import Core from "@alicloud/pop-core";
|
|
||||||
import RPCClient from "@alicloud/pop-core";
|
|
||||||
import { AliyunAccess } from "../../access";
|
|
||||||
|
|
||||||
@IsTaskPlugin({
|
|
||||||
name: "DeployCertToAliyunCDN",
|
|
||||||
title: "部署证书至阿里云CDN",
|
|
||||||
desc: "依赖证书申请前置任务,自动部署域名证书至阿里云CDN",
|
|
||||||
default: {
|
|
||||||
strategy: {
|
|
||||||
runStrategy: RunStrategy.SkipWhenSucceed,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
export class DeployCertToAliyunCDN extends AbstractTaskPlugin {
|
|
||||||
@TaskInput({
|
|
||||||
title: "CDN加速域名",
|
|
||||||
helper: "你在阿里云上配置的CDN加速域名,比如:certd.docmirror.cn",
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
domainName!: string;
|
|
||||||
|
|
||||||
@TaskInput({
|
|
||||||
title: "证书名称",
|
|
||||||
helper: "上传后将以此名称作为前缀备注",
|
|
||||||
})
|
|
||||||
certName!: string;
|
|
||||||
|
|
||||||
@TaskInput({
|
|
||||||
title: "域名证书",
|
|
||||||
helper: "请选择前置任务输出的域名证书",
|
|
||||||
component: {
|
|
||||||
name: "pi-output-selector",
|
|
||||||
},
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
cert!: string;
|
|
||||||
|
|
||||||
@TaskInput({
|
|
||||||
title: "Access授权",
|
|
||||||
helper: "阿里云授权AccessKeyId、AccessKeySecret",
|
|
||||||
component: {
|
|
||||||
name: "pi-access-selector",
|
|
||||||
type: "aliyun",
|
|
||||||
},
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
accessId!: string;
|
|
||||||
|
|
||||||
accessService!: IAccessService;
|
|
||||||
logger!: ILogger;
|
|
||||||
|
|
||||||
async onInstance() {
|
|
||||||
this.accessService = this.ctx.accessService;
|
|
||||||
this.logger = this.ctx.logger;
|
|
||||||
}
|
|
||||||
async execute(): Promise<void> {
|
|
||||||
console.log("开始部署证书到阿里云cdn");
|
|
||||||
const access = (await this.accessService.getById(this.accessId)) as AliyunAccess;
|
|
||||||
const client = this.getClient(access);
|
|
||||||
const params = await this.buildParams();
|
|
||||||
await this.doRequest(client, params);
|
|
||||||
console.log("部署完成");
|
|
||||||
}
|
|
||||||
|
|
||||||
getClient(access: AliyunAccess) {
|
|
||||||
return new Core({
|
|
||||||
accessKeyId: access.accessKeyId,
|
|
||||||
accessKeySecret: access.accessKeySecret,
|
|
||||||
endpoint: "https://cdn.aliyuncs.com",
|
|
||||||
apiVersion: "2018-05-10",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async buildParams() {
|
|
||||||
const CertName = (this.certName ?? "certd") + "-" + dayjs().format("YYYYMMDDHHmmss");
|
|
||||||
const cert: any = this.cert;
|
|
||||||
return {
|
|
||||||
RegionId: "cn-hangzhou",
|
|
||||||
DomainName: this.domainName,
|
|
||||||
ServerCertificateStatus: "on",
|
|
||||||
CertName: CertName,
|
|
||||||
CertType: "upload",
|
|
||||||
ServerCertificate: cert.crt,
|
|
||||||
PrivateKey: cert.key,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async doRequest(client: RPCClient, params: any) {
|
|
||||||
const requestOption = {
|
|
||||||
method: "POST",
|
|
||||||
};
|
|
||||||
const ret: any = await client.request("SetDomainServerCertificate", params, requestOption);
|
|
||||||
this.checkRet(ret);
|
|
||||||
this.logger.info("设置cdn证书成功:", ret.RequestId);
|
|
||||||
}
|
|
||||||
|
|
||||||
checkRet(ret: any) {
|
|
||||||
if (ret.code != null) {
|
|
||||||
throw new Error("执行失败:" + ret.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
new DeployCertToAliyunCDN();
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
export * from "./deploy-to-cdn/index";
|
|
||||||
export * from "./deploy-to-ack-ingress/index";
|
|
||||||
export * from "./upload-to-aliyun/index";
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
import { AbstractTaskPlugin, IAccessService, IsTaskPlugin, RunStrategy, TaskInput, TaskOutput } from "@certd/pipeline";
|
|
||||||
import Core from "@alicloud/pop-core";
|
|
||||||
import { AliyunAccess } from "../../access";
|
|
||||||
import { appendTimeSuffix, checkRet, ZoneOptions } from "../../utils";
|
|
||||||
import { Logger } from "log4js";
|
|
||||||
|
|
||||||
@IsTaskPlugin({
|
|
||||||
name: "uploadCertToAliyun",
|
|
||||||
title: "上传证书到阿里云",
|
|
||||||
desc: "",
|
|
||||||
default: {
|
|
||||||
strategy: {
|
|
||||||
runStrategy: RunStrategy.SkipWhenSucceed,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
export class UploadCertToAliyun extends AbstractTaskPlugin {
|
|
||||||
@TaskInput({
|
|
||||||
title: "证书名称",
|
|
||||||
helper: "证书上传后将以此参数作为名称前缀",
|
|
||||||
})
|
|
||||||
name!: string;
|
|
||||||
|
|
||||||
@TaskInput({
|
|
||||||
title: "大区",
|
|
||||||
value: "cn-hangzhou",
|
|
||||||
component: {
|
|
||||||
name: "a-select",
|
|
||||||
vModel: "value",
|
|
||||||
options: ZoneOptions,
|
|
||||||
},
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
regionId!: string;
|
|
||||||
|
|
||||||
@TaskInput({
|
|
||||||
title: "域名证书",
|
|
||||||
helper: "请选择前置任务输出的域名证书",
|
|
||||||
component: {
|
|
||||||
name: "pi-output-selector",
|
|
||||||
},
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
cert!: any;
|
|
||||||
|
|
||||||
@TaskInput({
|
|
||||||
title: "Access授权",
|
|
||||||
helper: "阿里云授权AccessKeyId、AccessKeySecret",
|
|
||||||
component: {
|
|
||||||
name: "pi-access-selector",
|
|
||||||
type: "aliyun",
|
|
||||||
},
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
accessId!: string;
|
|
||||||
|
|
||||||
@TaskOutput({
|
|
||||||
title: "上传成功后的阿里云CertId",
|
|
||||||
})
|
|
||||||
aliyunCertId!: string;
|
|
||||||
|
|
||||||
accessService!: IAccessService;
|
|
||||||
logger!: Logger;
|
|
||||||
|
|
||||||
async onInstance() {
|
|
||||||
this.accessService = this.ctx.accessService;
|
|
||||||
this.logger = this.ctx.logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
async execute(): Promise<void> {
|
|
||||||
console.log("开始部署证书到阿里云cdn");
|
|
||||||
const access = (await this.accessService.getById(this.accessId)) as AliyunAccess;
|
|
||||||
const client = this.getClient(access);
|
|
||||||
const certName = appendTimeSuffix(this.name);
|
|
||||||
const params = {
|
|
||||||
RegionId: this.regionId || "cn-hangzhou",
|
|
||||||
Name: certName,
|
|
||||||
Cert: this.cert.crt,
|
|
||||||
Key: this.cert.key,
|
|
||||||
};
|
|
||||||
|
|
||||||
const requestOption = {
|
|
||||||
method: "POST",
|
|
||||||
};
|
|
||||||
|
|
||||||
const ret = (await client.request("CreateUserCertificate", params, requestOption)) as any;
|
|
||||||
checkRet(ret);
|
|
||||||
this.logger.info("证书上传成功:aliyunCertId=", ret.CertId);
|
|
||||||
|
|
||||||
//output
|
|
||||||
this.aliyunCertId = ret.CertId;
|
|
||||||
}
|
|
||||||
|
|
||||||
getClient(aliyunProvider: AliyunAccess) {
|
|
||||||
return new Core({
|
|
||||||
accessKeyId: aliyunProvider.accessKeyId,
|
|
||||||
accessKeySecret: aliyunProvider.accessKeySecret,
|
|
||||||
endpoint: "https://cas.aliyuncs.com",
|
|
||||||
apiVersion: "2018-07-13",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//注册插件
|
|
||||||
new UploadCertToAliyun();
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
import dayjs from "dayjs";
|
|
||||||
|
|
||||||
export const ZoneOptions = [{ value: "cn-hangzhou" }];
|
|
||||||
export function appendTimeSuffix(name: string) {
|
|
||||||
if (name == null) {
|
|
||||||
name = "certd";
|
|
||||||
}
|
|
||||||
return name + "-" + dayjs().format("YYYYMMDD-HHmmss");
|
|
||||||
}
|
|
||||||
|
|
||||||
export function checkRet(ret: any) {
|
|
||||||
if (ret.code != null) {
|
|
||||||
throw new Error("执行失败:" + ret.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"importHelpers": false,
|
|
||||||
"target": "ESNext",
|
|
||||||
"useDefineForClassFields": true,
|
|
||||||
"module": "ESNext",
|
|
||||||
"moduleResolution": "Node",
|
|
||||||
"strict": true,
|
|
||||||
"jsx": "preserve",
|
|
||||||
"sourceMap": true,
|
|
||||||
"resolveJsonModule": true,
|
|
||||||
"isolatedModules": true,
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"lib": ["ESNext", "DOM"],
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"experimentalDecorators": true,
|
|
||||||
"paths": {
|
|
||||||
"tslib" : ["./node_modules/tslib/tslib.d.ts"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue","test/**/*.ts","rollup.config.ts"],
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
import { defineConfig } from "vite";
|
|
||||||
import visualizer from "rollup-plugin-visualizer";
|
|
||||||
import typescript from "@rollup/plugin-typescript";
|
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
|
||||||
export default defineConfig({
|
|
||||||
plugins: [],
|
|
||||||
build: {
|
|
||||||
lib: {
|
|
||||||
entry: "src/index.ts",
|
|
||||||
name: "pipeline",
|
|
||||||
},
|
|
||||||
rollupOptions: {
|
|
||||||
plugins: [
|
|
||||||
// @ts-ignore
|
|
||||||
visualizer(),
|
|
||||||
// @ts-ignore
|
|
||||||
typescript({
|
|
||||||
target: "esnext",
|
|
||||||
rootDir: "src",
|
|
||||||
declaration: true,
|
|
||||||
declarationDir: "dist/d",
|
|
||||||
exclude: ["./node_modules/**", "./src/**/*.vue"],
|
|
||||||
allowSyntheticDefaultImports: true,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
external: [
|
|
||||||
"vue",
|
|
||||||
"lodash",
|
|
||||||
"dayjs",
|
|
||||||
"@certd/acme-client",
|
|
||||||
"@certd/pipeline",
|
|
||||||
"@certd/plugin-cert",
|
|
||||||
"@certd/plugin-aliyun",
|
|
||||||
"@certd/plugin-tencent",
|
|
||||||
"@certd/plugin-huawei",
|
|
||||||
"@certd/plugin-host",
|
|
||||||
"@certd/plugin-tencent",
|
|
||||||
"@certd/plugin-util",
|
|
||||||
],
|
|
||||||
output: {
|
|
||||||
globals: {
|
|
||||||
vue: "Vue",
|
|
||||||
lodash: "_",
|
|
||||||
dayjs: "dayjs",
|
|
||||||
"@certd/plugin-cert": "CertdPluginCert",
|
|
||||||
"@certd/acme-client": "CertdAcmeClient",
|
|
||||||
"@certd/pipeline": "CertdPluginPipeline",
|
|
||||||
"@certd/plugin-aliyun": "CertdPluginAliyun",
|
|
||||||
"@certd/plugin-host": "CertdPluginHost",
|
|
||||||
"@certd/plugin-huawei": "CertdPluginHuawei",
|
|
||||||
"@certd/plugin-util": "CertdPluginUtil",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"parser": "@typescript-eslint/parser",
|
|
||||||
"plugins": [
|
|
||||||
"@typescript-eslint"
|
|
||||||
],
|
|
||||||
"extends": [
|
|
||||||
"plugin:@typescript-eslint/recommended",
|
|
||||||
"plugin:prettier/recommended",
|
|
||||||
"prettier"
|
|
||||||
],
|
|
||||||
"env": {
|
|
||||||
"mocha": true
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"@typescript-eslint/no-var-requires": "off",
|
|
||||||
"@typescript-eslint/ban-ts-comment": "off",
|
|
||||||
"@typescript-eslint/ban-ts-ignore": "off",
|
|
||||||
"@typescript-eslint/no-explicit-any": "off",
|
|
||||||
"@typescript-eslint/no-empty-function": "off",
|
|
||||||
// "no-unused-expressions": "off",
|
|
||||||
"max-len": [0, 160, 2, { "ignoreUrls": true }]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
26
packages/plugins/plugin-all/.gitignore
vendored
26
packages/plugins/plugin-all/.gitignore
vendored
@@ -1,26 +0,0 @@
|
|||||||
# Logs
|
|
||||||
logs
|
|
||||||
*.log
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
pnpm-debug.log*
|
|
||||||
lerna-debug.log*
|
|
||||||
|
|
||||||
node_modules
|
|
||||||
dist
|
|
||||||
dist-ssr
|
|
||||||
*.local
|
|
||||||
|
|
||||||
# Editor directories and files
|
|
||||||
.vscode/*
|
|
||||||
!.vscode/extensions.json
|
|
||||||
.idea
|
|
||||||
.DS_Store
|
|
||||||
*.suo
|
|
||||||
*.ntvs*
|
|
||||||
*.njsproj
|
|
||||||
*.sln
|
|
||||||
*.sw?
|
|
||||||
|
|
||||||
test/user.secret.ts
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"extension": ["ts"],
|
|
||||||
"spec": "test/**/*.test.ts",
|
|
||||||
"require": "ts-node/register"
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
node_modules
|
|
||||||
src
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"printWidth": 160
|
|
||||||
}
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
# Change Log
|
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
||||||
|
|
||||||
## [1.20.8](https://github.com/certd/certd/compare/v1.20.7...v1.20.8) (2024-03-22)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-all
|
|
||||||
|
|
||||||
## [1.20.7](https://github.com/certd/certd/compare/v1.20.6...v1.20.7) (2024-03-22)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-all
|
|
||||||
|
|
||||||
## [1.20.6](https://github.com/certd/certd/compare/v1.20.5...v1.20.6) (2024-03-21)
|
|
||||||
|
|
||||||
### Performance Improvements
|
|
||||||
|
|
||||||
* 插件贡献文档及示例 ([72fb20a](https://github.com/certd/certd/commit/72fb20abf3ba5bdd862575d2907703a52fd7eb17))
|
|
||||||
|
|
||||||
## [1.20.5](https://github.com/certd/certd/compare/v1.20.2...v1.20.5) (2024-03-11)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-all
|
|
||||||
|
|
||||||
## [1.20.2](https://github.com/certd/certd/compare/v1.2.1...v1.20.2) (2024-02-28)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-all
|
|
||||||
|
|
||||||
## [1.2.1](https://github.com/certd/certd/compare/v1.2.0...v1.2.1) (2023-12-12)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-all
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-all
|
|
||||||
|
|
||||||
# [1.2.0](https://github.com/certd/certd/compare/v1.1.6...v1.2.0) (2023-10-27)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-all
|
|
||||||
|
|
||||||
## [1.1.6](https://github.com/certd/certd/compare/v1.1.5...v1.1.6) (2023-07-10)
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* 修复上传证书到腾讯云失败的bug ([e950322](https://github.com/certd/certd/commit/e950322232e19d1263b8552eefa5b0150fd7864e))
|
|
||||||
|
|
||||||
## [1.1.5](https://github.com/certd/certd/compare/v1.1.4...v1.1.5) (2023-07-03)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-all
|
|
||||||
|
|
||||||
## [1.1.4](https://github.com/certd/certd/compare/v1.1.3...v1.1.4) (2023-07-03)
|
|
||||||
|
|
||||||
### Performance Improvements
|
|
||||||
|
|
||||||
* timeout ([3eeb1f7](https://github.com/certd/certd/commit/3eeb1f77aa2922f3545f3d2067f561d95621d54f))
|
|
||||||
|
|
||||||
## [1.1.3](https://github.com/certd/certd/compare/v1.1.2...v1.1.3) (2023-07-03)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-all
|
|
||||||
|
|
||||||
## [1.1.2](https://github.com/certd/certd/compare/v1.1.1...v1.1.2) (2023-07-03)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-all
|
|
||||||
|
|
||||||
## [1.1.1](https://github.com/certd/certd/compare/v1.1.0...v1.1.1) (2023-06-28)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-all
|
|
||||||
|
|
||||||
# [1.1.0](https://github.com/certd/certd/compare/v1.0.6...v1.1.0) (2023-06-28)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-all
|
|
||||||
|
|
||||||
## [1.0.6](https://github.com/certd/certd/compare/v1.0.5...v1.0.6) (2023-05-25)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-all
|
|
||||||
|
|
||||||
## [1.0.5](https://github.com/certd/certd/compare/v1.0.4...v1.0.5) (2023-05-25)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-all
|
|
||||||
|
|
||||||
## [1.0.4](https://github.com/certd/certd/compare/v1.0.3...v1.0.4) (2023-05-25)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-all
|
|
||||||
|
|
||||||
## [1.0.3](https://github.com/certd/certd/compare/v1.0.2...v1.0.3) (2023-05-25)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-all
|
|
||||||
|
|
||||||
## [1.0.2](https://github.com/certd/certd/compare/v1.0.1...v1.0.2) (2023-05-24)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-all
|
|
||||||
|
|
||||||
## [1.0.1](https://github.com/certd/certd/compare/v1.0.0...v1.0.1) (2023-05-24)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-all
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
# Vue 3 + TypeScript + Vite
|
|
||||||
|
|
||||||
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
|
||||||
|
|
||||||
## Recommended IDE Setup
|
|
||||||
|
|
||||||
- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar)
|
|
||||||
|
|
||||||
## Type Support For `.vue` Imports in TS
|
|
||||||
|
|
||||||
Since TypeScript cannot handle type information for `.vue` imports, they are shimmed to be a generic Vue component type by default. In most cases this is fine if you don't really care about component prop types outside of templates. However, if you wish to get actual prop types in `.vue` imports (for example to get props validation when using manual `h(...)` calls), you can enable Volar's Take Over mode by following these steps:
|
|
||||||
|
|
||||||
1. Run `Extensions: Show Built-in Extensions` from VS Code's command palette, look for `TypeScript and JavaScript Language Features`, then right click and select `Disable (Workspace)`. By default, Take Over mode will enable itself if the default TypeScript extension is disabled.
|
|
||||||
2. Reload the VS Code window by running `Developer: Reload Window` from the command palette.
|
|
||||||
|
|
||||||
You can learn more about Take Over mode [here](https://github.com/johnsoncodehk/volar/discussions/471).
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@certd/plugin-all",
|
|
||||||
"private": false,
|
|
||||||
"version": "1.20.8",
|
|
||||||
"main": "./src/index.ts",
|
|
||||||
"module": "./src/index.ts",
|
|
||||||
"types": "./src/index.ts",
|
|
||||||
"publishConfig": {
|
|
||||||
"main": "./dist/bundle.js",
|
|
||||||
"module": "./dist/bundle.mjs",
|
|
||||||
"types": "./dist/d/index.d.ts"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"dev": "vite",
|
|
||||||
"build2": " vite build",
|
|
||||||
"build": "rollup -c",
|
|
||||||
"preview": "vite preview"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@certd/pipeline": "^1.20.8",
|
|
||||||
"@certd/plugin-aliyun": "^1.20.8",
|
|
||||||
"@certd/plugin-center": "^1.20.8",
|
|
||||||
"@certd/plugin-cert": "^1.20.8",
|
|
||||||
"@certd/plugin-host": "^1.20.8",
|
|
||||||
"@certd/plugin-huawei": "^1.20.8",
|
|
||||||
"@certd/plugin-tencent": "^1.20.8",
|
|
||||||
"@rollup/plugin-commonjs": "^23.0.4",
|
|
||||||
"@rollup/plugin-json": "^6.0.0",
|
|
||||||
"@rollup/plugin-node-resolve": "^15.0.1",
|
|
||||||
"@rollup/plugin-terser": "^0.4.3",
|
|
||||||
"@rollup/plugin-typescript": "^11.0.0",
|
|
||||||
"@types/chai": "^4.3.5",
|
|
||||||
"@types/jest": "^26.0.24",
|
|
||||||
"@types/lodash": "^4.14.186",
|
|
||||||
"@types/node-forge": "^1.3.0",
|
|
||||||
"@typescript-eslint/eslint-plugin": "^5.38.1",
|
|
||||||
"@typescript-eslint/parser": "^5.38.1",
|
|
||||||
"eslint": "^8.24.0",
|
|
||||||
"eslint-config-prettier": "^8.5.0",
|
|
||||||
"eslint-plugin-import": "^2.26.0",
|
|
||||||
"eslint-plugin-node": "^11.1.0",
|
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
|
||||||
"prettier": "^2.8.8",
|
|
||||||
"rollup": "^3.7.4",
|
|
||||||
"rollup-plugin-typescript2": "^0.34.1",
|
|
||||||
"rollup-plugin-visualizer": "^5.8.2",
|
|
||||||
"ts-node": "^10.9.1",
|
|
||||||
"tslib": "^2.5.2",
|
|
||||||
"typescript": "^4.8.4",
|
|
||||||
"vite": "^3.1.0",
|
|
||||||
"vue-tsc": "^0.38.9"
|
|
||||||
},
|
|
||||||
"gitHead": "b258e926209fef4cc4d633b0383eb54e26c516f9"
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
const resolve = require("@rollup/plugin-node-resolve");
|
|
||||||
const commonjs = require("@rollup/plugin-commonjs");
|
|
||||||
//const Typescript = require("rollup-plugin-typescript2");
|
|
||||||
const Typescript = require("@rollup/plugin-typescript");
|
|
||||||
const json = require("@rollup/plugin-json");
|
|
||||||
const terser = require("@rollup/plugin-terser");
|
|
||||||
module.exports = {
|
|
||||||
input: "src/index.ts",
|
|
||||||
output: {
|
|
||||||
file: "dist/bundle.js",
|
|
||||||
format: "cjs",
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
// 解析第三方依赖
|
|
||||||
resolve(),
|
|
||||||
// 识别 commonjs 模式第三方依赖
|
|
||||||
commonjs(),
|
|
||||||
Typescript({
|
|
||||||
target: "esnext",
|
|
||||||
rootDir: "src",
|
|
||||||
declaration: true,
|
|
||||||
declarationDir: "dist/d",
|
|
||||||
exclude: ["./node_modules/**", "./src/**/*.vue"],
|
|
||||||
allowSyntheticDefaultImports: true,
|
|
||||||
}),
|
|
||||||
json(),
|
|
||||||
terser(),
|
|
||||||
],
|
|
||||||
external: [
|
|
||||||
"vue",
|
|
||||||
"lodash",
|
|
||||||
"dayjs",
|
|
||||||
"@certd/acme-client",
|
|
||||||
"@certd/pipeline",
|
|
||||||
"@certd/plugin-cert",
|
|
||||||
"@certd/plugin-aliyun",
|
|
||||||
"@certd/plugin-tencent",
|
|
||||||
"@certd/plugin-huawei",
|
|
||||||
"@certd/plugin-host",
|
|
||||||
"@certd/plugin-tencent",
|
|
||||||
"@certd/plugin-util",
|
|
||||||
"@certd/plugin-center",
|
|
||||||
],
|
|
||||||
};
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
export * from "@certd/plugin-cert";
|
|
||||||
export * from "@certd/plugin-aliyun";
|
|
||||||
export * from "@certd/plugin-tencent";
|
|
||||||
export * from "@certd/plugin-host";
|
|
||||||
export * from "@certd/plugin-huawei";
|
|
||||||
export * from "@certd/plugin-center";
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
export const fakeCrt = `-----BEGIN CERTIFICATE-----
|
|
||||||
MIIFSTCCBDGgAwIBAgITAPoZZk/LhVIyXoic2NnJyxubezANBgkqhkiG9w0BAQsF
|
|
||||||
ADAiMSAwHgYDVQQDDBdGYWtlIExFIEludGVybWVkaWF0ZSBYMTAeFw0yMDEyMTQx
|
|
||||||
NjA1NTFaFw0yMTAzMTQxNjA1NTFaMBsxGTAXBgNVBAMMECouZG9jbWlycm9yLmNs
|
|
||||||
dWIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC75tGrYjly+RpcZehQ
|
|
||||||
my1EpaXElT4L60pINKV2YDKnBrcSSo1c6rO7nFh12eC/ju4WwYUep0RVmBDF8xD0
|
|
||||||
I1Sd1uuDTQWP0UT1X9yqdXtjvxpUqoCHAzG633f3sJRFul7mDLuC9tRCuae9o7qP
|
|
||||||
EZ827XOmjBR35dso9I2GEE4828J3YE3tSKtobZlM+30jozLEcsO0PTyM5mq5PPjP
|
|
||||||
VI3fGLcEaBmLZf5ixz4XkcY9IAhyAMYf03cT2wRoYPBaDdXblgCYL6sFtIMbzl3M
|
|
||||||
Di94PB8NyoNSsC2nmBdWi54wFOgBvY/4ljsX/q7X3EqlSvcA0/M6/c/J9kJ3eupv
|
|
||||||
jV8nAgMBAAGjggJ9MIICeTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYB
|
|
||||||
BQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFAkdTjSCV3KD
|
|
||||||
x28sf98MrwVfyFYgMB8GA1UdIwQYMBaAFMDMA0a5WCDMXHJw8+EuyyCm9Wg6MHcG
|
|
||||||
CCsGAQUFBwEBBGswaTAyBggrBgEFBQcwAYYmaHR0cDovL29jc3Auc3RnLWludC14
|
|
||||||
MS5sZXRzZW5jcnlwdC5vcmcwMwYIKwYBBQUHMAKGJ2h0dHA6Ly9jZXJ0LnN0Zy1p
|
|
||||||
bnQteDEubGV0c2VuY3J5cHQub3JnLzArBgNVHREEJDAighAqLmRvY21pcnJvci5j
|
|
||||||
bHVigg5kb2NtaXJyb3IuY2x1YjBMBgNVHSAERTBDMAgGBmeBDAECATA3BgsrBgEE
|
|
||||||
AYLfEwEBATAoMCYGCCsGAQUFBwIBFhpodHRwOi8vY3BzLmxldHNlbmNyeXB0Lm9y
|
|
||||||
ZzCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB1ABboacHRlerXw/iXGuPwdgH3jOG2
|
|
||||||
nTGoUhi2g38xqBUIAAABdmI3LM4AAAQDAEYwRAIgaiNqXSEq+sxp8eqlJXp/KFdO
|
|
||||||
so5mT50MoRsLF8Inu0ACIDP46+ekng7I0BlmyIPmbqFcZgnZFVWLLCdLYijhVyOL
|
|
||||||
AHcA3Zk0/KXnJIDJVmh9gTSZCEmySfe1adjHvKs/XMHzbmQAAAF2YjcuxwAABAMA
|
|
||||||
SDBGAiEAxpeB8/w4YkHZ62nH20h128VtuTSmYDCnF7EK2fQyeZYCIQDbJlF2wehZ
|
|
||||||
sF1BeE7qnYYqCTP0dYIrQ9HWtBa/MbGOKTANBgkqhkiG9w0BAQsFAAOCAQEAL2di
|
|
||||||
HKh6XcZtGk0BFxJa51sCZ3MLu9+Zy90kCRD4ooP5x932WxVM25+LBRd+xSzx+TRL
|
|
||||||
UVrlKp9GdMYX1JXL4Vf2NwzuFO3snPDe/qizD/3+D6yo8eKJ/LD82t5kLWAD2rto
|
|
||||||
YfVSTKwfNIBBJwHUnjviBPJmheHHCKmz8Ct6/6QxFAeta9TAMn0sFeVCQnmAq7HL
|
|
||||||
jrunq0tNHR/EKG0ITPLf+6P7MxbmpYNnq918766l0tKsW8oo8ZSGEwKU2LMaSiAa
|
|
||||||
hasyl/2gMnYXjtKOjDcnR8oLpbrOg0qpVbynmJin1HP835oHPPAZ1gLsqYTTizNz
|
|
||||||
AHxTaXliTVvS83dogw==
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIEqzCCApOgAwIBAgIRAIvhKg5ZRO08VGQx8JdhT+UwDQYJKoZIhvcNAQELBQAw
|
|
||||||
GjEYMBYGA1UEAwwPRmFrZSBMRSBSb290IFgxMB4XDTE2MDUyMzIyMDc1OVoXDTM2
|
|
||||||
MDUyMzIyMDc1OVowIjEgMB4GA1UEAwwXRmFrZSBMRSBJbnRlcm1lZGlhdGUgWDEw
|
|
||||||
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDtWKySDn7rWZc5ggjz3ZB0
|
|
||||||
8jO4xti3uzINfD5sQ7Lj7hzetUT+wQob+iXSZkhnvx+IvdbXF5/yt8aWPpUKnPym
|
|
||||||
oLxsYiI5gQBLxNDzIec0OIaflWqAr29m7J8+NNtApEN8nZFnf3bhehZW7AxmS1m0
|
|
||||||
ZnSsdHw0Fw+bgixPg2MQ9k9oefFeqa+7Kqdlz5bbrUYV2volxhDFtnI4Mh8BiWCN
|
|
||||||
xDH1Hizq+GKCcHsinDZWurCqder/afJBnQs+SBSL6MVApHt+d35zjBD92fO2Je56
|
|
||||||
dhMfzCgOKXeJ340WhW3TjD1zqLZXeaCyUNRnfOmWZV8nEhtHOFbUCU7r/KkjMZO9
|
|
||||||
AgMBAAGjgeMwgeAwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAw
|
|
||||||
HQYDVR0OBBYEFMDMA0a5WCDMXHJw8+EuyyCm9Wg6MHoGCCsGAQUFBwEBBG4wbDA0
|
|
||||||
BggrBgEFBQcwAYYoaHR0cDovL29jc3Auc3RnLXJvb3QteDEubGV0c2VuY3J5cHQu
|
|
||||||
b3JnLzA0BggrBgEFBQcwAoYoaHR0cDovL2NlcnQuc3RnLXJvb3QteDEubGV0c2Vu
|
|
||||||
Y3J5cHQub3JnLzAfBgNVHSMEGDAWgBTBJnSkikSg5vogKNhcI5pFiBh54DANBgkq
|
|
||||||
hkiG9w0BAQsFAAOCAgEABYSu4Il+fI0MYU42OTmEj+1HqQ5DvyAeyCA6sGuZdwjF
|
|
||||||
UGeVOv3NnLyfofuUOjEbY5irFCDtnv+0ckukUZN9lz4Q2YjWGUpW4TTu3ieTsaC9
|
|
||||||
AFvCSgNHJyWSVtWvB5XDxsqawl1KzHzzwr132bF2rtGtazSqVqK9E07sGHMCf+zp
|
|
||||||
DQVDVVGtqZPHwX3KqUtefE621b8RI6VCl4oD30Olf8pjuzG4JKBFRFclzLRjo/h7
|
|
||||||
IkkfjZ8wDa7faOjVXx6n+eUQ29cIMCzr8/rNWHS9pYGGQKJiY2xmVC9h12H99Xyf
|
|
||||||
zWE9vb5zKP3MVG6neX1hSdo7PEAb9fqRhHkqVsqUvJlIRmvXvVKTwNCP3eCjRCCI
|
|
||||||
PTAvjV+4ni786iXwwFYNz8l3PmPLCyQXWGohnJ8iBm+5nk7O2ynaPVW0U2W+pt2w
|
|
||||||
SVuvdDM5zGv2f9ltNWUiYZHJ1mmO97jSY/6YfdOUH66iRtQtDkHBRdkNBsMbD+Em
|
|
||||||
2TgBldtHNSJBfB3pm9FblgOcJ0FSWcUDWJ7vO0+NTXlgrRofRT6pVywzxVo6dND0
|
|
||||||
WzYlTWeUVsO40xJqhgUQRER9YLOLxJ0O6C8i0xFxAMKOtSdodMB3RIwt7RFQ0uyt
|
|
||||||
n5Z5MqkYhlMI3J1tPRTp1nEt9fyGspBOO05gi148Qasp+3N+svqKomoQglNoAxU=
|
|
||||||
-----END CERTIFICATE-----`;
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user