diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..5989b73 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,41 @@ +name: Build + +on: + - push + - pull_request + +jobs: + build: + strategy: + matrix: + os: ['ubuntu-latest', 'windows-latest'] + node-version: ['20.x'] + + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v4 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: Dependencies + run: npm ci + + - name: Build + run: npm run build + + docker: + needs: build + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Use Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.x' + + - name: Test Docker Build + run: docker build -t myapp . \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..3a7b9cb --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,72 @@ +name: Publish + +on: + push: + tags: + - '*' + +jobs: + check: + runs-on: 'ubuntu-latest' + + steps: + - uses: actions/checkout@v4 + - name: Use Node.js 20.x + uses: actions/setup-node@v4 + with: + node-version: '20.x' + + - name: Dependencies + run: npm ci + + - name: Build + run: npm run build + + docker: + runs-on: 'ubuntu-latest' + needs: check + + steps: + - uses: actions/checkout@v4 + - name: Build and Publish Docker Image + run: | + tag=$(echo ${{ github.ref }} | sed 's/refs\/tags\///') + if [[ $tag == v[0-9]* ]]; then + tag=$(echo $tag | sed 's/v//') + fi + docker build -t ${{ vars.DOCKER_HUB_USERNAME }}/ssl-autoupdater:$tag . + docker login -u ${{ vars.DOCKER_HUB_USERNAME }} -p ${{ secrets.DOCKER_HUB_TOKEN }} + docker push ${{ vars.DOCKER_HUB_USERNAME }}/ssl-autoupdater:$tag + + npm: + runs-on: 'ubuntu-latest' + needs: check + + steps: + - uses: actions/checkout@v4 + - name: Use Node.js 20.x + uses: actions/setup-node@v4 + with: + node-version: '20.x' + registry-url: 'https://registry.npmjs.org/' + + - name: Dependencies + run: npm ci + + - name: Build + run: npm run build + + - name: Publish + run: | + PACKAGE_NAME=$(npm pkg get name) + PACKAGE_NAME=${PACKAGE_NAME//\"/} + VERSION=$(npm pkg get version) + VERSION=${VERSION//\"/} + if npm view ${PACKAGE_NAME}@${VERSION} > /dev/null 2>&1; then + echo "Version ${VERSION} of ${PACKAGE_NAME} already exists, skipping publish" + exit 0 + else + npm publish --access public + fi + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..123db54 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM node:20.11.0 + + +COPY . /app +RUN mkdir -p /app/data +COPY ./config.js /app/data/config.js + +USER root +WORKDIR /app +RUN npm install && npm run build + +ENTRYPOINT [ "npm", "run", "docker" ] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..bbba982 --- /dev/null +++ b/README.md @@ -0,0 +1,86 @@ +# SSL AutoUpdater + +This project is aimed to update SSL certificates (manually uploaded, such as Let's Encrypt) automatically on different server providers (QCloud, Aliyun, Qiniu, etc.). + +- **Supported Providers** + + - [x] 腾讯云 (QCloud) + - [x] 七牛云 (Qiniu) + +## Usage + +Make sure there are certificates on your machine, and this project will upload and update them automatically. + +The default certificate founder is `acme.sh`, you can modify the option `founder` as a function to customize. For further instructions, please refer to the type definition. + +### Node.js + +Install the package + +```shell +npm i -S ssl-autoupdater +``` + +Example: + +```javascript +const autossl = require("ssl-autoupdater") + +const QCloudUpdater = new autossl.updater.QCloud("your secretId", "your secretKey") +QCloudUpdater.watch() // watch and update automatically +``` + +Advanced usage for sending mail: + +```javascript +const mailer = new autossl.MailSender({ + host: "smtp.example.com", + port: 465, + secure: true, + auth: { // authentification for the smtp server + username: "your auth username", + password: "your auth password" + }, + sender: { // set the sender + name: "your name to send", + email: "your email to send" + }, + receiver: ["who@example.com"] // a list of receivers +}) + +const QCloudUpdater = new autossl.updater.QCloud("your secretId", "your secretKey", { + mailer: mailer // when the option `mailer` is set, the updater will send mail once after triggering the event +}) +``` + +More examples can be found in directory `test/`. + +### Docker + +Pull `cnily03/ssl-autoupdater` from Docker Hub + +```shell +docker run -itd \ + -v /path/to/your/config.js:/app/data/config.js \ + -v ~/.acme.sh:/root/.acme.sh \ + --restart=always \ + --name ssl-autoupdater \ + cnily03/ssl-autoupdater +``` + +Replace `/path/to/your/config.js` with your own configuration file. + +Or you can mount the whole directory to `/app/data/` to make it easier to manage. + +Configuration file is similar to the file `config.js` at the root of this repository. + +## References + +- [tencentcloud-sdk-nodejs](https://github.com/TencentCloud/tencentcloud-sdk-nodejs) +- [developer.qiniu.com](https://developer.qiniu.com) + +## License + +CopyRight (c) Cnily03. All rights reserved. + +Licensed under the [MIT](https://github.com/Cnily03/ssl-autoupdater?tab=MIT-1-ov-file) License. diff --git a/config.js b/config.js index 0f291d3..5c99d22 100644 --- a/config.js +++ b/config.js @@ -1,5 +1,6 @@ module.exports = { qcloud: { + enable: false, secretId: "", secretKey: "", forceUploadDays: 15, // 距离证书过期多少天,强制上传证书 @@ -8,6 +9,7 @@ module.exports = { founder: "acme.sh" // 证书查找器(使用内置 acme.sh 查找器) }, qiniu: { + enable: false, accessKey: "", secretKey: "", forceUploadDays: 15, @@ -16,13 +18,14 @@ module.exports = { founder: "acme.sh" }, mailserver: { + enable: false, smtp_host: "smtp.example.com", smtp_port: 465, smtp_secure: true, smtp_username: "notifications@example.com", smtp_password: "password", sender_name: "SSL Updater", - sender_email: "notifications@exaple.com", + sender_email: "notifications@example.com", receiver: ["example@receiver.com"] } } \ No newline at end of file diff --git a/package.json b/package.json index 167b688..5744709 100644 --- a/package.json +++ b/package.json @@ -1,16 +1,26 @@ { "name": "ssl-autoupdater", - "version": "1.0.0", - "description": "", - "main": "index.js", + "version": "0.1.0", + "description": "Automatically update SSL certificate on different cloud platforms", + "main": "dist/index.js", + "types": "dist/index.d.ts", "scripts": { "compile-template": "node compile-template.js", "build": "rm -rf dist/* dist/.[!.]* dist/..?* && tsc && tsc-alias && npm run compile-template", - "test": "npm run build && node test/index.js" + "test": "npm run build && node test/index.js", + "docker": "node test/docker.js" }, - "keywords": [], - "author": "", + "keywords": ["auto", "SSL", "update"], + "author": "Cnily03", + "email": "cnily03@outlook.com", "license": "MIT", + "engines": { + "node": ">=16.13.1" + }, + "repository": "https://github.com/Cnily03/ssl-autoupdater", + "bugs": "https://github.com/Cnily03/ssl-autoupda/issues", + "homepage": "https://github.com/Cnily03/ssl-autoupda#readme", + "changelogs": "https://github.com/Cnily03/ssl-autoupda/releases", "dependencies": { "ansi-html": "^0.0.9", "colors": "^1.4.0", @@ -27,5 +37,10 @@ "ts-loader": "^9.5.1", "tsc-alias": "^1.8.8", "typescript": "^5.3.3" - } + }, + "files": [ + "dist/**/*", + "README.md", + "LICENSE" + ] } \ No newline at end of file diff --git a/test/docker.js b/test/docker.js new file mode 100644 index 0000000..21fd443 --- /dev/null +++ b/test/docker.js @@ -0,0 +1,65 @@ +const path = require("path") +const fs = require("fs") +const autossl = require("../dist") + +const CONF_PATH = "/app/data/config.js" +if (!fs.existsSync(CONF_PATH)) { + console.error("Config file not found at " + CONF_PATH) + process.exit(1) +} +// const CONFIG = require("../config.js") +const CONFIG = require(CONF_PATH) + +const mailOpts = () => ({ + host: CONFIG.mailserver.smtp_host, + port: CONFIG.mailserver.smtp_port, + secure: CONFIG.mailserver.smtp_secure, + auth: { + username: CONFIG.mailserver.smtp_username, + password: CONFIG.mailserver.smtp_password + }, + sender: { + name: CONFIG.mailserver.sender_name, + email: CONFIG.mailserver.sender_email + }, + receiver: CONFIG.mailserver.receiver +}) + +const QCloudBaseOpts = () => ({ + force_upload_days: CONFIG.qcloud.forceUploadDays, + timer_start_time: CONFIG.qcloud.startTime, + timer_interval: CONFIG.qcloud.interval, + founder: CONFIG.qcloud.founder +}) + +const QiniuBaseOpts = () => ({ + force_upload_days: CONFIG.qiniu.forceUploadDays, + timer_start_time: CONFIG.qiniu.startTime, + timer_interval: CONFIG.qiniu.interval, + founder: CONFIG.qiniu.founder +}) + +console.info(CONFIG.mailserver.enable ? + "[Function] Mail server enabled" : + "[Function] Mail server disabled") +console.info(CONFIG.qcloud.enable ? + "[Updater] QCloud enabled" : + "[Updater] QCloud disabled") +console.info(CONFIG.qiniu.enable ? + "[Updater] Qiniu enabled" : + "[Updater] Qiniu disabled") + + +if (CONFIG.qcloud.enable) { + let opts = QCloudBaseOpts() + if (CONFIG.mailserver.enable) opts.mailer = new autossl.MailSender(mailOpts()) + const QCloudUpdater = new autossl.updater.QCloud(CONFIG.qcloud.secretId, CONFIG.qcloud.secretKey, opts) + QCloudUpdater.watch() +} + +if (CONFIG.qiniu.enable) { + let opts = QiniuBaseOpts() + if (CONFIG.mailserver.enable) opts.mailer = new autossl.MailSender(mailOpts()) + const QiniuUpdater = new autossl.updater.Qiniu(CONFIG.qiniu.accessKey, CONFIG.qiniu.secretKey, opts) + QiniuUpdater.watch() +} \ No newline at end of file