pull/148/head
xiaojunnuo 2024-08-24 23:48:26 +08:00
parent c28f3cdcf7
commit 86ebbcb9bb
5 changed files with 62 additions and 21 deletions

View File

@ -19,14 +19,14 @@ type License = {
duration: number; duration: number;
version: number; version: number;
secret: string; secret: string;
level: number; vipType: string;
signature: string; signature: string;
}; };
class LicenseHolder { class LicenseHolder {
isPlus = false; isPlus = false;
expireTime = 0; expireTime = 0;
level = 1; vipType = "";
message?: string = undefined; message?: string = undefined;
secret?: string = undefined; secret?: string = undefined;
} }
@ -46,11 +46,11 @@ class LicenseVerifier {
holder.isPlus = true; holder.isPlus = true;
holder.expireTime = info.expireTime; holder.expireTime = info.expireTime;
holder.secret = info.secret; holder.secret = info.secret;
holder.level = info.level; holder.vipType = info.vipType;
} else { } else {
holder.isPlus = false; holder.isPlus = false;
holder.expireTime = 0; holder.expireTime = 0;
holder.level = 1; holder.vipType = "";
holder.message = info.message; holder.message = info.message;
holder.secret = undefined; holder.secret = undefined;
} }
@ -69,13 +69,13 @@ class LicenseVerifier {
return this.setPlus(false); return this.setPlus(false);
} }
const licenseJson = Buffer.from(Buffer.from(license, "hex").toString(), "base64").toString(); const licenseJson = Buffer.from(license, "base64").toString();
const json: License = JSON.parse(licenseJson); const json: License = JSON.parse(licenseJson);
if (json.expireTime < Date.now()) { if (json.expireTime < Date.now()) {
logger.warn("授权已过期"); logger.warn("授权已过期");
return this.setPlus(false, { message: "授权已过期" }); return this.setPlus(false, { message: "授权已过期" });
} }
const content = `${appKey},${this.licenseReq.subjectId},${json.code},${json.secret},${json.level},${json.activeTime},${json.duration},${json.expireTime},${json.version}`; const content = `${appKey},${this.licenseReq.subjectId},${json.code},${json.secret},${json.vipType},${json.activeTime},${json.duration},${json.expireTime},${json.version}`;
// content := fmt.Sprintf("%s,%s,%s,%s,%d,%d,%d,%d,%d", entity.AppKey, entity.SubjectId, entity.Code, entity.Secret, entity.Level, entity.ActiveTime, entity.Duration, entity.ExpireTime, entity.Version) // content := fmt.Sprintf("%s,%s,%s,%s,%d,%d,%d,%d,%d", entity.AppKey, entity.SubjectId, entity.Code, entity.Secret, entity.Level, entity.ActiveTime, entity.Duration, entity.ExpireTime, entity.Version)
//z4nXOeTeSnnpUpnmsV,_m9jFTdNHktdaEN4xBDw_,HZz7rAAR3h3zGlDMhScO1wGBYPjXpZ9S_1,uUpr9I8p6K3jWSzu2Wh5NECvgG2FNynU,0,1724199847470,365,1787271324416,1 //z4nXOeTeSnnpUpnmsV,_m9jFTdNHktdaEN4xBDw_,HZz7rAAR3h3zGlDMhScO1wGBYPjXpZ9S_1,uUpr9I8p6K3jWSzu2Wh5NECvgG2FNynU,0,1724199847470,365,1787271324416,1
logger.debug("content:", content); logger.debug("content:", content);
@ -89,7 +89,7 @@ class LicenseVerifier {
logger.info(`授权校验成功,到期时间:${dayjs(json.expireTime).format("YYYY-MM-DD HH:mm:ss")}`); logger.info(`授权校验成功,到期时间:${dayjs(json.expireTime).format("YYYY-MM-DD HH:mm:ss")}`);
return this.setPlus(true, { return this.setPlus(true, {
expireTime: json.expireTime, expireTime: json.expireTime,
level: json.level || 1, vipType: json.vipType || "plus",
secret: json.secret, secret: json.secret,
}); });
} }
@ -104,18 +104,27 @@ class LicenseVerifier {
const verifier = new LicenseVerifier(); const verifier = new LicenseVerifier();
export function isPlus() { export function isPlus() {
return holder.isPlus; return holder.isPlus && holder.expireTime > Date.now();
}
export function isCommercial() {
return holder.isPlus && holder.vipType === "comm" && holder.expireTime > Date.now();
} }
export function getPlusInfo() { export function getPlusInfo() {
return { return {
isPlus: holder.isPlus, isPlus: holder.isPlus,
level: holder.level, vipType: holder.vipType,
expireTime: holder.expireTime, expireTime: holder.expireTime,
secret: holder.secret, secret: holder.secret,
}; };
} }
export async function verify(req: LicenseVerifyReq) { export async function verify(req: LicenseVerifyReq) {
return await verifier.reVerify(req); try {
return await verifier.reVerify(req);
} catch (e) {
logger.error(e);
return verifier.setPlus(false, { message: "授权校验失败" });
}
} }

View File

@ -6,20 +6,41 @@
<span v-if="userStore.plusInfo?.isPlus"> <span v-if="userStore.plusInfo?.isPlus">
<a-tooltip> <a-tooltip>
<template #title> 到期时间{{ expireTime }} </template> <template #title> 到期时间{{ expireTime }} </template>
<span @click="openUpgrade"></span> <span @click="openUpgrade">{{ texts.plus }}</span>
</a-tooltip> </a-tooltip>
</span> </span>
<span v-else @click="openUpgrade"> </span> <span v-else @click="openUpgrade"> {{ texts.free }} </span>
</div> </div>
</div> </div>
</template> </template>
<script lang="tsx" setup> <script lang="tsx" setup>
import { ref, reactive } from "vue"; import { ref, reactive, computed } from "vue";
import { useUserStore } from "/src/store/modules/user"; import { useUserStore } from "/src/store/modules/user";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { message, Modal } from "ant-design-vue"; import { message, Modal } from "ant-design-vue";
import * as api from "./api"; import * as api from "./api";
const props = defineProps<{
mode: "button" | "nav";
}>();
type Texts = {
plus: string;
free: string;
};
const texts = computed<Texts>(() => {
if (props.mode === "button") {
return {
plus: "已开通",
free: "专业版功能"
};
} else {
return {
plus: "专业版",
free: "免费版,立即升级"
};
}
});
const userStore = useUserStore(); const userStore = useUserStore();
const expireTime = ref(""); const expireTime = ref("");
if (userStore.plusInfo?.isPlus) { if (userStore.plusInfo?.isPlus) {
@ -91,6 +112,7 @@ function openUpgrade() {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
height: 100%; height: 100%;
cursor: pointer;
&.isPlus { &.isPlus {
color: #c5913f; color: #c5913f;
} }

View File

@ -14,11 +14,11 @@
@finish-failed="onFinishFailed" @finish-failed="onFinishFailed"
> >
<a-form-item label="使用邮件代理" name="usePlus"> <a-form-item label="使用邮件代理" name="usePlus">
<a-switch v-model:checked="formState.usePlus" :disabled="!userStore.isPlus" /> <div class="flex-o">
<div class="helper">专业版功能免除繁琐的邮件配置直接发邮件</div> <a-switch v-model:checked="formState.usePlus" :disabled="!userStore.isPlus" />
<div> <vip-button class="ml-5" mode="button"></vip-button>
<vip-button></vip-button>
</div> </div>
<div class="helper">专业版功能免除繁琐的邮件配置直接发邮件</div>
</a-form-item> </a-form-item>
<template v-if="!formState.usePlus"> <template v-if="!formState.usePlus">
<a-form-item label="SMTP域名" name="host" :rules="[{ required: true, message: '请输入smtp域名或ip' }]"> <a-form-item label="SMTP域名" name="host" :rules="[{ required: true, message: '请输入smtp域名或ip' }]">

View File

@ -1,10 +1,10 @@
import { MidwayEnvironmentService } from '@midwayjs/core'; import { MidwayEnvironmentService } from '@midwayjs/core';
import { Controller, Get, Inject, Provide } from '@midwayjs/core'; import { Controller, Get, Inject, Provide } from '@midwayjs/core';
import { logger } from '../utils/logger.js'; import { logger } from '../../../utils/logger.js';
import { Constants } from '../basic/constants.js'; import { Constants } from '../../../basic/constants.js';
@Provide() @Provide()
@Controller('/hello') @Controller('/home')
export class HomeController { export class HomeController {
@Inject() @Inject()
environmentService: MidwayEnvironmentService; environmentService: MidwayEnvironmentService;

View File

@ -1,7 +1,7 @@
import { Config, Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core'; import { Config, Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
import { SysSettingsService } from '../../system/service/sys-settings-service.js'; import { SysSettingsService } from '../../system/service/sys-settings-service.js';
import { SysInstallInfo } from '../../system/service/models.js'; import { SysInstallInfo } from '../../system/service/models.js';
import { appKey, getPlusInfo } from '@certd/pipeline'; import { appKey, getPlusInfo, isPlus } from '@certd/pipeline';
import * as crypto from 'crypto'; import * as crypto from 'crypto';
import { request } from '../../../utils/http.js'; import { request } from '../../../utils/http.js';
import { logger } from '../../../utils/logger.js'; import { logger } from '../../../utils/logger.js';
@ -20,6 +20,9 @@ export class PlusService {
} }
async request(config: any) { async request(config: any) {
if (!isPlus()) {
throw new Error('您还不是专业版,请先激活专业版');
}
const { url, data } = config; const { url, data } = config;
const timestamps = Date.now(); const timestamps = Date.now();
const installInfo: SysInstallInfo = await this.sysSettingsService.getSetting(SysInstallInfo); const installInfo: SysInstallInfo = await this.sysSettingsService.getSetting(SysInstallInfo);
@ -51,6 +54,13 @@ export class PlusService {
const params = JSON.stringify(body); const params = JSON.stringify(body);
const plusInfo = getPlusInfo(); const plusInfo = getPlusInfo();
const secret = plusInfo.secret; const secret = plusInfo.secret;
if (!secret) {
const randomTime = Math.floor(Math.random() * 3 * 60 * 1000 + 30 * 1000);
setTimeout(() => {
process.exit();
}, randomTime);
return 'xxxxx';
}
const content = `${params}.${timestamps}.${secret}`; const content = `${params}.${timestamps}.${secret}`;
// sha256 // sha256