Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
142 commits
Select commit Hold shift + click to select a range
bfd4a61
fix: avoid duplicate bulk queue consumers
hardy-dev-infinilabs May 6, 2026
010000c
fix: keep consumer conflicts visible
hardy-dev-infinilabs May 6, 2026
543b468
fix: rate limit bulk queue lock logs
hardy-dev-infinilabs May 6, 2026
660c135
fix: avoid local bulk queue owner races
hardy-dev-infinilabs May 6, 2026
06d00a6
Merge remote-tracking branch 'origin/main' into pr/bulk-indexing-cons…
hardy-dev-infinilabs May 6, 2026
a177816
docs: add release note for bulk queue consumer fix
hardy-dev-infinilabs May 6, 2026
dbfe957
Merge branch 'main' into pr/bulk-indexing-consumer-race
hardy-dev-infinilabs May 11, 2026
0095e10
chore: for migration locat test
hardy-dev-infinilabs May 9, 2026
8231706
improve: add hash and terms partition
hardy-dev-infinilabs May 16, 2026
d5a190d
improve: add test for patition
hardy-dev-infinilabs May 16, 2026
2befa0b
improve: setting delete after compress with default true
hardy-dev-infinilabs May 16, 2026
9e34b49
improve: add creator for command save
hardy-dev-infinilabs May 16, 2026
d117e4a
improve: scroll and bulk continue
hardy-dev-infinilabs May 16, 2026
ee806e0
fix: config callback at first then pipeline restart
hardy-dev-infinilabs May 16, 2026
c3b0f5d
fix: init metadata by first register cluster
hardy-dev-infinilabs May 17, 2026
64f9330
fix: collect mode change with metrics for pipeline
hardy-dev-infinilabs May 17, 2026
b919298
fix: collect mode change with metrics for pipeline
hardy-dev-infinilabs May 17, 2026
7461327
fix: agent mode with metrics collect
hardy-dev-infinilabs May 17, 2026
d786b49
fix: registory for gateway
hardy-dev-infinilabs May 17, 2026
031f481
improve: migration with api context
hardy-dev-infinilabs May 18, 2026
86815e5
fix: console setup failed without initialized
hardy-dev-infinilabs May 18, 2026
9214dc5
fix: console setup failed without orm handler
hardy-dev-infinilabs May 18, 2026
cd63ded
fix: task and env for data and log
hardy-dev-infinilabs May 18, 2026
65c74c9
fix: service install and start user corrent data and log path
hardy-dev-infinilabs May 18, 2026
102a66b
improve: patition hash with missing values
hardy-dev-infinilabs May 18, 2026
88faccf
improve: pipeline with delete task
hardy-dev-infinilabs May 18, 2026
efa8d4d
improve: bulk index with docs
hardy-dev-infinilabs May 18, 2026
9cbed71
fix: pecentail for date
hardy-dev-infinilabs May 18, 2026
94951c3
improve: partition with terms
hardy-dev-infinilabs May 18, 2026
eaaac5e
fix: bulk index with corrent offset
hardy-dev-infinilabs May 18, 2026
88b2394
improve: format with only go files
hardy-dev-infinilabs May 19, 2026
bea7e1d
improve: add debug log for check cluster is not available
hardy-dev-infinilabs May 19, 2026
6c7e2b0
fix: when host can't access the metrics not use endpoint for collect
hardy-dev-infinilabs May 19, 2026
b8b3ad2
improve: add log for migration debug
hardy-dev-infinilabs May 20, 2026
4e40610
improve: init delay for task
hardy-dev-infinilabs May 20, 2026
982d252
improve: use availabels seed host
hardy-dev-infinilabs May 20, 2026
4c9e3f7
improve: base path with endpoint
hardy-dev-infinilabs May 20, 2026
733c889
improve: reduce debug logs for files clean
hardy-dev-infinilabs May 21, 2026
1e7eb10
improve: instance list with agent stats
hardy-dev-infinilabs May 21, 2026
9932769
improve: instance queue/config/task with agent
hardy-dev-infinilabs May 21, 2026
52c13b7
improve: instance enroll with web api
hardy-dev-infinilabs May 22, 2026
ecc8a40
improve: access with token for communicate
hardy-dev-infinilabs May 22, 2026
74a3102
improve: add instance with info
hardy-dev-infinilabs May 22, 2026
15042b1
fix: entry reload callback error
hardy-dev-infinilabs May 22, 2026
0bdc1d9
improve: update websocket to 8mb
hardy-dev-infinilabs May 22, 2026
c3a513f
improve: refactor for the code
hardy-dev-infinilabs May 22, 2026
13c81cf
improve: refactor for the code
hardy-dev-infinilabs May 23, 2026
10cfb4f
improve: refactor for the code
hardy-dev-infinilabs May 23, 2026
38b79a1
improve: agent reverse channel endpoint use array
hardy-dev-infinilabs May 23, 2026
513cc7d
fix(api): avoid duplicate embedded websocket routes
hardy-dev-infinilabs May 23, 2026
8337c84
fix(api): keep embedded API off UI root
hardy-dev-infinilabs May 23, 2026
3d2145b
fix(configs): inherit manager tls for config clients
hardy-dev-infinilabs May 23, 2026
c4f398a
feat: sync native challenge login into console_framework\n\nCo-author…
hardy-dev-infinilabs May 26, 2026
9f276ce
feat: support shared account flow migration\n\nCo-authored-by: Copilo…
hardy-dev-infinilabs May 26, 2026
f595d17
Avoid panic in RBAC user flow
hardy-dev-infinilabs May 26, 2026
be86a28
Clean auth runtime panics
hardy-dev-infinilabs May 26, 2026
62421be
Inline RBAC account routes
hardy-dev-infinilabs May 26, 2026
76d005b
Rehome account hook helpers
hardy-dev-infinilabs May 26, 2026
28d23e3
Tighten account login semantics
hardy-dev-infinilabs May 26, 2026
c4c5935
Drop legacy claim aliases
hardy-dev-infinilabs May 26, 2026
856ed7d
Protect framework roles in use
hardy-dev-infinilabs May 26, 2026
6ed8518
improve: add check for already register
hardy-dev-infinilabs May 27, 2026
202bf91
refactor: refactoring to simplify go modules (#300)
medcl May 22, 2026
e9a7a2d
fix: shared format target for non-module repositories (#361)
hardy-dev-infinilabs May 25, 2026
5f3bb5d
refactor: update gopsutil to v4, add overall host metrics (#281)
Copilot May 25, 2026
4f38ae2
fix(pipeline): add task type aliases for branch compatibility
hardy-dev-infinilabs May 27, 2026
78891af
fix: cluster register with metrics collect
hardy-dev-infinilabs May 27, 2026
8143a07
fix: console behind nginx with tls
hardy-dev-infinilabs May 28, 2026
123be0b
fix: logs search and check polling
hardy-dev-infinilabs May 28, 2026
a59bb4a
fix: monitor disable and cluster delete for clean kv
hardy-dev-infinilabs May 28, 2026
198b577
fix: build error with impl
hardy-dev-infinilabs May 28, 2026
cbf3390
feat: add token exchange for access
hardy-dev-infinilabs May 29, 2026
6c906bb
improve: guide for init and setting for migration
hardy-dev-infinilabs May 29, 2026
c049643
fix: config file check and security public api
hardy-dev-infinilabs May 29, 2026
e4dacd9
fix: config file check and security public api
hardy-dev-infinilabs May 29, 2026
2e16b2b
fix: ui method after api call with bridge
hardy-dev-infinilabs May 29, 2026
fe252eb
chore: fix incorrect provider (#371)
medcl May 28, 2026
624f0b9
fix: add missing api method ui route
hardy-dev-infinilabs May 29, 2026
50e191a
fix: add missing api method ui route for web
hardy-dev-infinilabs May 29, 2026
46ed919
fix: install script with token sync
hardy-dev-infinilabs May 29, 2026
7f61103
fix: auth for instance stats
hardy-dev-infinilabs May 29, 2026
30b30b6
fix: gateway access with username and password
hardy-dev-infinilabs May 29, 2026
8f9e464
fix: instance stats stuck the http request
hardy-dev-infinilabs May 29, 2026
5d97116
fix: migration with token auth by default
hardy-dev-infinilabs May 29, 2026
5f2b511
fix: disk sync with queue
hardy-dev-infinilabs May 29, 2026
b16b2dd
fix: console restart with bad file
hardy-dev-infinilabs May 29, 2026
a03595a
fix: console restart with bad file by comsumer
hardy-dev-infinilabs May 29, 2026
2109e33
improve: add sync publish address
hardy-dev-infinilabs May 30, 2026
68ef9e0
fix: https with nginx proxy
hardy-dev-infinilabs May 30, 2026
0bf767a
fix: agent register publish network address
hardy-dev-infinilabs May 30, 2026
93e67ba
fix: agent register publish network address test
hardy-dev-infinilabs May 30, 2026
0510d95
improve: edpoint with schema and log debug reduce
hardy-dev-infinilabs May 30, 2026
8903c1e
improve: log reduce with error user login
hardy-dev-infinilabs May 30, 2026
57545fe
improve: monitor log reduce with error user login
hardy-dev-infinilabs May 30, 2026
32120e1
improve: default close access log
hardy-dev-infinilabs May 31, 2026
a2ccf87
improve: legence agent register for console
hardy-dev-infinilabs May 31, 2026
04e3fad
improve: credention select manul first
hardy-dev-infinilabs May 31, 2026
c7153d3
improve: reduce debug log only for check
hardy-dev-infinilabs May 31, 2026
19fe96f
fix: legence agent auth faile with register
hardy-dev-infinilabs May 31, 2026
ee89304
fix: legence agent auth faile with register for log
hardy-dev-infinilabs May 31, 2026
0afba6d
fix: atomic register at time
hardy-dev-infinilabs May 31, 2026
3aae76b
fix: challenge same
hardy-dev-infinilabs Jun 1, 2026
6642942
fix: ui work well with test and log mask
hardy-dev-infinilabs Jun 1, 2026
9e18ac6
improve: some page optimize and legacy login
hardy-dev-infinilabs Jun 2, 2026
7395d8b
improve: store no panic and pause only running
hardy-dev-infinilabs Jun 2, 2026
9e9aef5
fix: migration can't stop with arm64
hardy-dev-infinilabs Jun 2, 2026
144c33a
improve: user login upgrade by challege
hardy-dev-infinilabs Jun 2, 2026
ab83db6
improve: login with upgrade
hardy-dev-infinilabs Jun 2, 2026
5b7aad4
fix: hide task and remove node alert with time range
hardy-dev-infinilabs Jun 10, 2026
6fae495
fix: common alert with the health activity change
hardy-dev-infinilabs Jun 11, 2026
f1ec0c6
fix: index recorded and metadata twice to activity
hardy-dev-infinilabs Jun 11, 2026
0d321ab
chore: start merge conflict resolution with main
Copilot Jun 11, 2026
b72cb38
fix: resolve merge conflicts with main branch
Copilot Jun 11, 2026
121bf92
fix: mTLS skip domain verify
hardy-dev-infinilabs Jun 11, 2026
7585778
Merge remote-tracking branch 'origin/console_framework' into console_…
Copilot Jun 11, 2026
1164ae0
chore: add mTLS skip domain verify test
hardy-dev-infinilabs Jun 11, 2026
85bf5ae
fix: correct GetPipelinesResponse and GetPipelineTasksResponse type a…
hardy-dev-infinilabs Jun 11, 2026
2fb02a5
fix: remove references to deleted Permissions field in UserSessionInfo
Copilot Jun 11, 2026
b222e26
fix: remove references to deleted Permissions field in UserSessionInfo
Copilot Jun 11, 2026
615ca02
chore: revert the generated info
hardy-dev-infinilabs Jun 11, 2026
1a64d24
chore: revert app
medcl Jun 11, 2026
47c5590
chore: revert unnecessary change
medcl Jun 11, 2026
e43f1af
chore: revert unnecessary change
medcl Jun 11, 2026
20f3ac0
chore: revert unnecessary change
medcl Jun 11, 2026
193351d
fix: get alias failed with permission
hardy-dev-infinilabs Jun 11, 2026
d41d668
chore: remove trace log
hardy-dev-infinilabs Jun 12, 2026
8042b5e
chore: remove unused duplicated access_token
medcl Jun 12, 2026
0eeeb07
improve: metadata sync increasement
hardy-dev-infinilabs Jun 12, 2026
fc4db22
fix: type [UnmappedTerms] unsupported
hardy-dev-infinilabs Jun 12, 2026
7a305e8
improve: recovery with bootstrap token for agent
hardy-dev-infinilabs Jun 12, 2026
7cde061
chore: temp file for target file was exits, skip
hardy-dev-infinilabs Jun 13, 2026
3771157
improve: update the host avaliable check
hardy-dev-infinilabs Jun 15, 2026
fefc4e1
improve: restore gateway register to console
hardy-dev-infinilabs Jun 15, 2026
1ff4492
chore: add interval to bucket
medcl Jun 16, 2026
a8ef5b1
Merge branch 'console_framework' of github.com:infinilabs/framework i…
medcl Jun 16, 2026
d88324b
improve: add get all endpoints
hardy-dev-infinilabs Jun 16, 2026
8e5a12f
fix: element for array with quote
hardy-dev-infinilabs Jun 16, 2026
cc62257
fix: add event sink for metric
hardy-dev-infinilabs Jul 11, 2026
12b16a1
chore: code format and audit with user and role
hardy-dev-infinilabs Jul 29, 2026
bf1de81
fix: api token with api
hardy-dev-infinilabs Aug 7, 2026
1cb5787
fix: token with api expire date
hardy-dev-infinilabs Aug 8, 2026
5e3b781
fix: reset password and secrets
hardy-dev-infinilabs Aug 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -377,4 +377,4 @@ package-linux-arm-platform:
package-windows-platform:
@echo "Packaging Windows"
cd $(OUTPUT_DIR) && zip -r $(OUTPUT_DIR)/windows-amd64.zip $(APP_NAME)-windows-amd64.exe $(APP_CONFIG)
cd $(OUTPUT_DIR) && zip -r $(OUTPUT_DIR)/windows-386.zip $(APP_NAME)-windows-386.exe $(APP_CONFIG)
cd $(OUTPUT_DIR) && zip -r $(OUTPUT_DIR)/windows-386.zip $(APP_NAME)-windows-386.exe $(APP_CONFIG)
2 changes: 1 addition & 1 deletion cmd/vfs/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ func (vfs StaticFS) Open(name string) (http.File, error) {
}
}

log.Debug("local file not found,", localFile)
log.Trace("local file not found,", localFile)
}

if vfs.SkipVFS{
Expand Down
92 changes: 90 additions & 2 deletions core/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"net"
"net/http"
"runtime"
"strings"
"sync"
"time"

Expand Down Expand Up @@ -120,7 +121,7 @@ func initializeAPI() {
}

// HandleAPIMethod register api handler
func HandleAPIMethod(method Method, pattern string, handler func(w http.ResponseWriter, req *http.Request, ps httprouter.Params)) {
func HandleAPIMethod(method Method, pattern string, handler func(w http.ResponseWriter, req *http.Request, ps httprouter.Params), options ...Option) {
l.Lock()
if registeredAPIMethodHandler == nil {
registeredAPIMethodHandler = map[string]map[string]func(w http.ResponseWriter, req *http.Request, ps httprouter.Params){}
Expand All @@ -132,8 +133,57 @@ func HandleAPIMethod(method Method, pattern string, handler func(w http.Response
registeredAPIMethodHandler[m] = map[string]func(w http.ResponseWriter, req *http.Request, ps httprouter.Params){}
}
registeredAPIMethodHandler[m][pattern] = handler
if len(options) > 0 {
opts := &HandlerOptions{}
for _, option := range options {
option(opts)
}
apiOptions.Register(method, pattern, opts)
}

l.Unlock()
}

func ServeRegisteredAPIRequest(w http.ResponseWriter, req *http.Request) {
localMux := http.NewServeMux()
localRouter := httprouter.New(localMux)
localRouter.NotFound = notfoundHandler

l.Lock()
funcHandlers := make(map[string]func(http.ResponseWriter, *http.Request), len(registeredAPIFuncHandler))
for pattern, handler := range registeredAPIFuncHandler {
funcHandlers[pattern] = handler
}
methodHandlers := make(map[string]map[string]func(w http.ResponseWriter, req *http.Request, ps httprouter.Params), len(registeredAPIMethodHandler))
for method, handlers := range registeredAPIMethodHandler {
cloned := make(map[string]func(w http.ResponseWriter, req *http.Request, ps httprouter.Params), len(handlers))
for pattern, handler := range handlers {
cloned[pattern] = handler
}
methodHandlers[method] = cloned
}
filterSnapshot := append([]filter.Filter(nil), filters...)
l.Unlock()

for pattern, handler := range funcHandlers {
wrapped := handler
for _, f := range filterSnapshot {
wrapped = f.FilterHttpHandlerFunc(pattern, wrapped)
}
localMux.HandleFunc(pattern, wrapped)
}

for method, handlers := range methodHandlers {
for pattern, handler := range handlers {
wrapped := handler
for _, f := range filterSnapshot {
wrapped = f.FilterHttpRouter(pattern, wrapped)
}
localRouter.Handle(method, pattern, wrapped)
}
}

localRouter.ServeHTTP(w, req)
}

var router = httprouter.New(mux)
Expand All @@ -145,8 +195,45 @@ var rootKey *rsa.PrivateKey
var rootCertPEM []byte

var apiConfig *config.APIConfig

var listenAddress string
var resolveRuntimePublishIPv4 = util.GetIntranetIP

func normalizeRuntimePublishAddress(actualAddr string) string {
actualAddr = strings.TrimSpace(actualAddr)
if actualAddr == "" {
return actualAddr
}

host, port, err := net.SplitHostPort(actualAddr)
if err != nil {
return actualAddr
}

normalizedHost := strings.Trim(strings.TrimSpace(host), "[]")
if normalizedHost != "" {
ip := net.ParseIP(normalizedHost)
if normalizedHost != util.AnyAddress && (ip == nil || !ip.IsUnspecified()) {
return actualAddr
}
}

ipv4, err := resolveRuntimePublishIPv4()
if err != nil || strings.TrimSpace(ipv4) == "" {
return actualAddr
}

return net.JoinHostPort(ipv4, port)
}

func syncRuntimePublishAddress(networkConfig *config.NetworkConfig, actualAddr string) {
if networkConfig == nil || strings.TrimSpace(actualAddr) == "" {
return
}
if strings.TrimSpace(networkConfig.Publish) != "" {
return
}
networkConfig.Publish = normalizeRuntimePublishAddress(actualAddr)
}

var notfoundHandler = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
rw.Write([]byte("{\"message\":\"not_found\"}"))
Expand Down Expand Up @@ -219,6 +306,7 @@ func StartAPI() {
if err != nil {
panic(err)
}
syncRuntimePublishAddress(&apiConfig.NetworkConfig, l.Addr().String())

router.NotFound = notfoundHandler

Expand Down
128 changes: 128 additions & 0 deletions core/api/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,14 @@
package api

import (
"fmt"
"net/http"
"net/http/httptest"
"testing"
"time"

httprouter "infini.sh/framework/core/api/router"
"infini.sh/framework/core/config"
)

func TestStripPrefix(t *testing.T) {
Expand Down Expand Up @@ -111,3 +116,126 @@ func TestStripPrefix(t *testing.T) {
})
}
}

func TestServeRegisteredAPIRequest(t *testing.T) {
path := fmt.Sprintf("/__copilot_test__/api/%s/:id", t.Name())
HandleAPIMethod(GET, path, func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
w.WriteHeader(http.StatusAccepted)
_, _ = w.Write([]byte(ps.MustGetParameter("id") + ":" + req.URL.Query().Get("q")))
})

req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("%s/value?q=ok", fmt.Sprintf("/__copilot_test__/api/%s", t.Name())), nil)
recorder := httptest.NewRecorder()

ServeRegisteredAPIRequest(recorder, req)

if recorder.Code != http.StatusAccepted {
t.Fatalf("unexpected status: %d", recorder.Code)
}
if recorder.Body.String() != "value:ok" {
t.Fatalf("unexpected body: %s", recorder.Body.String())
}
}

func TestServeRegisteredAPIRequestAllowsNestedDispatch(t *testing.T) {
innerPath := fmt.Sprintf("/__copilot_test__/api/%s/inner", t.Name())
outerPath := fmt.Sprintf("/__copilot_test__/api/%s/outer", t.Name())

HandleAPIMethod(GET, innerPath, func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
w.WriteHeader(http.StatusAccepted)
_, _ = w.Write([]byte("inner-ok"))
})
HandleAPIMethod(GET, outerPath, func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
innerReq := httptest.NewRequest(http.MethodGet, innerPath, nil)
innerRecorder := httptest.NewRecorder()
ServeRegisteredAPIRequest(innerRecorder, innerReq)
w.WriteHeader(innerRecorder.Code)
_, _ = w.Write(innerRecorder.Body.Bytes())
})

req := httptest.NewRequest(http.MethodGet, outerPath, nil)
recorder := httptest.NewRecorder()

done := make(chan struct{})
go func() {
defer close(done)
ServeRegisteredAPIRequest(recorder, req)
}()

select {
case <-done:
case <-time.After(2 * time.Second):
t.Fatal("nested dispatch timed out")
}

if recorder.Code != http.StatusAccepted {
t.Fatalf("unexpected status: %d", recorder.Code)
}
if recorder.Body.String() != "inner-ok" {
t.Fatalf("unexpected body: %s", recorder.Body.String())
}
}

func TestSyncRuntimePublishAddressUsesActualListenAddressWhenUnset(t *testing.T) {
oldResolver := resolveRuntimePublishIPv4
resolveRuntimePublishIPv4 = func() (string, error) {
return "192.168.3.185", nil
}
t.Cleanup(func() {
resolveRuntimePublishIPv4 = oldResolver
})

cfg := config.NetworkConfig{}

syncRuntimePublishAddress(&cfg, "0.0.0.0:2901")

if cfg.Publish != "192.168.3.185:2901" {
t.Fatalf("expected runtime publish address to be updated, got %q", cfg.Publish)
}
}

func TestSyncRuntimePublishAddressNormalizesIPv6UnspecifiedHost(t *testing.T) {
oldResolver := resolveRuntimePublishIPv4
resolveRuntimePublishIPv4 = func() (string, error) {
return "192.168.3.185", nil
}
t.Cleanup(func() {
resolveRuntimePublishIPv4 = oldResolver
})

cfg := config.NetworkConfig{}

syncRuntimePublishAddress(&cfg, "[::]:2901")

if cfg.Publish != "192.168.3.185:2901" {
t.Fatalf("expected ipv6 unspecified runtime publish address to use ipv4, got %q", cfg.Publish)
}
}

func TestSyncRuntimePublishAddressPreservesExplicitPublishAddress(t *testing.T) {
cfg := config.NetworkConfig{Publish: "gateway.example:8443"}

syncRuntimePublishAddress(&cfg, "0.0.0.0:2901")

if cfg.Publish != "gateway.example:8443" {
t.Fatalf("expected explicit publish address to be preserved, got %q", cfg.Publish)
}
}

func TestSyncRuntimePublishAddressPreservesConcreteListenAddress(t *testing.T) {
oldResolver := resolveRuntimePublishIPv4
resolveRuntimePublishIPv4 = func() (string, error) {
return "192.168.3.185", nil
}
t.Cleanup(func() {
resolveRuntimePublishIPv4 = oldResolver
})

cfg := config.NetworkConfig{}

syncRuntimePublishAddress(&cfg, "10.0.0.8:2901")

if cfg.Publish != "10.0.0.8:2901" {
t.Fatalf("expected concrete runtime publish address to be preserved, got %q", cfg.Publish)
}
}
48 changes: 48 additions & 0 deletions core/api/basic_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,31 @@
package api

import (
"crypto/subtle"
httprouter "infini.sh/framework/core/api/router"
"net/http"
"strings"

"infini.sh/framework/core/model"
configcommon "infini.sh/framework/modules/configs/common"
)

type BasicAuthFilter struct {
Username string
Password string
}

var loadManagedAccessTokenFromKeystore = func() (string, error) {
return configcommon.LoadTokenFromKeystore(configcommon.AgentAccessTokenKeystoreKey)
}

// BasicAuth register api with basic auth
func BasicAuth(h httprouter.Handle, requiredUser, requiredPassword string) httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
if validateManagedAccessToken(r) {
h(w, r, ps)
return
}
// Get the Basic Authentication credentials
user, password, hasAuth := r.BasicAuth()

Expand All @@ -60,6 +73,10 @@ func (filter *BasicAuthFilter) FilterHttpRouter(pattern string, h httprouter.Han

func (filter *BasicAuthFilter) FilterHttpHandlerFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, request *http.Request) {
if validateManagedAccessToken(request) {
handler(w, request)
return
}
// Get the Basic Authentication credentials
user, password, hasAuth := request.BasicAuth()
if hasAuth && user == filter.Username && password == filter.Password {
Expand All @@ -72,3 +89,34 @@ func (filter *BasicAuthFilter) FilterHttpHandlerFunc(pattern string, handler fun
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
}
}

func validateManagedAccessToken(req *http.Request) bool {
tokenValue := ExtractBearerOrAPIToken(req)
if tokenValue == "" {
return false
}
expectedToken, err := loadManagedAccessTokenFromKeystore()
if err != nil || expectedToken == "" {
return false
}
return subtle.ConstantTimeCompare([]byte(expectedToken), []byte(tokenValue)) == 1
}

func ValidateManagedAccessTokenRequest(req *http.Request) bool {
return validateManagedAccessToken(req)
}

func ExtractBearerOrAPIToken(req *http.Request) string {
if req == nil {
return ""
}
tokenValue := strings.TrimSpace(req.Header.Get(model.API_TOKEN))
if tokenValue != "" {
return tokenValue
}
authHeader := strings.TrimSpace(req.Header.Get("Authorization"))
if len(authHeader) < len("Bearer ")+1 || !strings.EqualFold(authHeader[:len("Bearer ")], "Bearer ") {
return ""
}
return strings.TrimSpace(authHeader[len("Bearer "):])
}
Loading