|
@@ -0,0 +1,101 @@
|
|
|
+import { App, Config, Inject, Provide } from '@midwayjs/core';
|
|
|
+import { Application } from '@midwayjs/koa';
|
|
|
+import * as crypto from 'crypto';
|
|
|
+import * as path from 'path';
|
|
|
+import * as fs from 'fs';
|
|
|
+import { ProxyService } from './proxy.service';
|
|
|
+import { RequestBase } from '../interface/proxy.interface';
|
|
|
+import * as CryptoJS from 'crypto-js';
|
|
|
+import { get, isObject } from 'lodash';
|
|
|
+import * as NodeRSA from 'node-rsa';
|
|
|
+@Provide()
|
|
|
+export class PemService {
|
|
|
+ // pemDir = `${process.pwd()}`;
|
|
|
+ @App()
|
|
|
+ app: Application;
|
|
|
+ /**证书目录 */
|
|
|
+ certsDir = 'certs';
|
|
|
+ pemPublicName = 'public.pem';
|
|
|
+ pemPrivateName = 'private.pem';
|
|
|
+
|
|
|
+ @Config('jwt.secret')
|
|
|
+ jwtSecret: string;
|
|
|
+ @Inject()
|
|
|
+ proxyService: ProxyService;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据请求头,获取真实使用加密数据的字符串
|
|
|
+ * @returns {string} 真实使用加密数据的字符串
|
|
|
+ */
|
|
|
+ decryptRequestCode() {
|
|
|
+ const rb: RequestBase = this.proxyService.getRequstBase();
|
|
|
+ // 获取加密字符串
|
|
|
+ const enReqCode = get(rb, 'header.api-token');
|
|
|
+ // 使用RSA解密 加密字符串, 获得真实使用的加密字符串
|
|
|
+ const appPath = this.app.getAppDir();
|
|
|
+ const certsDirPath = path.resolve(appPath, this.certsDir);
|
|
|
+ const privatePath = path.resolve(certsDirPath, this.pemPrivateName);
|
|
|
+ const privateKey = fs.readFileSync(privatePath, { encoding: 'utf8' });
|
|
|
+ // 解密
|
|
|
+ const decrypt = new NodeRSA(privateKey, 'pkcs8-private-pem');
|
|
|
+ // 与前端加密保持一致
|
|
|
+ decrypt.setOptions({ encryptionScheme: 'pkcs1' });
|
|
|
+ const res = decrypt.decrypt(enReqCode, 'utf8');
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 加密: 用于请求返回给来源时
|
|
|
+ * @param data 需要加密的数据
|
|
|
+ */
|
|
|
+ encrypt(data: object | string) {
|
|
|
+ const code = this.decryptRequestCode();
|
|
|
+ if (!code) throw new Error('加密字符串解析错误');
|
|
|
+ let strData = data;
|
|
|
+ if (isObject(strData)) strData = JSON.stringify(data);
|
|
|
+ const ivStr = code.substring(0, 16);
|
|
|
+ const key = CryptoJS.enc.Utf8.parse(code);
|
|
|
+ const iv = CryptoJS.enc.Utf8.parse(ivStr);
|
|
|
+ const srcs = CryptoJS.enc.Utf8.parse(strData);
|
|
|
+ const encrypted = CryptoJS.AES.encrypt(srcs, key, {
|
|
|
+ iv,
|
|
|
+ mode: CryptoJS.mode.CBC,
|
|
|
+ padding: CryptoJS.pad.Pkcs7,
|
|
|
+ });
|
|
|
+ return encrypted.toString();
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 解密:用于请求代理前
|
|
|
+ * @param data body数据
|
|
|
+ */
|
|
|
+ decrypt(data: string) {
|
|
|
+ const code = this.decryptRequestCode();
|
|
|
+ if (!code) throw new Error('加密字符串解析错误');
|
|
|
+ const ivStr = code.substring(0, 16);
|
|
|
+ const key = CryptoJS.enc.Utf8.parse(code);
|
|
|
+ const iv = CryptoJS.enc.Utf8.parse(ivStr);
|
|
|
+ const decrypt = CryptoJS.AES.decrypt(data, key, {
|
|
|
+ iv,
|
|
|
+ mode: CryptoJS.mode.CBC,
|
|
|
+ padding: CryptoJS.pad.Pkcs7,
|
|
|
+ });
|
|
|
+ return decrypt.toString(CryptoJS.enc.Utf8);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**生成证书 */
|
|
|
+ createKeys() {
|
|
|
+ const key = new NodeRSA({ b: 512 });
|
|
|
+ key.setOptions({ encryptionScheme: 'pkcs1' });
|
|
|
+ //制定输出格式
|
|
|
+ const publicKey = key.exportKey('pkcs8-public-pem');
|
|
|
+ const privateKey = key.exportKey('pkcs8-private-pem');
|
|
|
+ // 获取项目路径,生成certs文件夹
|
|
|
+ const appPath = this.app.getAppDir();
|
|
|
+ const certsDirPath = path.resolve(appPath, this.certsDir);
|
|
|
+ const is_exists = fs.existsSync(certsDirPath);
|
|
|
+ if (!is_exists) fs.mkdirSync(certsDirPath);
|
|
|
+ const publicPath = path.resolve(certsDirPath, this.pemPublicName);
|
|
|
+ fs.writeFileSync(publicPath, publicKey, { encoding: 'utf8' });
|
|
|
+ const privatePath = path.resolve(certsDirPath, this.pemPrivateName);
|
|
|
+ fs.writeFileSync(privatePath, privateKey, { encoding: 'utf8' });
|
|
|
+ }
|
|
|
+}
|