From fa0344fb0cdc5d4be5653ed1e367bbee19aeb256 Mon Sep 17 00:00:00 2001 From: leiyun Date: Fri, 16 May 2025 15:54:14 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .babelrc | 8 + .gitignore | 35 ++++ .thinkjsrc | 5 + README.md | 22 +++ nginx.conf | 120 ++++++++++++++ package.json | 30 ++++ pm2.json | 18 ++ src/common/bootstrap/global.js | 12 ++ src/common/bootstrap/middleware.js | 13 ++ src/common/config/config.js | 7 + src/common/config/db.js | 22 +++ src/common/config/env/development.js | 15 ++ src/common/config/env/live.js | 15 ++ src/common/config/env/production.js | 5 + src/common/config/env/testing.js | 5 + src/common/config/error.js | 9 + src/common/config/hook.js | 9 + src/common/config/locale/en.js | 5 + src/common/config/session.js | 20 +++ src/common/config/view.js | 14 ++ src/common/controller/error.js | 77 +++++++++ src/home/config/config.js | 7 + src/home/controller/base.js | 7 + src/home/controller/index.js | 236 +++++++++++++++++++++++++++ src/home/logic/index.js | 15 ++ src/home/model/index.js | 7 + ssl/cert/.keep | 0 ssl/lechallenge/.keep | 0 ssl/letsencrypt/.keep | 0 view/common/error_400.html | 37 +++++ view/common/error_403.html | 37 +++++ view/common/error_404.html | 37 +++++ view/common/error_500.html | 37 +++++ view/common/error_503.html | 37 +++++ view/home/index_index.html | 72 ++++++++ www/README.md | 55 +++++++ www/development.js | 21 +++ www/live.js | 21 +++ www/production.js | 14 ++ www/testing.js | 14 ++ 40 files changed, 1120 insertions(+) create mode 100644 .babelrc create mode 100644 .gitignore create mode 100644 .thinkjsrc create mode 100644 README.md create mode 100644 nginx.conf create mode 100644 package.json create mode 100644 pm2.json create mode 100644 src/common/bootstrap/global.js create mode 100644 src/common/bootstrap/middleware.js create mode 100644 src/common/config/config.js create mode 100644 src/common/config/db.js create mode 100644 src/common/config/env/development.js create mode 100644 src/common/config/env/live.js create mode 100644 src/common/config/env/production.js create mode 100644 src/common/config/env/testing.js create mode 100644 src/common/config/error.js create mode 100644 src/common/config/hook.js create mode 100644 src/common/config/locale/en.js create mode 100644 src/common/config/session.js create mode 100644 src/common/config/view.js create mode 100644 src/common/controller/error.js create mode 100644 src/home/config/config.js create mode 100644 src/home/controller/base.js create mode 100644 src/home/controller/index.js create mode 100644 src/home/logic/index.js create mode 100644 src/home/model/index.js create mode 100644 ssl/cert/.keep create mode 100644 ssl/lechallenge/.keep create mode 100644 ssl/letsencrypt/.keep create mode 100644 view/common/error_400.html create mode 100644 view/common/error_403.html create mode 100644 view/common/error_404.html create mode 100644 view/common/error_500.html create mode 100644 view/common/error_503.html create mode 100644 view/home/index_index.html create mode 100644 www/README.md create mode 100644 www/development.js create mode 100644 www/live.js create mode 100644 www/production.js create mode 100644 www/testing.js diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..4689e9d --- /dev/null +++ b/.babelrc @@ -0,0 +1,8 @@ +{ + "presets": [ + ["es2015", {"loose": true}], + "stage-1" + ], + "plugins": ["transform-runtime"], + "sourceMaps": true +} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d107458 --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage/ + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# node-waf configuration +.lock-wscript + +# Dependency directory +# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git +node_modules/ + +# IDE config +.idea + +# output +output/ +output.tar.gz + +app/ + +runtime/ \ No newline at end of file diff --git a/.thinkjsrc b/.thinkjsrc new file mode 100644 index 0000000..4ffdfd9 --- /dev/null +++ b/.thinkjsrc @@ -0,0 +1,5 @@ +{ + "createAt": "2025-03-25 17:17:46", + "mode": "module", + "es": true +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..ee90448 --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ + +Application created by [ThinkJS](http://www.thinkjs.org) + +## Install dependencies + +``` +npm install +``` + +## Start server + +``` +npm start +``` + +## Deploy with pm2 + +Use pm2 to deploy app on production enviroment. + +``` +pm2 startOrReload pm2.json +``` \ No newline at end of file diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..d25335f --- /dev/null +++ b/nginx.conf @@ -0,0 +1,120 @@ +server { + listen 80; + server_name example.com www.example.com; + root D:\demo\ssl\ssl_manage/www; + set $node_port 8360; + + index index.js index.html index.htm; + if ( -f $request_filename/index.html ){ + rewrite (.*) $1/index.html break; + } + if ( !-f $request_filename ){ + rewrite (.*) /index.js; + } + location = /index.js { + proxy_http_version 1.1; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $http_host; + proxy_set_header X-NginX-Proxy true; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_pass http://127.0.0.1:$node_port$request_uri; + proxy_redirect off; + } + + location = /development.js { + deny all; + } + + location = /testing.js { + deny all; + } + + location = /production.js { + deny all; + } + + location ~ /static/ { + etag on; + expires max; + } +} + + + + +## http/2 nginx conf + +# server { +# listen 80; +# server_name example.com www.example.com; +# rewrite ^(.*) https://example.com$1 permanent; +# } +# +# server { +# listen 443 ssl http2 fastopen=3 reuseport; +# server_name www.thinkjs.org thinkjs.org; +# set $node_port 8360; +# +# root D:\demo\ssl\ssl_manage/www; +# +# keepalive_timeout 70; +# +# ssl_certificate /path/to/certificate; +# ssl_certificate_key /path/to/certificate.key; +# ssl_protocols TLSv1 TLSv1.1 TLSv1.2; +# ssl_ciphers "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"; +# ssl_prefer_server_ciphers on; + +# # openssl dhparam -out dhparams.pem 2048 +# ssl_dhparam /path/to/dhparams.pem; +# +# ssl_session_cache shared:SSL:10m; +# ssl_session_timeout 10m; +# +# ssl_session_ticket_key /path/to/tls_session_ticket.key; +# ssl_session_tickets on; +# +# ssl_stapling on; +# ssl_stapling_verify on; +# ssl_trusted_certificate /path/to/startssl_trust_chain.crt; +# +# +# add_header x-Content-Type-Options nosniff; +# add_header X-Frame-Options deny; +# add_header Strict-Transport-Security "max-age=16070400"; +# +# index index.js index.html index.htm; +# if ( -f $request_filename/index.html ){ +# rewrite (.*) $1/index.html break; +# } +# if ( !-f $request_filename ){ +# rewrite (.*) /index.js; +# } +# location = /index.js { +# proxy_http_version 1.1; +# proxy_set_header X-Real-IP $remote_addr; +# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; +# proxy_set_header Host $http_host; +# proxy_set_header X-NginX-Proxy true; +# proxy_set_header Upgrade $http_upgrade; +# proxy_set_header Connection "upgrade"; +# proxy_pass http://127.0.0.1:$node_port$request_uri; +# proxy_redirect off; +# } +# +# location = /production.js { +# deny all; +# } +# +# location = /testing.js { +# deny all; +# } +# +# location ~ /static/ { +# etag on; +# expires max; +# } +#} + diff --git a/package.json b/package.json new file mode 100644 index 0000000..b601850 --- /dev/null +++ b/package.json @@ -0,0 +1,30 @@ +{ + "name": "thinkjs-application", + "description": "application created by thinkjs", + "version": "1.0.0", + "scripts": { + "start": "node www/development.js", + "compile": "babel src/ --out-dir app/", + "watch-compile": "node -e \"console.log(' no longer need, use command direct.');console.log();\"", + "watch": "npm run watch-compile" + }, + "dependencies": { + "babel-runtime": "6.x.x", + "dayjs": "^1.11.13", + "fs-extra": "^11.3.0", + "greenlock": "^2.8.9", + "greenlock-store-fs": "^3.2.2", + "le-challenge-fs": "^2.0.9", + "source-map-support": "0.4.0", + "thinkjs": "v2" + }, + "devDependencies": { + "babel-cli": "^6.18.0", + "babel-preset-es2015": "^6.18.0", + "babel-preset-stage-1": "^6.16.0", + "babel-plugin-transform-runtime": "^6.15.0", + "babel-core": "^6.20.0" + }, + "repository": "", + "license": "MIT" +} diff --git a/pm2.json b/pm2.json new file mode 100644 index 0000000..6749098 --- /dev/null +++ b/pm2.json @@ -0,0 +1,18 @@ +{ + "apps": [ + { + "name": "ssl", + "script": "www/live.js", + "cwd": "/home/program/front/git/ssl_manage", + "exec_mode": "cluster", + "instances": 1, + "max_memory_restart": "2G", + "autorestart": true, + "node_args": [], + "args": [], + "env": {}, + "error_file": "/data/pm2/logs/ssl-err.log", + "out_file": "/data/pm2/logs/ssl-out.log" + } + ] +} diff --git a/src/common/bootstrap/global.js b/src/common/bootstrap/global.js new file mode 100644 index 0000000..ffc7bb5 --- /dev/null +++ b/src/common/bootstrap/global.js @@ -0,0 +1,12 @@ +/** + * this file will be loaded before server started + * you can define global functions used in controllers, models, templates + */ + +/** + * use global.xxx to define global functions + * + * global.fn1 = function(){ + * + * } + */ \ No newline at end of file diff --git a/src/common/bootstrap/middleware.js b/src/common/bootstrap/middleware.js new file mode 100644 index 0000000..88ab294 --- /dev/null +++ b/src/common/bootstrap/middleware.js @@ -0,0 +1,13 @@ +/** + * this file will be loaded before server started + * you can register middleware + * https://thinkjs.org/doc/middleware.html + */ + +/** + * + * think.middleware('xxx', http => { + * + * }) + * + */ diff --git a/src/common/config/config.js b/src/common/config/config.js new file mode 100644 index 0000000..6b90992 --- /dev/null +++ b/src/common/config/config.js @@ -0,0 +1,7 @@ +'use strict'; +/** + * config + */ +export default { + //key: value +}; \ No newline at end of file diff --git a/src/common/config/db.js b/src/common/config/db.js new file mode 100644 index 0000000..92243af --- /dev/null +++ b/src/common/config/db.js @@ -0,0 +1,22 @@ +'use strict'; +/** + * db config + * @type {Object} + */ +export default { + type: 'mysql', + adapter: { + mysql: { + host: '127.0.0.1', + port: '', + database: '', + user: '', + password: '', + prefix: '', + encoding: 'utf8' + }, + mongo: { + + } + } +}; \ No newline at end of file diff --git a/src/common/config/env/development.js b/src/common/config/env/development.js new file mode 100644 index 0000000..8499247 --- /dev/null +++ b/src/common/config/env/development.js @@ -0,0 +1,15 @@ +'use strict'; + +export default { + domains:[ + // "oa.live.educlouddata.com", + // "m.live.educlouddata.com", + // "yun.live.educlouddata.com", + // "yunh5.live.educlouddata.com", + // "kms.live.educlouddata.com", + // "ams.live.educlouddata.com", + // "data.live.educlouddata.com", + "live.qqsrx.top", + ], + CERT_DIR:"/usr/local/nginx/conf/cert" +}; \ No newline at end of file diff --git a/src/common/config/env/live.js b/src/common/config/env/live.js new file mode 100644 index 0000000..8499247 --- /dev/null +++ b/src/common/config/env/live.js @@ -0,0 +1,15 @@ +'use strict'; + +export default { + domains:[ + // "oa.live.educlouddata.com", + // "m.live.educlouddata.com", + // "yun.live.educlouddata.com", + // "yunh5.live.educlouddata.com", + // "kms.live.educlouddata.com", + // "ams.live.educlouddata.com", + // "data.live.educlouddata.com", + "live.qqsrx.top", + ], + CERT_DIR:"/usr/local/nginx/conf/cert" +}; \ No newline at end of file diff --git a/src/common/config/env/production.js b/src/common/config/env/production.js new file mode 100644 index 0000000..2f0c401 --- /dev/null +++ b/src/common/config/env/production.js @@ -0,0 +1,5 @@ +'use strict'; + +export default { + resource_on: false +}; \ No newline at end of file diff --git a/src/common/config/env/testing.js b/src/common/config/env/testing.js new file mode 100644 index 0000000..79370c0 --- /dev/null +++ b/src/common/config/env/testing.js @@ -0,0 +1,5 @@ +'use strict'; + +export default { + +}; \ No newline at end of file diff --git a/src/common/config/error.js b/src/common/config/error.js new file mode 100644 index 0000000..5ad3dc6 --- /dev/null +++ b/src/common/config/error.js @@ -0,0 +1,9 @@ +'use strict'; +/** + * err config + */ +export default { + //key: value + key: 'errno', //error number + msg: 'errmsg' //error message +}; \ No newline at end of file diff --git a/src/common/config/hook.js b/src/common/config/hook.js new file mode 100644 index 0000000..aad6b37 --- /dev/null +++ b/src/common/config/hook.js @@ -0,0 +1,9 @@ +'use strict'; + +/** + * hook config + * https://thinkjs.org/doc/middleware.html#toc-df6 + */ +export default { + +} \ No newline at end of file diff --git a/src/common/config/locale/en.js b/src/common/config/locale/en.js new file mode 100644 index 0000000..79370c0 --- /dev/null +++ b/src/common/config/locale/en.js @@ -0,0 +1,5 @@ +'use strict'; + +export default { + +}; \ No newline at end of file diff --git a/src/common/config/session.js b/src/common/config/session.js new file mode 100644 index 0000000..d6702e4 --- /dev/null +++ b/src/common/config/session.js @@ -0,0 +1,20 @@ +'use strict'; + +/** + * session configs + */ +export default { + name: 'thinkjs', + type: 'file', + secret: 'VH7!OBT^', + timeout: 24 * 3600, + cookie: { // cookie options + length: 32, + httponly: true + }, + adapter: { + file: { + path: think.RUNTIME_PATH + '/session', + } + } +}; \ No newline at end of file diff --git a/src/common/config/view.js b/src/common/config/view.js new file mode 100644 index 0000000..e18753b --- /dev/null +++ b/src/common/config/view.js @@ -0,0 +1,14 @@ +'use strict'; +/** + * template config + */ +export default { + type: 'ejs', + content_type: 'text/html', + file_ext: '.html', + file_depr: '_', + root_path: think.ROOT_PATH + '/view', + adapter: { + ejs: {} + } +}; \ No newline at end of file diff --git a/src/common/controller/error.js b/src/common/controller/error.js new file mode 100644 index 0000000..66ed454 --- /dev/null +++ b/src/common/controller/error.js @@ -0,0 +1,77 @@ +'use strict'; +/** + * error controller + */ +export default class extends think.controller.base { + /** + * display error page + * @param {Number} status [] + * @return {Promise} [] + */ + displayError(status){ + + //hide error message on production env + if(think.env === 'production'){ + this.http.error = null; + } + + let errorConfig = this.config('error'); + let message = this.http.error && this.http.error.message || ''; + if(this.isJsonp()){ + return this.jsonp({ + [errorConfig.key]: status, + [errorConfig.msg]: message + }) + }else if(this.isAjax()){ + return this.fail(status, message); + } + + let module = 'common'; + if(think.mode !== think.mode_module){ + module = this.config('default_module'); + } + let file = `${module}/error/${status}.html`; + let options = this.config('tpl'); + options = think.extend({}, options, {type: 'base', file_depr: '_'}); + this.fetch(file, {}, options).then(content => { + content = content.replace('ERROR_MESSAGE', message); + this.type(options.content_type); + this.end(content); + }); + } + /** + * Bad Request + * @return {Promise} [] + */ + _400Action(){ + return this.displayError(400); + } + /** + * Forbidden + * @return {Promise} [] + */ + _403Action(){ + return this.displayError(403); + } + /** + * Not Found + * @return {Promise} [] + */ + _404Action(){ + return this.displayError(404); + } + /** + * Internal Server Error + * @return {Promise} [] + */ + _500Action(){ + return this.displayError(500); + } + /** + * Service Unavailable + * @return {Promise} [] + */ + _503Action(){ + return this.displayError(503); + } +} \ No newline at end of file diff --git a/src/home/config/config.js b/src/home/config/config.js new file mode 100644 index 0000000..6b90992 --- /dev/null +++ b/src/home/config/config.js @@ -0,0 +1,7 @@ +'use strict'; +/** + * config + */ +export default { + //key: value +}; \ No newline at end of file diff --git a/src/home/controller/base.js b/src/home/controller/base.js new file mode 100644 index 0000000..1c45bd9 --- /dev/null +++ b/src/home/controller/base.js @@ -0,0 +1,7 @@ +'use strict'; + +export default class extends think.controller.base { + /** + * some base method in here + */ +} \ No newline at end of file diff --git a/src/home/controller/index.js b/src/home/controller/index.js new file mode 100644 index 0000000..9c33f22 --- /dev/null +++ b/src/home/controller/index.js @@ -0,0 +1,236 @@ +'use strict'; + +import Base from './base.js'; + +const Greenlock = require('greenlock'); +const path = require('path'); +const GreenlockStoreFs = require('greenlock-store-fs'); +const LeChallengeFs = require('le-challenge-fs'); +const fs = require('fs-extra'); +const { execSync } = require('child_process'); +const https = require('https'); +const dayjs = require('dayjs'); // 需安装dayjs库 + + +// SSL根目录 +const ROOT_PATH = path.join(think.ROOT_PATH, 'ssl'); +const PEM_PATH = path.join(ROOT_PATH, 'cert'); +// 创建存储对象 +const leStore = GreenlockStoreFs.create({ + configDir: path.join(ROOT_PATH, 'letsencrypt'), +}); +// 创建验证对象 +const leHttpChallenge = LeChallengeFs.create({ + webrootPath: path.join(ROOT_PATH, 'lechallenge'), +}); +// 是否同意协议 +function leAgree (opts, agreeCb) { + agreeCb(null, opts.tosUrl); +} + +// 证书申请对象 +const greenlock = Greenlock.create({ + version: 'draft-12', + // 测试环境 + server: 'https://acme-staging-v02.api.letsencrypt.org/directory', + // 生产环境 + // server: 'https://acme-v02.api.letsencrypt.org/directory', + store: leStore, + challenges: { + 'http-01': leHttpChallenge, + }, + challengeType: 'http-01', + agreeToTerms: leAgree, + debug: true, + renewBy: 10 * 24 * 60 * 60 * 1000,// 10倒计时开始续期 +}); + + +// 创建SSL证书申请请求 +async function CreateSSL (domain, email = '') { + const results = await greenlock.register({ + domains: [domain], + email, + agreeTos: true, + rsaKeySize: 2048, + }); + // 如果生成证书就保存一次证书 + const dir = path.join(PEM_PATH, domain); + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir); + } + if (results.cert && results.chain) { + fs.writeFileSync(path.join(dir, `${domain}.crt`), results.cert + results.chain, 'utf-8'); + console.log(`证书${domain}.crt创建成功!`); + } + if (results.privkey) { + fs.writeFileSync(path.join(dir, `${domain}.key`), results.privkey, 'utf-8'); + console.log(`证书${domain}.key创建成功!`); + } + return results; +} + + +/** + * 检查证书过期时间 + * @param {*} domain + * @returns + */ +function checkCertExpiry (domain) { + return new Promise((resolve, reject) => { + const req = https.request({ + hostname: domain, + port: 443, + method: 'GET', + agent: new https.Agent({ rejectUnauthorized: false }) // 避免自签名证书报错 + }, (res) => { + const cert = res.socket.getPeerCertificate(); + if (cert.valid_to) { + resolve(cert.valid_to); + } else { + reject(new Error('证书信息缺失')); + } + }); + + req.on('error', (err) => reject(err)); + req.end(); + }); +} + +/** + * + * @param {*} domain + * @returns + */ +async function getRemainingDays (domain) { + try { + const validTo = await checkCertExpiry(domain); + const expiryDate = dayjs(validTo, 'MMM DD HH:mm:ss YYYY GMT'); // 解析时间格式 + const currentDate = dayjs(); + const daysLeft = expiryDate.diff(currentDate, 'day'); + return daysLeft; + } catch (err) { + console.error(`检测失败:${err.message}`); + return -1; // 错误时返回-1 + } +} + + + + +export default class extends Base { + /** + * index action + * @return {Promise} [] + */ + async indexAction () { + let domains = this.config().domains; + let msgs = [] + for (let domain of domains) { + try { + const daysLeft = await getRemainingDays(domain); + const msg = `证书${domain},剩余${daysLeft}天` + console.log(msg); + msgs.push(msg); + } catch (e) { + const msg = `证书${domain},证书缺失或无法访问` + console.log(e); + msgs.push(msg); + } + } + this.assign({ + msgs: msgs.join('\n') + }); + return this.display(); + } + + /** + * 检查并更新证书 + */ + async checksslAction () { + let domains = this.config().domains; + let updateList = []; //需要更新的数据 + for (let domain of domains) { + try { + const daysLeft = await getRemainingDays(domain); + const msg = `证书${domain},剩余${daysLeft}天`; + console.log(msg); + if (daysLeft < 90) { + updateList.push(domain); + } + } catch (e) { + console.log("==".repeat(20)) + console.log('检查证书失败:', e); + console.log("==".repeat(20)) + } + } + if (updateList.length) { + console.log("==".repeat(20), "开始生成证书", "==".repeat(20)); + console.log('开始时间:', dayjs().format('YYYY-MM-DD HH:mm:ss')); + for (let domain of updateList) { + try { + const results = await CreateSSL(domain); + console.log(`证书${domain},生成成功`); + } catch (error) { + console.log("==".repeat(20), "证书生成失败", "==".repeat(20)); + console.log("域名:", domain); + console.log(e); + console.log("==".repeat(20), "证书生成失败", "==".repeat(20)); + } + } + await this.deployCert(updateList); + console.log(`更新证书数量:${updateList.length}`); + console.log('结束时间:', dayjs().format('YYYY-MM-DD HH:mm:ss')); + console.log("==".repeat(20), "结束生成证书", "==".repeat(20)); + } + this.success(); + } + + async createAction () { + const domain = this.post('domain'); + const email = this.post('email'); + if (!domain || !email) { + return this.fail('参数错误'); + } + try { + const results = await CreateSSL(domain, email); + this.deployCert([domain]); + return this.success(results); + } catch (error) { + return this.fail(JSON.stringify(error)); + } + } + + /** + * 复制证书到指定文件夹,并重启nginx + * @param {*} domains + * @returns + */ + async deployCert (domains) { + if (!domains || domains.length === 0) { + return; + } + try { + const dir2 = this.config().CERT_DIR; //nginx配置文件中 + // 1. 复制证书 + for (let domain of domains) { + const dir = path.join(PEM_PATH, domain); //生成的证书地址,项目中 + let originCrt = `${dir}/${domain}.crt`; + let originKey = `${dir}/${domain}.key`; + if (fs.existsSync(originCrt) && fs.existsSync(originKey)) { + await fs.copy(`${dir}/${domain}.crt`, `${dir2}/${domain}.crt`); + await fs.copy(`${dir}/${domain}.key`, `${dir2}/${domain}.key`); + } + } + + // 2. 检查配置 + execSync('nginx -t'); + + // 3. 重载服务 + execSync('nginx -s reload'); + console.log('证书部署成功!'); + } catch (error) { + console.error('部署失败:', error.message); + } + } +} \ No newline at end of file diff --git a/src/home/logic/index.js b/src/home/logic/index.js new file mode 100644 index 0000000..f1b7c98 --- /dev/null +++ b/src/home/logic/index.js @@ -0,0 +1,15 @@ +'use strict'; +/** + * logic + * @param {} [] + * @return {} [] + */ +export default class extends think.logic.base { + /** + * index action logic + * @return {} [] + */ + indexAction(){ + + } +} \ No newline at end of file diff --git a/src/home/model/index.js b/src/home/model/index.js new file mode 100644 index 0000000..64ea068 --- /dev/null +++ b/src/home/model/index.js @@ -0,0 +1,7 @@ +'use strict'; +/** + * model + */ +export default class extends think.model.base { + +} \ No newline at end of file diff --git a/ssl/cert/.keep b/ssl/cert/.keep new file mode 100644 index 0000000..e69de29 diff --git a/ssl/lechallenge/.keep b/ssl/lechallenge/.keep new file mode 100644 index 0000000..e69de29 diff --git a/ssl/letsencrypt/.keep b/ssl/letsencrypt/.keep new file mode 100644 index 0000000..e69de29 diff --git a/view/common/error_400.html b/view/common/error_400.html new file mode 100644 index 0000000..3e26b0c --- /dev/null +++ b/view/common/error_400.html @@ -0,0 +1,37 @@ + + + +Bad Request - ThinkJS + + + + +
+
+

Bad Request

+
ERROR_MESSAGE
+
+ + diff --git a/view/common/error_403.html b/view/common/error_403.html new file mode 100644 index 0000000..2824b21 --- /dev/null +++ b/view/common/error_403.html @@ -0,0 +1,37 @@ + + + +Forbidden - ThinkJS + + + + +
+
+

Forbidden

+
ERROR_MESSAGE
+
+ + diff --git a/view/common/error_404.html b/view/common/error_404.html new file mode 100644 index 0000000..4f3e432 --- /dev/null +++ b/view/common/error_404.html @@ -0,0 +1,37 @@ + + + +Not Found - ThinkJS + + + + +
+
+

Not Found

+
ERROR_MESSAGE
+
+ + diff --git a/view/common/error_500.html b/view/common/error_500.html new file mode 100644 index 0000000..9ea0b52 --- /dev/null +++ b/view/common/error_500.html @@ -0,0 +1,37 @@ + + + +Internal Server Error - ThinkJS + + + + +
+
+

Internal Server Error

+
ERROR_MESSAGE
+
+ + diff --git a/view/common/error_503.html b/view/common/error_503.html new file mode 100644 index 0000000..478727c --- /dev/null +++ b/view/common/error_503.html @@ -0,0 +1,37 @@ + + + +Service Unavailable - ThinkJS + + + + +
+
+

Service Unavailable

+
ERROR_MESSAGE
+
+ + diff --git a/view/home/index_index.html b/view/home/index_index.html new file mode 100644 index 0000000..7e0d2a1 --- /dev/null +++ b/view/home/index_index.html @@ -0,0 +1,72 @@ + + + + + + New ThinkJS Application + + + + +
+
+

证书自动更新系统

+
+
+
+
+ <%= msgs %> +
+
+ + + \ No newline at end of file diff --git a/www/README.md b/www/README.md new file mode 100644 index 0000000..dfa9125 --- /dev/null +++ b/www/README.md @@ -0,0 +1,55 @@ +## application + +### start server + +*development* + +```js +node www/development.js +``` + +*testing* + +```js +node www/testing.js +``` + +*production* + +```js +node www/production.js +``` + +or use pm2 to manage node: + +``` +pm2 start www/production.js +``` + +### compile es6 code + +``` +npm run compile +``` + +### how to link resource + +*in template file* + +```html + + + + + + + +``` + +*link image in css* + +```css +.a{ + background: url(../img/a.png) no-repeat; +} +``` diff --git a/www/development.js b/www/development.js new file mode 100644 index 0000000..760053d --- /dev/null +++ b/www/development.js @@ -0,0 +1,21 @@ +var thinkjs = require('thinkjs'); +var path = require('path'); + +var rootPath = path.dirname(__dirname); + +var instance = new thinkjs({ + APP_PATH: rootPath + path.sep + 'app', + RUNTIME_PATH: rootPath + path.sep + 'runtime', + ROOT_PATH: rootPath, + RESOURCE_PATH: __dirname, + env: 'development' +}); + +// Build code from src to app directory. +instance.compile({ + log: true, + presets: [], + plugins: [] +}); + +instance.run(); diff --git a/www/live.js b/www/live.js new file mode 100644 index 0000000..da02586 --- /dev/null +++ b/www/live.js @@ -0,0 +1,21 @@ +var thinkjs = require('thinkjs'); +var path = require('path'); + +var rootPath = path.dirname(__dirname); + +var instance = new thinkjs({ + APP_PATH: rootPath + path.sep + 'app', + RUNTIME_PATH: rootPath + path.sep + 'runtime', + ROOT_PATH: rootPath, + RESOURCE_PATH: __dirname, + env: 'live' +}); + +// Build code from src to app directory. +instance.compile({ + log: true, + presets: [], + plugins: [] +}); + +instance.run(); diff --git a/www/production.js b/www/production.js new file mode 100644 index 0000000..71d1703 --- /dev/null +++ b/www/production.js @@ -0,0 +1,14 @@ +var thinkjs = require('thinkjs'); +var path = require('path'); + +var rootPath = path.dirname(__dirname); + +var instance = new thinkjs({ + APP_PATH: rootPath + path.sep + 'app', + RUNTIME_PATH: rootPath + path.sep + 'runtime', + ROOT_PATH: rootPath, + RESOURCE_PATH: __dirname, + env: 'production' +}); + +instance.run(true); diff --git a/www/testing.js b/www/testing.js new file mode 100644 index 0000000..6b5cac1 --- /dev/null +++ b/www/testing.js @@ -0,0 +1,14 @@ +var thinkjs = require('thinkjs'); +var path = require('path'); + +var rootPath = path.dirname(__dirname); + +var instance = new thinkjs({ + APP_PATH: rootPath + path.sep + 'app', + RUNTIME_PATH: rootPath + path.sep + 'runtime', + ROOT_PATH: rootPath, + RESOURCE_PATH: __dirname, + env: 'testing' +}); + +instance.run(); \ No newline at end of file