@certd/plugin-plus 1.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.eslintrc ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "parser": "@typescript-eslint/parser",
3
+ "plugins": [
4
+ "@typescript-eslint"
5
+ ],
6
+ "extends": [
7
+ "plugin:@typescript-eslint/recommended",
8
+ "plugin:prettier/recommended",
9
+ "prettier"
10
+ ],
11
+ "env": {
12
+ "mocha": true
13
+ },
14
+ "rules": {
15
+ "@typescript-eslint/no-var-requires": "off",
16
+ "@typescript-eslint/ban-ts-comment": "off",
17
+ "@typescript-eslint/ban-ts-ignore": "off",
18
+ "@typescript-eslint/no-explicit-any": "off",
19
+ "@typescript-eslint/no-empty-function": "off",
20
+ // "no-unused-expressions": "off",
21
+ "max-len": [0, 160, 2, { "ignoreUrls": true }]
22
+ }
23
+ }
package/.prettierrc ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "printWidth": 160
3
+ }
package/CHANGELOG.md ADDED
@@ -0,0 +1,15 @@
1
+ # Change Log
2
+
3
+ All notable changes to this project will be documented in this file.
4
+ See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
+
6
+ ## [1.22.1](https://github.com/certd/certd/compare/v1.22.0...v1.22.1) (2024-07-20)
7
+
8
+ **Note:** Version bump only for package @certd/lib-huawei
9
+
10
+ # [1.22.0](https://github.com/certd/certd/compare/v1.21.2...v1.22.0) (2024-07-19)
11
+
12
+ ### Features
13
+
14
+ * 升级midway,支持esm ([485e603](https://github.com/certd/certd/commit/485e603b5165c28bc08694997726eaf2a585ebe7))
15
+ * 支持postgresql ([3b19bfb](https://github.com/certd/certd/commit/3b19bfb4291e89064b3b407a80dae092d54747d5))
package/README.md ADDED
@@ -0,0 +1,16 @@
1
+ # Vue 3 + TypeScript + Vite
2
+
3
+ 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.
4
+
5
+ ## Recommended IDE Setup
6
+
7
+ - [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar)
8
+
9
+ ## Type Support For `.vue` Imports in TS
10
+
11
+ 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:
12
+
13
+ 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.
14
+ 2. Reload the VS Code window by running `Developer: Reload Window` from the command palette.
15
+
16
+ You can learn more about Take Over mode [here](https://github.com/johnsoncodehk/volar/discussions/471).
@@ -0,0 +1 @@
1
+ "use strict";var e=require("@certd/pipeline"),t=require("@certd/plugin-cert"),s=require("node:crypto"),o=require("fs"),r=require("node:path");function n(e,t,s,o){var r,n=arguments.length,i=n<3?t:null===o?o=Object.getOwnPropertyDescriptor(t,s):o;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,s,o);else for(var p=e.length-1;p>=0;p--)(r=e[p])&&(i=(n<3?r(i):n>3?r(t,s,i):r(t,s))||i);return n>3&&i&&Object.defineProperty(t,s,i),i}function i(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}"function"==typeof SuppressedError&&SuppressedError;class p{access;http;constructor(e,t){this.access=e,this.http=t}getRequestToken(){const e=(new Date).getTime(),t=e+this.getMd5(this.access.apiSecret);return{request_token:this.getMd5(t),request_time:e}}getMd5(e){return s.createHash("md5").update(e).digest("hex")}async doRequest(e,t,s){const o=this.getRequestToken();console.log("token",o);const r={...o,...s};let n=`${this.access.panelUrl}${e}`;t&&(n=`${n}?action=${t}`);const i=await this.http.request({url:n,method:"post",headers:{"Content-Type":"application/x-www-form-urlencoded"},data:r});if(!i.status)throw new Error(i.msg);return i}}class a extends e.AbstractTaskPlugin{setCtx(t){super.setCtx(t),function(){if(!e.isPlus())throw new Error("此插件仅供专业版中使用")}()}}exports.BaotaDeployPanelCertPlugin=class extends a{cert;accessId;async onInstance(){}async execute(){const{cert:e,accessId:s}=this,o=new t.CertReader(e),r=await this.accessService.getById(s),n=this.ctx.http,i=new p(r,n),a=await i.doRequest("/config","SavePanelSSL",{privateKey:o.key,certPem:o.crt});this.logger.info(a?.msg)}},n([e.TaskInput({title:"域名证书",helper:"请选择前置任务输出的域名证书",component:{name:"pi-output-selector"},required:!0}),i("design:type",Object)],exports.BaotaDeployPanelCertPlugin.prototype,"cert",void 0),n([e.TaskInput({title:"宝塔授权",helper:"baota的接口密钥,目前测试宝塔面板本身开启ssl之后,API接口就不能用了",component:{name:"pi-access-selector",type:"baota"},required:!0}),i("design:type",String)],exports.BaotaDeployPanelCertPlugin.prototype,"accessId",void 0),exports.BaotaDeployPanelCertPlugin=n([e.IsTaskPlugin({name:"BaotaDeployPanelCert",title:"宝塔面板证书部署",group:e.pluginGroups.other.key,desc:"部署宝塔面板本身的ssl证书",default:{strategy:{runStrategy:e.RunStrategy.SkipWhenSucceed}},needPlus:!0})],exports.BaotaDeployPanelCertPlugin),new exports.BaotaDeployPanelCertPlugin,exports.BaotaDeployWebSiteCertPlugin=class extends a{siteName;isReverseProxy=!1;cert;accessId;async onInstance(){}async execute(){const{cert:e,accessId:s}=this,o=new t.CertReader(e),r=await this.accessService.getById(s),n=this.ctx.http,i=new p(r,n);if(this.logger.info(`siteName:${this.siteName}`),this.isReverseProxy){const e=await i.doRequest("/mod/proxy/com/set_ssl",null,{site_name:this.siteName,key:o.key,csr:o.crt});this.logger.info(e?.msg)}else{const e=await i.doRequest("/site","SetSSL",{type:0,siteName:this.siteName,key:o.key,csr:o.crt});this.logger.info(e?.msg)}}},n([e.TaskInput({title:"网站域名",component:{name:"a-input"},helper:"登录面板->网站->网站名/域名/项目名称",required:!0}),i("design:type",String)],exports.BaotaDeployWebSiteCertPlugin.prototype,"siteName",void 0),n([e.TaskInput({title:"是否反向代理",value:!1,component:{name:"a-switch",vModel:"checked"},helper:"该项目类型是反向代理还是其他项目",required:!0}),i("design:type",Object)],exports.BaotaDeployWebSiteCertPlugin.prototype,"isReverseProxy",void 0),n([e.TaskInput({title:"域名证书",helper:"请选择前置任务输出的域名证书",component:{name:"pi-output-selector"},required:!0}),i("design:type",Object)],exports.BaotaDeployWebSiteCertPlugin.prototype,"cert",void 0),n([e.TaskInput({title:"宝塔授权",helper:"baota的接口密钥",component:{name:"pi-access-selector",type:"baota"},required:!0}),i("design:type",String)],exports.BaotaDeployWebSiteCertPlugin.prototype,"accessId",void 0),exports.BaotaDeployWebSiteCertPlugin=n([e.IsTaskPlugin({name:"BaotaDeployWebSiteCert",title:"宝塔网站证书部署",group:e.pluginGroups.other.key,desc:"部署宝塔管理的站点的ssl证书",default:{strategy:{runStrategy:e.RunStrategy.SkipWhenSucceed}},needPlus:!0})],exports.BaotaDeployWebSiteCertPlugin),new exports.BaotaDeployWebSiteCertPlugin,exports.BaotaAccess=class{panelUrl="";apiSecret=""},n([e.AccessInput({title:"宝塔URL地址",component:{placeholder:"http://192.168.42.237:41896"},helper:"宝塔面板的url地址,例如:http://192.168.42.237:41896",required:!0}),i("design:type",Object)],exports.BaotaAccess.prototype,"panelUrl",void 0),n([e.AccessInput({title:"接口密钥",component:{placeholder:"接口密钥"},helper:"宝塔面板设置->面板设置->API接口->接口配置->接口密钥。\n必须要加IP白名单,你可以先运行一次,报错之后会打印IP,将IP加入白名单之后再次运行即可",required:!0,encrypt:!0}),i("design:type",Object)],exports.BaotaAccess.prototype,"apiSecret",void 0),exports.BaotaAccess=n([e.IsAccess({name:"baota",title:"baota授权",desc:""})],exports.BaotaAccess),new exports.BaotaAccess,exports.YidunDeployToCDNPlugin=class extends a{certId;domain;cert;accessId;async onInstance(){}async execute(){const{domain:e,certId:s,cert:o}=this;if(!e&&!s)throw new Error("证书ID和网站域名必须填写一个");const r=new t.CertReader(o);s>0?await this.updateByCertId(r,s):await this.updateByDomain(r)}async updateByCertId(e,t){this.logger.info(`更新证书,证书ID:${t}`);const s=`http://user.yiduncdn.com/v1/certs/${t}`;await this.doRequest(s,"PUT",{cert:e.crt,key:e.key})}async doRequest(e,t,s){const o=await this.accessService.getById(this.accessId),{apiKey:r,apiSecret:n}=o,i=this.ctx.http,p=await i.request({url:e,method:t,headers:{"api-key":r,"api-secret":n},data:s});if(0!=p.code)throw new Error(p.msg);return p}async updateByDomain(e){const t=await this.doRequest("http://user.yiduncdn.com/v1/sites","GET",{domain:this.domain});if(0===t.data.length)throw new Error(`未找到域名相关站点:${this.domain}`);let s=null;for(const e of t.data)e.domain===this.domain&&(s=e);if(!s)throw new Error(`未找到域名匹配的站点:${this.domain}`);if(s.https_listen?.cert){const t=s.https_listen.cert;await this.updateByCertId(e,t)}else{this.logger.info(`创建证书,域名:${this.domain}`);const t="http://user.yiduncdn.com/v1/certs",o=this.domain+"_"+(new Date).getTime();await this.doRequest(t,"POST",{name:o,type:"custom",cert:e.crt,key:e.key});const r=(await this.doRequest(t,"GET",{name:o})).data[0].id,n="http://user.yiduncdn.com/v1/sites";await this.doRequest(n,"PUT",{id:s.id,https_listen:{cert:r}})}}},n([e.TaskInput({title:"证书ID",component:{name:"a-input-number",vModel:"value"},helper:"证书ID,在证书管理页面查看,每条记录都有证书id"}),i("design:type",Number)],exports.YidunDeployToCDNPlugin.prototype,"certId",void 0),n([e.TaskInput({title:"网站域名",component:{name:"a-input",vModel:"value"},helper:"网站域名和证书ID选填其中一个,填了证书ID,则忽略网站域名"}),i("design:type",Number)],exports.YidunDeployToCDNPlugin.prototype,"domain",void 0),n([e.TaskInput({title:"域名证书",helper:"请选择前置任务输出的域名证书",component:{name:"pi-output-selector"},required:!0}),i("design:type",Object)],exports.YidunDeployToCDNPlugin.prototype,"cert",void 0),n([e.TaskInput({title:"易盾授权",helper:"易盾CDN授权",component:{name:"pi-access-selector",type:"yidun"},required:!0}),i("design:type",String)],exports.YidunDeployToCDNPlugin.prototype,"accessId",void 0),exports.YidunDeployToCDNPlugin=n([e.IsTaskPlugin({name:"YidunDeployToCDN",title:"部署证书到易盾CDN",group:e.pluginGroups.other.key,desc:"http://user.yiduncdn.com/",default:{strategy:{runStrategy:e.RunStrategy.SkipWhenSucceed}},needPlus:!0})],exports.YidunDeployToCDNPlugin),new exports.YidunDeployToCDNPlugin,exports.YidunAccess=class{apiKey="";apiSecret=""},n([e.AccessInput({title:"api_key",component:{placeholder:"api_key"},helper:"http://user.yiduncdn.com/console/index.html#/account/config/api,点击开启后获取",required:!0,encrypt:!0}),i("design:type",Object)],exports.YidunAccess.prototype,"apiKey",void 0),n([e.AccessInput({title:"api_secret",component:{placeholder:"api_secret"},helper:"http://user.yiduncdn.com/console/index.html#/account/config/api,点击开启后获取",required:!0,encrypt:!0}),i("design:type",Object)],exports.YidunAccess.prototype,"apiSecret",void 0),exports.YidunAccess=n([e.IsAccess({name:"yidun",title:"易盾云授权",desc:"user.yiduncdn.com"})],exports.YidunAccess),new exports.YidunAccess,exports.FtpAccess=class{host;port;user;password;secure=!1},n([e.AccessInput({title:"host",component:{placeholder:"ip / 域名",name:"a-input",vModel:"value"},helper:"FTP地址",required:!0}),i("design:type",String)],exports.FtpAccess.prototype,"host",void 0),n([e.AccessInput({title:"host",value:21,component:{placeholder:"21",name:"a-input-number",vModel:"value"},helper:"FTP端口",required:!0}),i("design:type",String)],exports.FtpAccess.prototype,"port",void 0),n([e.AccessInput({title:"user",component:{placeholder:"用户名"},helper:"FTP用户名",required:!0}),i("design:type",String)],exports.FtpAccess.prototype,"user",void 0),n([e.AccessInput({title:"password",component:{placeholder:"密码",component:{name:"a-input-password",vModel:"value"}},encrypt:!0,helper:"FTP密码",required:!0}),i("design:type",String)],exports.FtpAccess.prototype,"password",void 0),n([e.AccessInput({title:"secure",value:!1,component:{name:"a-switch",vModel:"checked"},helper:"是否使用SSL",required:!0}),i("design:type",Boolean)],exports.FtpAccess.prototype,"secure",void 0),exports.FtpAccess=n([e.IsAccess({name:"ftp",title:"FTP授权",desc:""})],exports.FtpAccess),new exports.FtpAccess,exports.UploadCertToFTPPlugin=class extends a{crtPath;keyPath;cert;accessId;async onInstance(){}async execute(){const{cert:e,accessId:s}=this,r=new t.CertReader(e);this.logger.info("将证书写入本地缓存文件");const n=r.saveToFile("crt"),i=r.saveToFile("key");this.logger.info("本地文件写入成功");let p=null;try{const e=await import("basic-ftp");p=new(0,e.Client),p.ftp.verbose=!0,this.logger.info("开始连接FTP");const t=await this.accessService.getById(s);await p.access(t),this.logger.info("FTP连接成功"),await this.doUpload(p,n,this.crtPath),await this.doUpload(p,i,this.keyPath)}finally{p&&p.close(),this.logger.info("删除临时文件"),o.unlinkSync(n),o.unlinkSync(i)}}async doUpload(e,t,s){const o=r.dirname(this.keyPath);this.logger.info(`确保目录存在:${o}`),await e.ensureDir(o),this.logger.info(`开始上传文件${t} -> ${s}`),await e.uploadFrom(t,s)}},n([e.TaskInput({title:"证书保存路径",helper:"需要有写入权限,路径要包含证书文件名,文件名不能用*?!等特殊符号",component:{placeholder:"/test/cert.pem"}}),i("design:type",String)],exports.UploadCertToFTPPlugin.prototype,"crtPath",void 0),n([e.TaskInput({title:"私钥保存路径",helper:"需要有写入权限,路径要包含私钥文件名,文件名不能用*?!等特殊符号",component:{placeholder:"/test/cert.key"}}),i("design:type",String)],exports.UploadCertToFTPPlugin.prototype,"keyPath",void 0),n([e.TaskInput({title:"域名证书",helper:"请选择前置任务输出的域名证书",component:{name:"pi-output-selector"},required:!0}),i("design:type",Object)],exports.UploadCertToFTPPlugin.prototype,"cert",void 0),n([e.TaskInput({title:"FTP授权",component:{name:"pi-access-selector",type:"ftp"},required:!0}),i("design:type",String)],exports.UploadCertToFTPPlugin.prototype,"accessId",void 0),exports.UploadCertToFTPPlugin=n([e.IsTaskPlugin({name:"UploadCertToFTP",title:"上传证书到FTP",group:e.pluginGroups.host.key,desc:"将证书上传到FTP服务器",default:{strategy:{runStrategy:e.RunStrategy.SkipWhenSucceed}},needPlus:!0})],exports.UploadCertToFTPPlugin),new exports.UploadCertToFTPPlugin;
@@ -0,0 +1 @@
1
+ import{AbstractTaskPlugin as e,isPlus as t,TaskInput as o,IsTaskPlugin as s,pluginGroups as i,RunStrategy as r,AccessInput as n,IsAccess as c}from"@certd/pipeline";import{CertReader as a}from"@certd/plugin-cert";import p from"node:crypto";import d from"fs";import l from"node:path";function u(e,t,o,s){var i,r=arguments.length,n=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,o):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)n=Reflect.decorate(e,t,o,s);else for(var c=e.length-1;c>=0;c--)(i=e[c])&&(n=(r<3?i(n):r>3?i(t,o,n):i(t,o))||n);return r>3&&n&&Object.defineProperty(t,o,n),n}function h(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}"function"==typeof SuppressedError&&SuppressedError;class y{access;http;constructor(e,t){this.access=e,this.http=t}getRequestToken(){const e=(new Date).getTime(),t=e+this.getMd5(this.access.apiSecret);return{request_token:this.getMd5(t),request_time:e}}getMd5(e){return p.createHash("md5").update(e).digest("hex")}async doRequest(e,t,o){const s=this.getRequestToken();console.log("token",s);const i={...s,...o};let r=`${this.access.panelUrl}${e}`;t&&(r=`${r}?action=${t}`);const n=await this.http.request({url:r,method:"post",headers:{"Content-Type":"application/x-www-form-urlencoded"},data:i});if(!n.status)throw new Error(n.msg);return n}}class m extends e{setCtx(e){super.setCtx(e),function(){if(!t())throw new Error("此插件仅供专业版中使用")}()}}let g=class extends m{cert;accessId;async onInstance(){}async execute(){const{cert:e,accessId:t}=this,o=new a(e),s=await this.accessService.getById(t),i=this.ctx.http,r=new y(s,i),n=await r.doRequest("/config","SavePanelSSL",{privateKey:o.key,certPem:o.crt});this.logger.info(n?.msg)}};u([o({title:"域名证书",helper:"请选择前置任务输出的域名证书",component:{name:"pi-output-selector"},required:!0}),h("design:type",Object)],g.prototype,"cert",void 0),u([o({title:"宝塔授权",helper:"baota的接口密钥,目前测试宝塔面板本身开启ssl之后,API接口就不能用了",component:{name:"pi-access-selector",type:"baota"},required:!0}),h("design:type",String)],g.prototype,"accessId",void 0),g=u([s({name:"BaotaDeployPanelCert",title:"宝塔面板证书部署",group:i.other.key,desc:"部署宝塔面板本身的ssl证书",default:{strategy:{runStrategy:r.SkipWhenSucceed}},needPlus:!0})],g),new g;let f=class extends m{siteName;isReverseProxy=!1;cert;accessId;async onInstance(){}async execute(){const{cert:e,accessId:t}=this,o=new a(e),s=await this.accessService.getById(t),i=this.ctx.http,r=new y(s,i);if(this.logger.info(`siteName:${this.siteName}`),this.isReverseProxy){const e=await r.doRequest("/mod/proxy/com/set_ssl",null,{site_name:this.siteName,key:o.key,csr:o.crt});this.logger.info(e?.msg)}else{const e=await r.doRequest("/site","SetSSL",{type:0,siteName:this.siteName,key:o.key,csr:o.crt});this.logger.info(e?.msg)}}};u([o({title:"网站域名",component:{name:"a-input"},helper:"登录面板->网站->网站名/域名/项目名称",required:!0}),h("design:type",String)],f.prototype,"siteName",void 0),u([o({title:"是否反向代理",value:!1,component:{name:"a-switch",vModel:"checked"},helper:"该项目类型是反向代理还是其他项目",required:!0}),h("design:type",Object)],f.prototype,"isReverseProxy",void 0),u([o({title:"域名证书",helper:"请选择前置任务输出的域名证书",component:{name:"pi-output-selector"},required:!0}),h("design:type",Object)],f.prototype,"cert",void 0),u([o({title:"宝塔授权",helper:"baota的接口密钥",component:{name:"pi-access-selector",type:"baota"},required:!0}),h("design:type",String)],f.prototype,"accessId",void 0),f=u([s({name:"BaotaDeployWebSiteCert",title:"宝塔网站证书部署",group:i.other.key,desc:"部署宝塔管理的站点的ssl证书",default:{strategy:{runStrategy:r.SkipWhenSucceed}},needPlus:!0})],f),new f;let w=class{panelUrl="";apiSecret=""};u([n({title:"宝塔URL地址",component:{placeholder:"http://192.168.42.237:41896"},helper:"宝塔面板的url地址,例如:http://192.168.42.237:41896",required:!0}),h("design:type",Object)],w.prototype,"panelUrl",void 0),u([n({title:"接口密钥",component:{placeholder:"接口密钥"},helper:"宝塔面板设置->面板设置->API接口->接口配置->接口密钥。\n必须要加IP白名单,你可以先运行一次,报错之后会打印IP,将IP加入白名单之后再次运行即可",required:!0,encrypt:!0}),h("design:type",Object)],w.prototype,"apiSecret",void 0),w=u([c({name:"baota",title:"baota授权",desc:""})],w),new w;let v=class extends m{certId;domain;cert;accessId;async onInstance(){}async execute(){const{domain:e,certId:t,cert:o}=this;if(!e&&!t)throw new Error("证书ID和网站域名必须填写一个");const s=new a(o);t>0?await this.updateByCertId(s,t):await this.updateByDomain(s)}async updateByCertId(e,t){this.logger.info(`更新证书,证书ID:${t}`);const o=`http://user.yiduncdn.com/v1/certs/${t}`;await this.doRequest(o,"PUT",{cert:e.crt,key:e.key})}async doRequest(e,t,o){const s=await this.accessService.getById(this.accessId),{apiKey:i,apiSecret:r}=s,n=this.ctx.http,c=await n.request({url:e,method:t,headers:{"api-key":i,"api-secret":r},data:o});if(0!=c.code)throw new Error(c.msg);return c}async updateByDomain(e){const t=await this.doRequest("http://user.yiduncdn.com/v1/sites","GET",{domain:this.domain});if(0===t.data.length)throw new Error(`未找到域名相关站点:${this.domain}`);let o=null;for(const e of t.data)e.domain===this.domain&&(o=e);if(!o)throw new Error(`未找到域名匹配的站点:${this.domain}`);if(o.https_listen?.cert){const t=o.https_listen.cert;await this.updateByCertId(e,t)}else{this.logger.info(`创建证书,域名:${this.domain}`);const t="http://user.yiduncdn.com/v1/certs",s=this.domain+"_"+(new Date).getTime();await this.doRequest(t,"POST",{name:s,type:"custom",cert:e.crt,key:e.key});const i=(await this.doRequest(t,"GET",{name:s})).data[0].id,r="http://user.yiduncdn.com/v1/sites";await this.doRequest(r,"PUT",{id:o.id,https_listen:{cert:i}})}}};u([o({title:"证书ID",component:{name:"a-input-number",vModel:"value"},helper:"证书ID,在证书管理页面查看,每条记录都有证书id"}),h("design:type",Number)],v.prototype,"certId",void 0),u([o({title:"网站域名",component:{name:"a-input",vModel:"value"},helper:"网站域名和证书ID选填其中一个,填了证书ID,则忽略网站域名"}),h("design:type",Number)],v.prototype,"domain",void 0),u([o({title:"域名证书",helper:"请选择前置任务输出的域名证书",component:{name:"pi-output-selector"},required:!0}),h("design:type",Object)],v.prototype,"cert",void 0),u([o({title:"易盾授权",helper:"易盾CDN授权",component:{name:"pi-access-selector",type:"yidun"},required:!0}),h("design:type",String)],v.prototype,"accessId",void 0),v=u([s({name:"YidunDeployToCDN",title:"部署证书到易盾CDN",group:i.other.key,desc:"http://user.yiduncdn.com/",default:{strategy:{runStrategy:r.SkipWhenSucceed}},needPlus:!0})],v),new v;let S=class{apiKey="";apiSecret=""};u([n({title:"api_key",component:{placeholder:"api_key"},helper:"http://user.yiduncdn.com/console/index.html#/account/config/api,点击开启后获取",required:!0,encrypt:!0}),h("design:type",Object)],S.prototype,"apiKey",void 0),u([n({title:"api_secret",component:{placeholder:"api_secret"},helper:"http://user.yiduncdn.com/console/index.html#/account/config/api,点击开启后获取",required:!0,encrypt:!0}),h("design:type",Object)],S.prototype,"apiSecret",void 0),S=u([c({name:"yidun",title:"易盾云授权",desc:"user.yiduncdn.com"})],S),new S;let P=class{host;port;user;password;secure=!1};u([n({title:"host",component:{placeholder:"ip / 域名",name:"a-input",vModel:"value"},helper:"FTP地址",required:!0}),h("design:type",String)],P.prototype,"host",void 0),u([n({title:"host",value:21,component:{placeholder:"21",name:"a-input-number",vModel:"value"},helper:"FTP端口",required:!0}),h("design:type",String)],P.prototype,"port",void 0),u([n({title:"user",component:{placeholder:"用户名"},helper:"FTP用户名",required:!0}),h("design:type",String)],P.prototype,"user",void 0),u([n({title:"password",component:{placeholder:"密码",component:{name:"a-input-password",vModel:"value"}},encrypt:!0,helper:"FTP密码",required:!0}),h("design:type",String)],P.prototype,"password",void 0),u([n({title:"secure",value:!1,component:{name:"a-switch",vModel:"checked"},helper:"是否使用SSL",required:!0}),h("design:type",Boolean)],P.prototype,"secure",void 0),P=u([c({name:"ftp",title:"FTP授权",desc:""})],P),new P;let I=class extends m{crtPath;keyPath;cert;accessId;async onInstance(){}async execute(){const{cert:e,accessId:t}=this,o=new a(e);this.logger.info("将证书写入本地缓存文件");const s=o.saveToFile("crt"),i=o.saveToFile("key");this.logger.info("本地文件写入成功");let r=null;try{const e=await import("basic-ftp");r=new(0,e.Client),r.ftp.verbose=!0,this.logger.info("开始连接FTP");const o=await this.accessService.getById(t);await r.access(o),this.logger.info("FTP连接成功"),await this.doUpload(r,s,this.crtPath),await this.doUpload(r,i,this.keyPath)}finally{r&&r.close(),this.logger.info("删除临时文件"),d.unlinkSync(s),d.unlinkSync(i)}}async doUpload(e,t,o){const s=l.dirname(this.keyPath);this.logger.info(`确保目录存在:${s}`),await e.ensureDir(s),this.logger.info(`开始上传文件${t} -> ${o}`),await e.uploadFrom(t,o)}};u([o({title:"证书保存路径",helper:"需要有写入权限,路径要包含证书文件名,文件名不能用*?!等特殊符号",component:{placeholder:"/test/cert.pem"}}),h("design:type",String)],I.prototype,"crtPath",void 0),u([o({title:"私钥保存路径",helper:"需要有写入权限,路径要包含私钥文件名,文件名不能用*?!等特殊符号",component:{placeholder:"/test/cert.key"}}),h("design:type",String)],I.prototype,"keyPath",void 0),u([o({title:"域名证书",helper:"请选择前置任务输出的域名证书",component:{name:"pi-output-selector"},required:!0}),h("design:type",Object)],I.prototype,"cert",void 0),u([o({title:"FTP授权",component:{name:"pi-access-selector",type:"ftp"},required:!0}),h("design:type",String)],I.prototype,"accessId",void 0),I=u([s({name:"UploadCertToFTP",title:"上传证书到FTP",group:i.host.key,desc:"将证书上传到FTP服务器",default:{strategy:{runStrategy:r.SkipWhenSucceed}},needPlus:!0})],I),new I;export{w as BaotaAccess,g as BaotaDeployPanelCertPlugin,f as BaotaDeployWebSiteCertPlugin,P as FtpAccess,I as UploadCertToFTPPlugin,S as YidunAccess,v as YidunDeployToCDNPlugin};
@@ -0,0 +1,8 @@
1
+ /**
2
+ * 这个注解将注册一个授权配置
3
+ * 在certd的后台管理系统中,用户可以选择添加此类型的授权
4
+ */
5
+ export declare class BaotaAccess {
6
+ panelUrl: string;
7
+ apiSecret: string;
8
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./plugins/index.js";
2
+ export * from "./access.js";
@@ -0,0 +1,13 @@
1
+ import { AxiosInstance } from "axios";
2
+ import { BaotaAccess } from "../access.js";
3
+ export declare class BaotaClient {
4
+ access: BaotaAccess;
5
+ http: AxiosInstance;
6
+ constructor(access: BaotaAccess, http: AxiosInstance);
7
+ getRequestToken(): {
8
+ request_token: string;
9
+ request_time: number;
10
+ };
11
+ getMd5(content: string): string;
12
+ doRequest(path: string, action: string, data: any): Promise<any>;
13
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./plugin-deploy-to-panel.js";
2
+ export * from "./plugin-deploy-to-web-site.js";
@@ -0,0 +1,8 @@
1
+ import { CertInfo } from "@certd/plugin-cert";
2
+ import { AbstractPlusTaskPlugin } from "../../lib/index.js";
3
+ export declare class BaotaDeployPanelCertPlugin extends AbstractPlusTaskPlugin {
4
+ cert: CertInfo;
5
+ accessId: string;
6
+ onInstance(): Promise<void>;
7
+ execute(): Promise<void>;
8
+ }
@@ -0,0 +1,10 @@
1
+ import { CertInfo } from "@certd/plugin-cert";
2
+ import { AbstractPlusTaskPlugin } from "../../lib/index.js";
3
+ export declare class BaotaDeployWebSiteCertPlugin extends AbstractPlusTaskPlugin {
4
+ siteName: string;
5
+ isReverseProxy: boolean;
6
+ cert: CertInfo;
7
+ accessId: string;
8
+ onInstance(): Promise<void>;
9
+ execute(): Promise<void>;
10
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * 这个注解将注册一个授权配置
3
+ * 在certd的后台管理系统中,用户可以选择添加此类型的授权
4
+ */
5
+ export declare class FtpAccess {
6
+ host: string;
7
+ port: string;
8
+ user: string;
9
+ password: string;
10
+ secure?: boolean;
11
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./access.js";
2
+ export * from "./plugins/index.js";
@@ -0,0 +1 @@
1
+ export * from "./plugin-upload-to-ftp.js";
@@ -0,0 +1,11 @@
1
+ import { CertInfo } from "@certd/plugin-cert";
2
+ import { AbstractPlusTaskPlugin } from "../../lib/index.js";
3
+ export declare class UploadCertToFTPPlugin extends AbstractPlusTaskPlugin {
4
+ crtPath: string;
5
+ keyPath: string;
6
+ cert: CertInfo;
7
+ accessId: string;
8
+ onInstance(): Promise<void>;
9
+ execute(): Promise<void>;
10
+ private doUpload;
11
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./baota/index.js";
2
+ export * from "./yidun/index.js";
3
+ export * from "./ftp/index.js";
@@ -0,0 +1,6 @@
1
+ import { AbstractTaskPlugin, TaskInstanceContext } from "@certd/pipeline";
2
+ export declare function mustPlus(): void;
3
+ export declare abstract class AbstractPlusTaskPlugin extends AbstractTaskPlugin {
4
+ setCtx(ctx: TaskInstanceContext): void;
5
+ abstract execute(): Promise<void>;
6
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * 这个注解将注册一个授权配置
3
+ * 在certd的后台管理系统中,用户可以选择添加此类型的授权
4
+ */
5
+ export declare class YidunAccess {
6
+ apiKey: string;
7
+ apiSecret: string;
8
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./plugins/index.js";
2
+ export * from "./access.js";
@@ -0,0 +1 @@
1
+ export * from "./plugin-deploy-to-cdn.js";
@@ -0,0 +1,13 @@
1
+ import { CertInfo } from "@certd/plugin-cert";
2
+ import { AbstractPlusTaskPlugin } from "../../lib/index.js";
3
+ export declare class YidunDeployToCDNPlugin extends AbstractPlusTaskPlugin {
4
+ certId: number;
5
+ domain: number;
6
+ cert: CertInfo;
7
+ accessId: string;
8
+ onInstance(): Promise<void>;
9
+ execute(): Promise<void>;
10
+ private updateByCertId;
11
+ doRequest(url: string, method: string, data: any): Promise<any>;
12
+ private updateByDomain;
13
+ }
@@ -0,0 +1,96 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+
4
+ // https://gist.github.com/lovasoa/8691344
5
+ async function* walk(dir) {
6
+ for await (const d of await fs.promises.opendir(dir)) {
7
+ const entry = path.join(dir, d.name);
8
+ if (d.isDirectory()) {
9
+ yield* walk(entry);
10
+ } else if (d.isFile()) {
11
+ yield entry;
12
+ }
13
+ }
14
+ }
15
+
16
+ function resolveImportPath(sourceFile, importPath, options) {
17
+ const sourceFileAbs = path.resolve(process.cwd(), sourceFile);
18
+ const root = path.dirname(sourceFileAbs);
19
+ const { moduleFilter = defaultModuleFilter } = options;
20
+
21
+ if (moduleFilter(importPath)) {
22
+ const importPathAbs = path.resolve(root, importPath);
23
+ let possiblePath = [path.resolve(importPathAbs, "./index.ts"), path.resolve(importPathAbs, "./index.js"), importPathAbs + ".ts", importPathAbs + ".js"];
24
+
25
+ if (possiblePath.length) {
26
+ for (let i = 0; i < possiblePath.length; i++) {
27
+ let entry = possiblePath[i];
28
+ if (fs.existsSync(entry)) {
29
+ const resolved = path.relative(root, entry.replace(/\.ts$/, ".js"));
30
+
31
+ if (!resolved.startsWith(".")) {
32
+ return "./" + resolved;
33
+ }
34
+
35
+ return resolved;
36
+ }
37
+ }
38
+ }
39
+ }
40
+
41
+ return null;
42
+ }
43
+
44
+ function replace(filePath, outFilePath, options) {
45
+ const code = fs.readFileSync(filePath).toString();
46
+ const newCode = code.replace(/(import|export) (.+?) from ('[^\n']+'|"[^\n"]+");/gs, function (found, action, imported, from) {
47
+ const importPath = from.slice(1, -1);
48
+ let resolvedPath = resolveImportPath(filePath, importPath, options);
49
+
50
+ if (resolvedPath) {
51
+ resolvedPath = resolvedPath.replaceAll("\\", "/");
52
+ console.log("\t", importPath, resolvedPath);
53
+ return `${action} ${imported} from "${resolvedPath}";`;
54
+ }
55
+
56
+ return found;
57
+ });
58
+
59
+ if (code !== newCode) {
60
+ fs.writeFileSync(outFilePath, newCode);
61
+ }
62
+ }
63
+
64
+ // Then, use it with a simple async for loop
65
+ async function run(srcDir, options = defaultOptions) {
66
+ const { sourceFileFilter = defaultSourceFileFilter } = options;
67
+
68
+ for await (const entry of walk(srcDir)) {
69
+ if (sourceFileFilter(entry)) {
70
+ console.log(entry);
71
+ replace(entry, entry, options);
72
+ }
73
+ }
74
+ }
75
+
76
+ const defaultSourceFileFilter = function (sourceFilePath) {
77
+ return /\.(js|ts)$/.test(sourceFilePath) && !/node_modules/.test(sourceFilePath);
78
+ };
79
+
80
+ const defaultModuleFilter = function (importedModule) {
81
+ return !path.isAbsolute(importedModule) && !importedModule.startsWith("@") && !importedModule.endsWith(".js");
82
+ };
83
+
84
+ const defaultOptions = {
85
+ sourceFileFilter: defaultSourceFileFilter,
86
+ moduleFilter: defaultModuleFilter,
87
+ };
88
+
89
+ // Switch this to test on one file or directly run on a directory.
90
+ const DEBUG = false;
91
+
92
+ if (DEBUG) {
93
+ replace("./src/index.ts", "./out.ts", defaultOptions);
94
+ } else {
95
+ await run("./src/", defaultOptions);
96
+ }
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@certd/plugin-plus",
3
+ "private": false,
4
+ "version": "1.24.0",
5
+ "main": "./dist/bundle.mjs",
6
+ "module": "./dist/bundle.mjs",
7
+ "types": "./dist/d/index.d.ts",
8
+ "type": "module",
9
+ "scripts": {
10
+ "dev": "vite",
11
+ "build": "rollup -c ",
12
+ "build2": "vue-tsc --noEmit && vite build",
13
+ "preview": "vite preview"
14
+ },
15
+ "dependencies": {
16
+ },
17
+ "devDependencies": {
18
+ "@certd/pipeline": "1.24.0",
19
+ "@certd/plugin-cert": "1.24.0",
20
+ "basic-ftp": "^5.0.5",
21
+ "@rollup/plugin-json": "^6.0.0",
22
+ "@rollup/plugin-terser": "^0.4.3",
23
+ "@rollup/plugin-typescript": "^11.0.0",
24
+ "@types/chai": "^4.3.10",
25
+ "@types/mocha": "^10.0.7",
26
+ "@types/node": "20",
27
+ "chai": "4.3.10",
28
+ "dayjs": "^1.11.7",
29
+ "eslint": "^8.41.0",
30
+ "eslint-config-prettier": "^8.8.0",
31
+ "eslint-plugin-import": "^2.27.5",
32
+ "eslint-plugin-node": "^11.1.0",
33
+ "eslint-plugin-prettier": "^4.2.1",
34
+ "mocha": "^10.2.0",
35
+ "rollup": "^3.7.4",
36
+ "ts-node": "^10.9.1",
37
+ "tslib": "^2.5.2",
38
+ "typescript": "^5.0.4"
39
+ },
40
+ "gitHead": "47fe3d5826661f678d081ab53e67c847a3239d88"
41
+ }
@@ -0,0 +1,39 @@
1
+ // const resolve = require("@rollup/plugin-node-resolve");
2
+ // const commonjs = require("@rollup/plugin-commonjs");
3
+ //const Typescript = require("rollup-plugin-typescript2");
4
+ import typescript from "@rollup/plugin-typescript";
5
+ import json from "@rollup/plugin-json";
6
+ import terser from "@rollup/plugin-terser";
7
+ export default {
8
+ input: "src/index.ts",
9
+ output: [
10
+ {
11
+ file: "dist/bundle.mjs",
12
+ format: "es",
13
+ },
14
+ {
15
+ file: "dist/bundle.cjs",
16
+ format: "cjs",
17
+ },
18
+ ],
19
+ plugins: [
20
+ typescript({
21
+ target: "esnext",
22
+ rootDir: "src",
23
+ declaration: true,
24
+ declarationDir: "dist/d",
25
+ exclude: ["./node_modules/**", "./src/**/*.vue", "./src/**/*.spec.ts"],
26
+ allowSyntheticDefaultImports: true,
27
+ }),
28
+ json(),
29
+ terser({
30
+ compress: true,
31
+ mangle: true,
32
+ output: {
33
+ beautify: false,
34
+ comments: false,
35
+ },
36
+ }),
37
+ ],
38
+ external: ["vue", "lodash-es", "dayjs", "log4js", "@midwayjs/core", "@certd/pipeline", "axios", "basic-ftp"],
39
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "compileOnSave": false,
3
+ "compilerOptions": {
4
+ "importHelpers": true,
5
+ "target": "ESNext",
6
+ "module": "ESNext",
7
+ "moduleResolution": "node",
8
+ "esModuleInterop": true,
9
+ "experimentalDecorators": true,
10
+ "emitDecoratorMetadata": true,
11
+ "inlineSourceMap":true,
12
+ "noImplicitThis": true,
13
+ "noUnusedLocals": true,
14
+ "stripInternal": true,
15
+ "skipLibCheck": true,
16
+ "pretty": true,
17
+ "declaration": true,
18
+ "forceConsistentCasingInFileNames": true,
19
+ "typeRoots": [ "./typings", "./node_modules/@types"],
20
+ "outDir": "dist",
21
+ "rootDir": "src",
22
+ "composite": true,
23
+ "useDefineForClassFields": true,
24
+ "strict": false,
25
+ "sourceMap": true,
26
+ "resolveJsonModule": true,
27
+ "isolatedModules": false,
28
+ "lib": ["ESNext", "DOM"],
29
+ },
30
+ "include": [
31
+ "src/**/*.ts",
32
+ "src/**/*.d.ts",
33
+ "src/**/*.js",
34
+ "src/**/*.json"
35
+ ],
36
+ "exclude": [
37
+ "*.ts",
38
+ "*.spec.ts",
39
+ "dist",
40
+ "node_modules",
41
+ "test"
42
+ ],
43
+ }