mirror of
https://github.com/certd/certd.git
synced 2026-04-23 11:37:23 +08:00
feat: 支持open api接口,根据域名获取证书
This commit is contained in:
@@ -1,5 +0,0 @@
|
||||
export * from "./entity/site-info.js";
|
||||
export * from "./entity/cert-info.js";
|
||||
|
||||
export * from "./service/cert-info-service.js";
|
||||
export * from "./service/site-info-service.js";
|
||||
@@ -1,8 +1,10 @@
|
||||
import { Provide } from '@midwayjs/core';
|
||||
import { BaseService, PageReq } from '@certd/lib-server';
|
||||
import { BaseService, CodeException, Constants, PageReq } from '@certd/lib-server';
|
||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { CertInfoEntity } from '../entity/cert-info.js';
|
||||
import { utils } from '@certd/basic';
|
||||
import { CertInfo, CertReader } from '@certd/plugin-cert';
|
||||
|
||||
@Provide()
|
||||
export class CertInfoService extends BaseService<CertInfoEntity> {
|
||||
@@ -68,4 +70,25 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
|
||||
pipelineId: id,
|
||||
});
|
||||
}
|
||||
|
||||
async getCertInfo(param: { domains: string[]; userId: number }) {
|
||||
const { domains, userId } = param;
|
||||
|
||||
const list = await this.find({
|
||||
where: {
|
||||
userId,
|
||||
},
|
||||
});
|
||||
//遍历查找
|
||||
const matched = list.find(item => {
|
||||
const itemDomains = item.domains.split(',');
|
||||
return utils.domain.match(domains, itemDomains);
|
||||
});
|
||||
if (!matched || !matched.certInfo) {
|
||||
throw new CodeException(Constants.res.openCertNotFound);
|
||||
}
|
||||
const certInfo = JSON.parse(matched.certInfo) as CertInfo;
|
||||
const certReader = new CertReader(certInfo);
|
||||
return certReader.toCertInfo();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
|
||||
|
||||
@Entity('cd_open_key')
|
||||
export class OpenKeyEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'user_id', comment: '用户id', unique: true })
|
||||
userId: number;
|
||||
|
||||
@Column({ name: 'key_id', comment: 'keyId', unique: true })
|
||||
keyId: string;
|
||||
|
||||
@Column({ name: 'key_secret', comment: 'keySecret', unique: true })
|
||||
keySecret: string;
|
||||
|
||||
@Column({ name: 'create_time', comment: '创建时间', default: () => 'CURRENT_TIMESTAMP' })
|
||||
createTime: Date;
|
||||
|
||||
@Column({ name: 'update_time', comment: '修改时间', default: () => 'CURRENT_TIMESTAMP' })
|
||||
updateTime: Date;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
import { Provide } from '@midwayjs/core';
|
||||
import { BaseService, Constants, CodeException, PageReq } from '@certd/lib-server';
|
||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { OpenKeyEntity } from '../entity/open-key.js';
|
||||
import { utils } from '@certd/basic';
|
||||
import crypto from 'crypto';
|
||||
|
||||
export type OpenKey = {
|
||||
userId: number;
|
||||
keyId: string;
|
||||
keySecret: string;
|
||||
encrypt: boolean;
|
||||
};
|
||||
@Provide()
|
||||
export class OpenKeyService extends BaseService<OpenKeyEntity> {
|
||||
@InjectEntityModel(OpenKeyEntity)
|
||||
repository: Repository<OpenKeyEntity>;
|
||||
|
||||
//@ts-ignore
|
||||
getRepository() {
|
||||
return this.repository;
|
||||
}
|
||||
|
||||
async page(pageReq: PageReq<OpenKeyEntity>) {
|
||||
return await super.page(pageReq);
|
||||
}
|
||||
|
||||
async getKey(userId: number) {
|
||||
let entity = await this.getByUserId(userId);
|
||||
if (entity) {
|
||||
return {
|
||||
keyId: entity.keyId,
|
||||
keySecret: entity.keySecret,
|
||||
};
|
||||
}
|
||||
const keyId = utils.id.simpleNanoId(12) + '_key';
|
||||
const secretKey = crypto.randomBytes(32);
|
||||
const keySecret = secretKey.toString('base64');
|
||||
entity = new OpenKeyEntity();
|
||||
entity.userId = userId;
|
||||
entity.keyId = keyId;
|
||||
entity.keySecret = keySecret;
|
||||
await this.repository.save(entity);
|
||||
return {
|
||||
keyId: entity.keyId,
|
||||
keySecret: entity.keySecret,
|
||||
};
|
||||
}
|
||||
|
||||
private getByUserId(userId: number) {
|
||||
return this.repository.findOne({ where: { userId } });
|
||||
}
|
||||
|
||||
async getByKeyId(keyId: string) {
|
||||
return this.repository.findOne({ where: { keyId } });
|
||||
}
|
||||
|
||||
async verifyOpenKey(openKey: string): Promise<OpenKey> {
|
||||
// openkey 组成,content = base64({keyId,t,encrypt,signType}) ,sign = md5({keyId,t,encrypt,signType}secret) , key = content.sign
|
||||
const [content, sign] = openKey.split('.');
|
||||
const contentJson = Buffer.from(content, 'base64').toString();
|
||||
const { keyId, t, encrypt, signType } = JSON.parse(contentJson);
|
||||
// 正负不超过3分钟 ,timestamps单位为秒
|
||||
if (Math.abs(Number(t) - Math.floor(Date.now() / 1000)) > 180) {
|
||||
throw new CodeException(Constants.res.openKeyExpiresError);
|
||||
}
|
||||
|
||||
const entity = await this.getByKeyId(keyId);
|
||||
if (!entity) {
|
||||
throw new Error('openKey不存在');
|
||||
}
|
||||
const secret = entity.keySecret;
|
||||
let computedSign = '';
|
||||
if (signType === 'md5') {
|
||||
computedSign = utils.hash.md5(contentJson + secret);
|
||||
} else if (signType === 'sha256') {
|
||||
computedSign = utils.hash.sha256(contentJson + secret);
|
||||
} else {
|
||||
throw new CodeException(Constants.res.openKeySignTypeError);
|
||||
}
|
||||
if (computedSign !== sign) {
|
||||
throw new CodeException(Constants.res.openKeySignError);
|
||||
}
|
||||
|
||||
if (!entity.userId) {
|
||||
throw new CodeException(Constants.res.openKeyError);
|
||||
}
|
||||
|
||||
return {
|
||||
userId: entity.userId,
|
||||
keyId: entity.keyId,
|
||||
keySecret: entity.keySecret,
|
||||
encrypt: encrypt,
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user