auth.go

v1.3.6
Doc Versions Source
1
package server
2
3
import (
4
	"fmt"
5
	"net/http"
6
	"strings"
7
8
	"go.bigb.es/curator/internal/config"
9
)
10
11
// ParseAdminToken resolves an admin token value.
12
// If value starts with "@", the rest is treated as a file path and the token
13
// is read from the first non-empty, non-comment line.
14
func ParseAdminToken(value string) (string, error) {
15
	resolved, err := config.ResolveValue(value)
16
	if err != nil {
17
		return "", err
18
	}
19
	if !strings.HasPrefix(value, "@") {
20
		return value, nil
21
	}
22
23
	for _, line := range strings.Split(resolved, "\n") {
24
		token := strings.TrimSpace(line)
25
		if token != "" && !strings.HasPrefix(token, "#") {
26
			return token, nil
27
		}
28
	}
29
	return "", fmt.Errorf("no token found in file")
30
}
31
32
// ParseAuthTokens parses auth tokens from a value.
33
// If value starts with "@", the rest is treated as a file path
34
// (one token per line, # comments supported).
35
// Otherwise the value is split on commas.
36
func ParseAuthTokens(value string) (map[string]struct{}, error) {
37
	resolved, err := config.ResolveValue(value)
38
	if err != nil {
39
		return nil, err
40
	}
41
42
	if strings.HasPrefix(value, "@") {
43
		return parseTokenLines(resolved), nil
44
	}
45
46
	// Comma-separated tokens.
47
	tokens := make(map[string]struct{})
48
	for _, raw := range strings.Split(resolved, ",") {
49
		token := strings.TrimSpace(raw)
50
		if token != "" {
51
			tokens[token] = struct{}{}
52
		}
53
	}
54
	return tokens, nil
55
}
56
57
func parseTokenLines(data string) map[string]struct{} {
58
	tokens := make(map[string]struct{})
59
	for _, line := range strings.Split(data, "\n") {
60
		token := strings.TrimSpace(line)
61
		if token != "" && !strings.HasPrefix(token, "#") {
62
			tokens[token] = struct{}{}
63
		}
64
	}
65
	return tokens
66
}
67
68
func (s *Server) isAuthenticated(r *http.Request) bool {
69
	if len(s.AuthTokens) == 0 {
70
		return false
71
	}
72
73
	auth := r.Header.Get("Authorization")
74
	if token, ok := strings.CutPrefix(auth, "Bearer "); ok {
75
		_, valid := s.AuthTokens[token]
76
		return valid
77
	}
78
79
	if _, password, ok := r.BasicAuth(); ok {
80
		_, valid := s.AuthTokens[password]
81
		return valid
82
	}
83
84
	return false
85
}
86
87
// CanAccessModule returns true if the request is allowed to access the module.
88
func (s *Server) CanAccessModule(modName string, r *http.Request) bool {
89
	mod, ok := s.Resolver.ResolveModule(modName)
90
	if !ok {
91
		return false
92
	}
93
94
	if !mod.Private {
95
		return true
96
	}
97
98
	return s.isAuthenticated(r)
99
}
100

Source Files