feat: rename project from Fonu to Havline
CI / verify (push) Canceled after 0s

This commit is contained in:
2026-10-01 16:54:35 +08:00
parent c377405696
commit 8fa5d922ac
250 changed files with 6724 additions and 5070 deletions
+4 -4
View File
@@ -9,8 +9,8 @@ import (
"sync"
"time"
"github.com/fonu/fonu/internal/auth"
"github.com/fonu/fonu/internal/notify"
"github.com/havline/havline/internal/auth"
"github.com/havline/havline/internal/notify"
)
type AuthHandler struct {
@@ -168,7 +168,7 @@ func (h *AuthHandler) Logout(w http.ResponseWriter, r *http.Request) {
func setSessionCookie(w http.ResponseWriter, r *http.Request, sessionID string) {
http.SetCookie(w, &http.Cookie{
Name: "fonu_session",
Name: "havline_session",
Value: sessionID,
Path: "/",
HttpOnly: true,
@@ -197,7 +197,7 @@ func clientIP(r *http.Request) string {
func clearSessionCookie(w http.ResponseWriter, r *http.Request) {
http.SetCookie(w, &http.Cookie{
Name: "fonu_session",
Name: "havline_session",
Value: "",
Path: "/",
HttpOnly: true,
+11 -11
View File
@@ -10,19 +10,19 @@ import (
"testing"
"time"
"github.com/fonu/fonu/internal/auth"
"github.com/fonu/fonu/internal/backup"
"github.com/fonu/fonu/internal/config"
"github.com/fonu/fonu/internal/db"
"github.com/fonu/fonu/internal/discovery"
"github.com/fonu/fonu/internal/certificate"
"github.com/fonu/fonu/internal/proxy"
"github.com/fonu/fonu/internal/service"
"github.com/fonu/fonu/internal/settings"
"github.com/havline/havline/internal/auth"
"github.com/havline/havline/internal/backup"
"github.com/havline/havline/internal/certificate"
"github.com/havline/havline/internal/config"
"github.com/havline/havline/internal/db"
"github.com/havline/havline/internal/discovery"
"github.com/havline/havline/internal/proxy"
"github.com/havline/havline/internal/service"
"github.com/havline/havline/internal/settings"
)
func TestAuthSetupAndLoginFlow(t *testing.T) {
conn, err := db.Open(filepath.Join(t.TempDir(), "fonu.db"))
conn, err := db.Open(filepath.Join(t.TempDir(), "havline.db"))
if err != nil {
t.Fatalf("open db: %v", err)
}
@@ -67,7 +67,7 @@ func TestAuthSetupAndLoginFlow(t *testing.T) {
}
cookie := loginRec.Result().Cookies()[0]
if cookie.Name != "fonu_session" || cookie.HttpOnly == false {
if cookie.Name != "havline_session" || cookie.HttpOnly == false {
t.Fatal("expected httponly session cookie")
}
+5 -5
View File
@@ -6,8 +6,8 @@ import (
"os"
"path/filepath"
"github.com/fonu/fonu/internal/backup"
"github.com/fonu/fonu/internal/settings"
"github.com/havline/havline/internal/backup"
"github.com/havline/havline/internal/settings"
)
type BackupHandler struct {
@@ -52,7 +52,7 @@ func (h *BackupHandler) Restore(w http.ResponseWriter, r *http.Request) {
defer file.Close()
// 上传文件名完全由客户端控制:不能拼进临时路径(../ 可逃出临时目录),交给 CreateTemp 生成
out, err := os.CreateTemp("", "fonu-restore-*.tar.gz")
out, err := os.CreateTemp("", "havline-restore-*.tar.gz")
if err != nil {
writeError(r, w, http.StatusInternalServerError, "保存上传文件失败")
return
@@ -72,7 +72,7 @@ func (h *BackupHandler) Restore(w http.ResponseWriter, r *http.Request) {
return
}
_ = os.Remove(tmpPath)
writeJSON(w, http.StatusOK, map[string]string{"message": "备份已恢复,建议重启 Fonu"})
writeJSON(w, http.StatusOK, map[string]string{"message": "备份已恢复,建议重启 Havline"})
}
// ListArchives 列出留在磁盘上的备份(自动备份 + 手动「立即备份」)。
@@ -150,7 +150,7 @@ func (h *BackupHandler) RestoreArchive(w http.ResponseWriter, r *http.Request) {
writeError(r, w, http.StatusBadRequest, err.Error(), err)
return
}
writeJSON(w, http.StatusOK, map[string]string{"message": "备份已恢复,建议重启 Fonu"})
writeJSON(w, http.StatusOK, map[string]string{"message": "备份已恢复,建议重启 Havline"})
}
// DeleteArchive 删除指定备份
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"net/http"
"strings"
"github.com/fonu/fonu/internal/acme"
"github.com/havline/havline/internal/acme"
)
type CertHandler struct {
+1 -1
View File
@@ -3,7 +3,7 @@ package api
import (
"net/http"
"github.com/fonu/fonu/internal/chinacidr"
"github.com/havline/havline/internal/chinacidr"
)
type ChinaCIDRHandler struct {
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"strconv"
"strings"
"github.com/fonu/fonu/internal/cloudflared"
"github.com/havline/havline/internal/cloudflared"
)
type CloudflareHandler struct {
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"net/http"
"strconv"
"github.com/fonu/fonu/internal/ddns"
"github.com/havline/havline/internal/ddns"
)
type DDNSHandler struct {
+15 -15
View File
@@ -4,21 +4,21 @@ import (
"io/fs"
"log/slog"
"github.com/fonu/fonu/internal/acme"
"github.com/fonu/fonu/internal/auth"
"github.com/fonu/fonu/internal/backup"
"github.com/fonu/fonu/internal/chinacidr"
"github.com/fonu/fonu/internal/cloudflared"
"github.com/fonu/fonu/internal/config"
"github.com/fonu/fonu/internal/ddns"
"github.com/fonu/fonu/internal/discovery"
"github.com/fonu/fonu/internal/frp"
"github.com/fonu/fonu/internal/metrics"
"github.com/fonu/fonu/internal/notify"
"github.com/fonu/fonu/internal/service"
"github.com/fonu/fonu/internal/settings"
"github.com/fonu/fonu/internal/traffic"
"github.com/fonu/fonu/internal/updater"
"github.com/havline/havline/internal/acme"
"github.com/havline/havline/internal/auth"
"github.com/havline/havline/internal/backup"
"github.com/havline/havline/internal/chinacidr"
"github.com/havline/havline/internal/cloudflared"
"github.com/havline/havline/internal/config"
"github.com/havline/havline/internal/ddns"
"github.com/havline/havline/internal/discovery"
"github.com/havline/havline/internal/frp"
"github.com/havline/havline/internal/metrics"
"github.com/havline/havline/internal/notify"
"github.com/havline/havline/internal/service"
"github.com/havline/havline/internal/settings"
"github.com/havline/havline/internal/traffic"
"github.com/havline/havline/internal/updater"
)
type Deps struct {
+1 -1
View File
@@ -3,7 +3,7 @@ package api
import (
"net/http"
"github.com/fonu/fonu/internal/discovery"
"github.com/havline/havline/internal/discovery"
)
type DiscoveryHandler struct {
+2 -2
View File
@@ -10,8 +10,8 @@ import (
"strings"
"time"
"github.com/fonu/fonu/internal/auth"
"github.com/fonu/fonu/internal/frp"
"github.com/havline/havline/internal/auth"
"github.com/havline/havline/internal/frp"
)
// FRPMultiHandler 承载多服务端 FRP 模块的 HTTP 接口(/api/frpmulti/*),
+2 -2
View File
@@ -5,8 +5,8 @@ import (
"path/filepath"
"strconv"
"github.com/fonu/fonu/internal/config"
"github.com/fonu/fonu/internal/logstore"
"github.com/havline/havline/internal/config"
"github.com/havline/havline/internal/logstore"
)
type LogsHandler struct {
+11 -11
View File
@@ -9,20 +9,20 @@ import (
"testing"
"time"
"github.com/fonu/fonu/internal/auth"
"github.com/fonu/fonu/internal/backup"
"github.com/fonu/fonu/internal/config"
"github.com/fonu/fonu/internal/db"
"github.com/fonu/fonu/internal/discovery"
"github.com/fonu/fonu/internal/certificate"
"github.com/fonu/fonu/internal/proxy"
"github.com/fonu/fonu/internal/service"
"github.com/fonu/fonu/internal/settings"
"github.com/havline/havline/internal/auth"
"github.com/havline/havline/internal/backup"
"github.com/havline/havline/internal/certificate"
"github.com/havline/havline/internal/config"
"github.com/havline/havline/internal/db"
"github.com/havline/havline/internal/discovery"
"github.com/havline/havline/internal/proxy"
"github.com/havline/havline/internal/service"
"github.com/havline/havline/internal/settings"
)
func TestLogsAccessRoute(t *testing.T) {
dir := t.TempDir()
conn, err := db.Open(filepath.Join(dir, "fonu.db"))
conn, err := db.Open(filepath.Join(dir, "havline.db"))
if err != nil {
t.Fatalf("open db: %v", err)
}
@@ -50,7 +50,7 @@ func TestLogsAccessRoute(t *testing.T) {
})
req := httptest.NewRequest(http.MethodGet, "/api/logs/access?limit=100", nil)
req.AddCookie(&http.Cookie{Name: "fonu_session", Value: sessionID})
req.AddCookie(&http.Cookie{Name: "havline_session", Value: sessionID})
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"strconv"
"time"
"github.com/fonu/fonu/internal/metrics"
"github.com/havline/havline/internal/metrics"
)
type MetricsHandler struct {
+2 -2
View File
@@ -5,7 +5,7 @@ import (
"net/http"
"strings"
"github.com/fonu/fonu/internal/auth"
"github.com/havline/havline/internal/auth"
)
type contextKey string
@@ -15,7 +15,7 @@ const sessionContextKey contextKey = "session_id"
func SessionMiddleware(authSvc *auth.Service) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie("fonu_session")
cookie, err := r.Cookie("havline_session")
if err == nil && cookie.Value != "" {
ctx := context.WithValue(r.Context(), sessionContextKey, cookie.Value)
r = r.WithContext(ctx)
+3 -3
View File
@@ -8,13 +8,13 @@ import (
"testing"
"time"
"github.com/fonu/fonu/internal/auth"
"github.com/fonu/fonu/internal/db"
"github.com/havline/havline/internal/auth"
"github.com/havline/havline/internal/db"
)
func newTokenTestAuth(t *testing.T, scope string) (*auth.Service, string) {
t.Helper()
conn, err := db.Open(filepath.Join(t.TempDir(), "fonu.db"))
conn, err := db.Open(filepath.Join(t.TempDir(), "havline.db"))
if err != nil {
t.Fatalf("open db: %v", err)
}
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"encoding/json"
"net/http"
"github.com/fonu/fonu/internal/service"
"github.com/havline/havline/internal/service"
)
type NginxHandler struct {
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"encoding/json"
"net/http"
"github.com/fonu/fonu/internal/notify"
"github.com/havline/havline/internal/notify"
)
type NotifyHandler struct {
+5 -5
View File
@@ -5,11 +5,11 @@ import (
"net/http"
"strconv"
"github.com/fonu/fonu/internal/config"
"github.com/fonu/fonu/internal/logstore"
"github.com/fonu/fonu/internal/proxy"
"github.com/fonu/fonu/internal/service"
"github.com/fonu/fonu/internal/traffic"
"github.com/havline/havline/internal/config"
"github.com/havline/havline/internal/logstore"
"github.com/havline/havline/internal/proxy"
"github.com/havline/havline/internal/service"
"github.com/havline/havline/internal/traffic"
)
type ProxyHandler struct {
+1 -1
View File
@@ -1,7 +1,7 @@
package api
import (
"github.com/fonu/fonu/internal/proxy"
"github.com/havline/havline/internal/proxy"
)
type securityRequest struct {
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"strings"
"time"
"github.com/fonu/fonu/internal/auth"
"github.com/havline/havline/internal/auth"
)
// routeSpec 是一条 API 路由的注册信息;测试据此遍历全部路由验证鉴权覆盖。
+9 -9
View File
@@ -11,14 +11,14 @@ import (
"strings"
"testing"
"github.com/fonu/fonu/internal/auth"
"github.com/fonu/fonu/internal/certificate"
"github.com/fonu/fonu/internal/cloudflared"
"github.com/fonu/fonu/internal/config"
"github.com/fonu/fonu/internal/db"
"github.com/fonu/fonu/internal/frp"
"github.com/fonu/fonu/internal/secret"
"github.com/fonu/fonu/internal/settings"
"github.com/havline/havline/internal/auth"
"github.com/havline/havline/internal/certificate"
"github.com/havline/havline/internal/cloudflared"
"github.com/havline/havline/internal/config"
"github.com/havline/havline/internal/db"
"github.com/havline/havline/internal/frp"
"github.com/havline/havline/internal/secret"
"github.com/havline/havline/internal/settings"
)
var routeParamPattern = regexp.MustCompile(`\{[^}]+\}`)
@@ -26,7 +26,7 @@ var routeParamPattern = regexp.MustCompile(`\{[^}]+\}`)
// TestProtectedRoutesRequireAuth 遍历路由表:受保护路由匿名必须 401,公开路由不能被鉴权误拦。
func TestProtectedRoutesRequireAuth(t *testing.T) {
dir := t.TempDir()
conn, err := db.Open(filepath.Join(dir, "fonu.db"))
conn, err := db.Open(filepath.Join(dir, "havline.db"))
if err != nil {
t.Fatalf("open db: %v", err)
}
+4 -4
View File
@@ -7,10 +7,10 @@ import (
"strconv"
"strings"
"github.com/fonu/fonu/internal/notify"
"github.com/fonu/fonu/internal/service"
"github.com/fonu/fonu/internal/settings"
"github.com/fonu/fonu/internal/validate"
"github.com/havline/havline/internal/notify"
"github.com/havline/havline/internal/service"
"github.com/havline/havline/internal/settings"
"github.com/havline/havline/internal/validate"
)
type SettingsHandler struct {
+9 -9
View File
@@ -11,15 +11,15 @@ import (
"sync"
"time"
"github.com/fonu/fonu/internal/acme"
certstore "github.com/fonu/fonu/internal/certificate"
"github.com/fonu/fonu/internal/cloudflared"
"github.com/fonu/fonu/internal/config"
"github.com/fonu/fonu/internal/ddns"
"github.com/fonu/fonu/internal/logstore"
"github.com/fonu/fonu/internal/publicip"
"github.com/fonu/fonu/internal/service"
"github.com/fonu/fonu/internal/sysinfo"
"github.com/havline/havline/internal/acme"
certstore "github.com/havline/havline/internal/certificate"
"github.com/havline/havline/internal/cloudflared"
"github.com/havline/havline/internal/config"
"github.com/havline/havline/internal/ddns"
"github.com/havline/havline/internal/logstore"
"github.com/havline/havline/internal/publicip"
"github.com/havline/havline/internal/service"
"github.com/havline/havline/internal/sysinfo"
)
type StatusHandler struct {
+5 -5
View File
@@ -10,10 +10,10 @@ import (
"sync"
"time"
"github.com/fonu/fonu/internal/cloudflared"
"github.com/fonu/fonu/internal/frp"
"github.com/fonu/fonu/internal/notify"
"github.com/fonu/fonu/internal/settings"
"github.com/havline/havline/internal/cloudflared"
"github.com/havline/havline/internal/frp"
"github.com/havline/havline/internal/notify"
"github.com/havline/havline/internal/settings"
)
// statusPageWindow / statusPageLimit 匿名访问的限流窗口与配额:
@@ -99,7 +99,7 @@ func (h *StatusPageHandler) Get(w http.ResponseWriter, r *http.Request) {
}
payload := statusPagePayload{
Title: "Fonu 服务状态",
Title: "Havline 服务状态",
CodeRequired: codeRequired,
CheckedAt: time.Now().UTC().Format(time.RFC3339),
Routes: make([]statusPageRoute, 0),
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"strings"
"time"
"github.com/fonu/fonu/internal/auth"
"github.com/havline/havline/internal/auth"
)
// 令牌管理挂在 AuthHandler 上:它已经持有 auth.Service,不必再加一层 handler。
+1 -1
View File
@@ -3,7 +3,7 @@ package api
import (
"net/http"
"github.com/fonu/fonu/internal/updater"
"github.com/havline/havline/internal/updater"
)
type UpdateHandler struct {
+5 -5
View File
@@ -3,14 +3,14 @@ package api
import (
"net/http"
"github.com/fonu/fonu/internal/config"
"github.com/fonu/fonu/internal/version"
"github.com/havline/havline/internal/config"
"github.com/havline/havline/internal/version"
)
type versionResponse struct {
Version string `json:"version"`
NginxHTTPPort int `json:"nginx_http_port"`
NginxHTTPSPort int `json:"nginx_https_port"`
Version string `json:"version"`
NginxHTTPPort int `json:"nginx_http_port"`
NginxHTTPSPort int `json:"nginx_https_port"`
}
func Version(cfg config.Config) http.HandlerFunc {
+2 -2
View File
@@ -6,8 +6,8 @@ import (
"net/http/httptest"
"testing"
"github.com/fonu/fonu/internal/config"
"github.com/fonu/fonu/internal/version"
"github.com/havline/havline/internal/config"
"github.com/havline/havline/internal/version"
)
func TestVersionEndpoint(t *testing.T) {