feat(license): 首次安装 14 天 Pro 试用(无需授权码)
- 首次启动落试用起点(DATA_DIR/.trial-start 0600 + 库内 settings 双写,取最早防分次续命);
窗口内 IsPro() 等效 Pro——日志分析/告警/AI 助手/审计全解锁,到期自动回免费版
- 防刷三层:时间戳双写(删任一不重发)+ 机器级指纹(machine-id / hostname+cpu,
故意不含 DATA_DIR 特征——目录特征会因删除重建漂移等于后门);指纹命中则落已过期起点
- LicenseStatusPayload 返回 trial{active,daysLeft} 与 plan=trial;
设置页授权区显示「Pro 试用中 · 剩余 N 天」提示条
- 单测:全新安装 14 天/到期回落/删时间戳重装不重发(指纹防刷)三用例
- 滥用评估:删库重装同机器被指纹拦截;换机器/VM 必然可重试(接受,Pro 功能零边际成本,
追杀到硬件级得不偿失);正式授权随时激活覆盖试用
This commit is contained in:
1 parent
f67b86e6bb
commit
9a477e9c9b
6 files changed
+355
-5
No files matched your search
@@ -1,6 +1,8 @@
|
||||
import { http } from '../http'
|
||||
|
||||
export interface TrialInfo { active: boolean; daysLeft: number }
|
||||
export interface LicenseInfo {
|
||||
trial?: TrialInfo
|
||||
plan: 'free' | 'pro'
|
||||
edition?: string
|
||||
instances?: number
|
||||
|
||||
@@ -103,8 +103,14 @@ export const LicenseSection = memo(function LicenseSection() {
|
||||
<CardContent className="space-y-4">
|
||||
<LicenseStatusBanners info={info} pro={pro} onAction={isAdmin && !pro ? focusKey : undefined} />
|
||||
<InstanceIdRow instanceId={info?.instanceId} />
|
||||
{info?.trial?.active && (
|
||||
<div className="flex items-center gap-2 rounded-lg border border-info/40 bg-info/10 px-3 py-2 text-xs text-info">
|
||||
<span className="font-medium">Pro 试用中</span>
|
||||
<span>剩余 {info.trial.daysLeft} 天,到期后回到免费版</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="text-sm">
|
||||
{pro ? (
|
||||
{pro && !info?.trial?.active ? (
|
||||
<div className="grid gap-1 text-muted-foreground sm:grid-cols-2">
|
||||
<p>{t('edition')}: {planLabel}</p>
|
||||
<p>{t('expiry')}: {expiry}</p>
|
||||
|
||||
Reference in new issue
Block a user