aardio 文档

aardio 范例: ACME 申请证书

阿里云 DNS 解析 | IIS 管理接口

/*
IIS / FastCGI 运行 aardio 可支持 HTTPS。
如果是 aardio 内置的 wsock.tcp.simpleHttpServer 等仅支持 HTTP,
可使用 dotNet 库调用 C# 将 HTTPS 转发到 aardio 的 HTTP 服务器即可,要不了几句代码。

IIS 管理接口: https://www.aardio.com/zh-cn/doc/example/Languages/dotNet/Apps/IIS.html
*/
import console.int;
import web.acme;
import crypt.rsa;
import crypt.cert; 
console.showLoading("正在初始化");

// 使用测试环境(开发时推荐)
var acme,err = web.acme("letsencrypt_test");

// 2. 生成或加载账户密钥
acme.initAccountKey(io.appData("/aardio/example/web/acme/account.key"));

// 3. 注册账户,邮箱仅用于接收通知所以不用验证
var account, err = acme.register("admin@aardio.com");
if(!account) {  
    return console.error("注册失败:", err);
}
console.log("账户 URL:", acme.accountUrl);

// 4. 创建订单
var order, err = acme.newOrder("test-acme.aardio.com");
if(!order) return console.error("创建订单失败:", err);
console.log("订单状态:", order.status);

// 5. 处理授权
for(i, authUrl in order.authorizations){
    var auth = acme.getAuthorization(authUrl);
    console.log("域名:", auth.identifier.value);

    // 查找 HTTP-01 挑战
    for(_, challenge in auth.challenges){
        if(challenge.type == "http-01"){
            var keyAuth = acme.getKeyAuthorization(challenge.token);

            console.log("HTTP-01 挑战:");
            console.log("  URL: http://" + auth.identifier.value + 
                       "/.well-known/acme-challenge/" + challenge.token);
            console.log("  内容:", keyAuth);

            // TODO: 在 Web 服务器上部署挑战文件
            console.pause(,"部署完成后按回车继续...");
            console.showLoading("正在验证")

            // 通知服务器验证
            acme.respondChallenge(challenge.url);

            // 等待验证完成
            var result = acme.pollStatus(authUrl, "valid", 30, 3000);
            if(!result) return console.log("验证失败");
            console.log("验证通过!");
        }
        /***************
        elseif(challenge.type == "dns-01"){
            dnsChallengeFound = true;

            // 计算需要的 TXT 记录值
            var dnsValue = acme.getDns01Value(challenge.token);
            var hostRecord = "_acme-challenge";
            // 如果是泛域名或子域名,显示完整主机头有助于理解
            var fullRecord = "_acme-challenge." + auth.identifier.value; 

            //阿里云 DNS 解析: https://www.aardio.com/zh-cn/doc/example/Web/REST/aliyun/dns.html

            console.log("----------------------------------------------------");
            console.log("【请手动添加 DNS TXT 记录以完成验证】");
            console.log("域名(Host):", hostRecord);
            console.log("完整记录名:", fullRecord);
            console.log("记录值(Value):", dnsValue);
            console.log("----------------------------------------------------");

            // 暂停等待用户操作
            // 在实际工程中,这里可以调用阿里云/腾讯云 API 自动添加解析记录
            console.log("请前往域名服务商添加上述 TXT 记录。");
            console.log("注意:添加后通常需要等待几分钟让 DNS 全球生效。");
            console.pause(, "添加并等待生效后,请按任意键继续验证...");
            console.showLoading("正在验证")

            console.log("正在通知服务器验证...");
            acme.respondChallenge(challenge.url);

            // 轮询等待验证结果
            var result, err = acme.pollStatus(authUrl, "valid", 30, 5000);
            if(!result) {
                console.error("验证失败:", err);
                return;
            }
            console.log("域名验证通过!");
        }
        ***************/
    }
}

console.log("正在申请证书")

// 6. 生成域名密钥和 CSR

import crypt.csr;
var csrGen = crypt.csr();
csrGen.genSignatureKey(2048) // 生成密钥对 
var domainKeyPem = csrGen.exportPrivateKeyPkcs8ToPem();
string.save("/domain.key",domainKeyPem)

var csrDer, err = csrGen.createDer("test-acme.aardio.com");
csrGen.delete();

// 7. 完成订单
var result = acme.finalizeOrder(order.finalize, csrDer);
console.log("Finalize 状态:", result.status);
console.showLoading("正在签发证书")

// 8. 等待证书签发
order = acme.pollStatus(order.orderUrl, "valid", 30, 3000);
if(!order) return console.log("证书签发失败");

// 9. 下载证书
var certPem = acme.downloadCertificate(order.certificate);
if(!certPem) return console.error("下载证书内容为空");
string.save("/cert.pem", certPem);
console.log("已保存 cert.pem 证书!");

// 从 PEM 创建证书对象
import crypt.cert
var crt, err = crypt.cert.fromPem(domainKeyPem, certPem);

//显示证书信息
console.log("  主题:", crt.subject);
console.log("  颁发者:", crt.issuer);
console.log("  序列号:", crt.serialNumber);
console.log("  指纹:", crt.thumbprint);
console.log("  算法:", crt.algorithm);
console.log("  生效时间:", crt.validFrom);
console.log("  过期时间:", crt.validTo);
console.log("  是否有效:", crt.isValid);
console.log("  含私钥:", crt.hasPrivateKey);

//转换为 pfx 文件 
var pfxPath, password = crt.exportPfx("123456", "/cert.pfx");

if(pfxPath){
    console.success("PFX 转换成功!已保存为:", pfxPath);
    console.log("密码:", password); 
} else {
    // 导出失败时,第二个返回值是错误信息
    console.error("PFX 导出失败:", password);
}

console.pause(); 
Markdown 格式