- 首次启动落试用起点(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 功能零边际成本,
追杀到硬件级得不偿失);正式授权随时激活覆盖试用
83 lines
2.2 KiB
Go
83 lines
2.2 KiB
Go
package services
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"testing"
|
|
"time"
|
|
|
|
"lokistack/repository"
|
|
)
|
|
|
|
func trialTestEnv(t *testing.T) string {
|
|
dir := t.TempDir()
|
|
t.Setenv("DATA_DIR", dir)
|
|
t.Setenv("JWT_SECRET", "test-secret-0123456789abcdef")
|
|
t.Setenv("ENCRYPTION_KEY", "test-encryption-key-0123456789abcdef")
|
|
if err := repository.InitDB(); err != nil {
|
|
t.Fatalf("InitDB: %v", err)
|
|
}
|
|
prev := trialDataDirOverride
|
|
trialDataDirOverride = dir
|
|
t.Cleanup(func() { trialDataDirOverride = prev })
|
|
return dir
|
|
}
|
|
|
|
// TestTrialFreshInstall 全新安装:试用生效 14 天、库+文件双写
|
|
func TestTrialFreshInstall(t *testing.T) {
|
|
dir := trialTestEnv(t)
|
|
if !TrialActive() {
|
|
t.Fatal("全新安装试用应生效")
|
|
}
|
|
EnsureTrialStarted()
|
|
if d := TrialRemainingDays(); d != 14 {
|
|
t.Fatalf("剩余应为 14,got %d", d)
|
|
}
|
|
if _, err := os.Stat(filepath.Join(dir, ".trial-start")); err != nil {
|
|
t.Fatal("试用起点文件应落盘")
|
|
}
|
|
if trialStartFromDB() == 0 {
|
|
t.Fatal("库内应记录起点")
|
|
}
|
|
}
|
|
|
|
// TestTrialExpired 试用到期:TrialActive=false、剩余 0
|
|
func TestTrialExpired(t *testing.T) {
|
|
dir := trialTestEnv(t)
|
|
expired := time.Now().Unix() - 15*86400
|
|
_ = os.WriteFile(filepath.Join(dir, ".trial-start"), []byte(strconv.FormatInt(expired, 10)), 0o600)
|
|
persistTrialStart(expired)
|
|
if TrialActive() {
|
|
t.Fatal("到期后试用不应生效")
|
|
}
|
|
if d := TrialRemainingDays(); d != 0 {
|
|
t.Fatalf("到期剩余应为 0,got %d", d)
|
|
}
|
|
if IsPro() {
|
|
t.Fatal("无授权且试用到期不应是 Pro")
|
|
}
|
|
}
|
|
|
|
// TestTrialAntiReinstall 删库重装防刷:指纹已消费则不重发试用
|
|
func TestTrialAntiReinstall(t *testing.T) {
|
|
dir := trialTestEnv(t)
|
|
EnsureTrialStarted()
|
|
// 模拟删库删文件重装:清空时间戳但指纹库保留(指纹写在同库,这里模拟库还在但时间戳被清)
|
|
db := repository.GetDB()
|
|
db.Lock()
|
|
for i := range db.Settings {
|
|
if db.Settings[i].Key == "trial_started_at" {
|
|
db.Settings = append(db.Settings[:i], db.Settings[i+1:]...)
|
|
break
|
|
}
|
|
}
|
|
db.RequestSave()
|
|
db.Unlock()
|
|
_ = os.Remove(filepath.Join(dir, ".trial-start"))
|
|
EnsureTrialStarted()
|
|
if TrialActive() {
|
|
t.Fatal("指纹已消费的机器删时间戳重装不应重得试用")
|
|
}
|
|
}
|