This commit is contained in:
2026-06-23 05:02:15 +08:00
commit e6f1776d4f
264 changed files with 54215 additions and 0 deletions
+98
View File
@@ -0,0 +1,98 @@
package auth
import (
"fmt"
"os"
"path/filepath"
"strings"
"gopkg.in/yaml.v3"
)
type teaLogin struct {
Name string `yaml:"name"`
URL string `yaml:"url"`
Token string `yaml:"token"`
Default bool `yaml:"default"`
}
type teaConfig struct {
Logins []teaLogin `yaml:"logins"`
}
func parseTea(path string) (*teaConfig, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("read tea config %s: %w", path, err)
}
var cfg teaConfig
if err := yaml.Unmarshal(data, &cfg); err != nil {
return nil, fmt.Errorf("parse tea config %s: %w", path, err)
}
return &cfg, nil
}
func defaultTeaConfigPath() (string, error) {
home, err := os.UserHomeDir()
if err != nil {
return "", fmt.Errorf("resolve home dir: %w", err)
}
return filepath.Join(home, ".config", "tea", "config.yml"), nil
}
// ResolveGiteaToken returns a Gitea token for the given host.
// Resolution order:
// 1. GITEA_TOKEN env var (if non-empty)
// 2. ~/.config/tea/config.yml: entry matching host, else default login
func ResolveGiteaToken(host string) (string, error) {
return resolveGiteaToken(host, "")
}
func resolveGiteaToken(host, teaConfigPath string) (string, error) {
if tok := os.Getenv("GITEA_TOKEN"); tok != "" {
return tok, nil
}
if teaConfigPath == "" {
var err error
teaConfigPath, err = defaultTeaConfigPath()
if err != nil {
return "", err
}
}
cfg, err := parseTea(teaConfigPath)
if err != nil {
return "", err
}
if len(cfg.Logins) == 0 {
return "", fmt.Errorf("no logins in tea config %s", teaConfigPath)
}
want := strings.TrimRight(strings.ToLower(host), "/")
// First try exact host match.
for _, l := range cfg.Logins {
loginHost := strings.TrimRight(strings.ToLower(l.URL), "/")
if loginHost == want {
if l.Token == "" {
return "", fmt.Errorf("tea config login for host %s has empty token", host)
}
return l.Token, nil
}
}
// Fall back to default login.
var chosen *teaLogin
for i := range cfg.Logins {
if cfg.Logins[i].Default {
chosen = &cfg.Logins[i]
break
}
}
if chosen == nil {
chosen = &cfg.Logins[0]
}
if chosen.Token == "" {
return "", fmt.Errorf("tea config default login has empty token")
}
return chosen.Token, nil
}
+106
View File
@@ -0,0 +1,106 @@
package auth
import (
"os"
"path/filepath"
"testing"
)
func writeTeaConfig(t *testing.T, content string) string {
t.Helper()
dir := t.TempDir()
path := filepath.Join(dir, "config.yml")
if err := os.WriteFile(path, []byte(content), 0o600); err != nil {
t.Fatalf("write tea config: %v", err)
}
return path
}
func TestResolveGiteaToken_EnvVarTakesPriority(t *testing.T) {
t.Setenv("GITEA_TOKEN", "envtoken123")
path := writeTeaConfig(t, `logins:
- name: test
url: https://gitea.example.com
token: yamltoken
default: true
`)
tok, err := resolveGiteaToken("https://gitea.example.com", path)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if tok != "envtoken123" {
t.Errorf("got %q, want envtoken123", tok)
}
}
func TestResolveGiteaToken_DefaultLogin(t *testing.T) {
t.Setenv("GITEA_TOKEN", "")
path := writeTeaConfig(t, `logins:
- name: work
url: https://gitea.work.com
token: worktoken
default: false
- name: personal
url: https://gitea.personal.com
token: personaltoken
default: true
`)
tok, err := resolveGiteaToken("https://unknown.host.com", path)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if tok != "personaltoken" {
t.Errorf("got %q, want personaltoken", tok)
}
}
func TestResolveGiteaToken_HostMatch(t *testing.T) {
t.Setenv("GITEA_TOKEN", "")
path := writeTeaConfig(t, `logins:
- name: work
url: https://gitea.work.com
token: worktoken
default: false
- name: personal
url: https://gitea.personal.com
token: personaltoken
default: true
`)
tok, err := resolveGiteaToken("https://gitea.work.com", path)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if tok != "worktoken" {
t.Errorf("got %q, want worktoken", tok)
}
}
func TestResolveGiteaToken_EmptyLogins(t *testing.T) {
t.Setenv("GITEA_TOKEN", "")
path := writeTeaConfig(t, `logins: []`)
_, err := resolveGiteaToken("https://gitea.example.com", path)
if err == nil {
t.Fatal("expected error for empty logins")
}
}
func TestResolveGiteaToken_FirstLoginFallback(t *testing.T) {
t.Setenv("GITEA_TOKEN", "")
path := writeTeaConfig(t, `logins:
- name: first
url: https://gitea.first.com
token: firsttoken
default: false
- name: second
url: https://gitea.second.com
token: secondtoken
default: false
`)
tok, err := resolveGiteaToken("https://unknown.host.com", path)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if tok != "firsttoken" {
t.Errorf("got %q, want firsttoken", tok)
}
}