certd/packages/ui/certd-server/src/modules/open/service/open-key-service.ts

107 lines
3.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import { Provide, Scope, ScopeEnum } 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';
import dayjs from 'dayjs';
export type OpenKey = {
userId: number;
keyId: string;
keySecret: string;
encrypt: boolean;
};
@Provide()
@Scope(ScopeEnum.Request, { allowDowngrade: true })
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 add(bean: OpenKeyEntity) {
return await this.generate(bean.userId);
}
async generate(userId: number) {
const keyId = utils.id.simpleNanoId(18) + '_key';
const secretKey = crypto.randomBytes(32);
const keySecret = Buffer.from(secretKey).toString('hex');
const entity = new OpenKeyEntity();
entity.userId = userId;
entity.keyId = keyId;
entity.keySecret = keySecret;
await this.repository.save(entity);
return entity;
}
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 (Buffer.from(computedSign).toString('base64') !== 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,
};
}
async getApiToken(id: number) {
const entity = await this.repository.findOne({ where: { id } });
if (!entity) {
throw new Error('id不存在');
}
const { keyId, keySecret } = entity;
const openKey = {
keyId,
t: dayjs().unix(),
encrypt: false,
signType: 'md5',
};
const content = JSON.stringify(openKey);
const sign = utils.hash.md5(content + keySecret);
return Buffer.from(content).toString('base64') + '.' + Buffer.from(sign).toString('base64');
}
}