Files
LokiStack/backend/services/trial_test.go
T
opsx 9a477e9c9b
CI / Backend (go vet + test) (push) Waiting to run
CI / Frontend (lint + build + test) (push) Waiting to run
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 功能零边际成本,
  追杀到硬件级得不偿失);正式授权随时激活覆盖试用
2026-11-01 05:53:55 +08:00

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("指纹已消费的机器删时间戳重装不应重得试用")
}
}