all repos

rss-tools @ 20e54e6

get rss feed from sources that(i need and) dont provide one
4 files changed, 90 insertions(+), 4 deletions(-)
add auth middleware (at the moment only fixed token)
Author: Oleksandr Smirnov olexsmir@gmail.com
Committed at: 2026-04-22 20:13:38 +0300
Authored at: 2026-04-22 19:52:45 +0300
Change ID: wsuzotwwmmskkuwwnqmnqnxtzqsswyxw
Parent: 4f31c23
M app/app.go
···
        85
        85
         	}

      
        86
        86
         

      
        87
        87
         	// http server

      
        88
        
        -	// TODO: opt in auth middleware

      
        89
        88
         	handler := a.recoverMiddleware(a.mux)

      
        
        89
        +	handler = a.authMiddleware(handler)

      
        90
        90
         	handler = a.loggingMiddleware(handler)

      
        91
        91
         	httpSrv := &http.Server{

      
        92
        92
         		Addr:    fmt.Sprintf(":%d", a.Config.Port), // fixme

      
M app/config.go
···
        6
        6
         )

      
        7
        7
         

      
        8
        8
         type Config struct {

      
        9
        
        -	Port     int    `json:"port"`

      
        10
        
        -	TGUserID int64  `json:"tg_userid"`

      
        11
        
        -	TGToken  string `json:"tg_token"`

      
        
        9
        +	Port      int    `json:"port"`

      
        
        10
        +	AuthToken string `json:"auth_token"`

      
        
        11
        +	TGUserID  int64  `json:"tg_userid"`

      
        
        12
        +	TGToken   string `json:"tg_token"`

      
        12
        13
         }

      
        13
        14
         

      
        14
        15
         func NewConfig(fpath string) (*Config, error) {

      
M app/http.go
···
        3
        3
         import (

      
        4
        4
         	"log/slog"

      
        5
        5
         	"net/http"

      
        
        6
        +	"strings"

      
        6
        7
         	"time"

      
        7
        8
         )

      
        8
        9
         

      ···
        30
        31
         			"latency", time.Since(start).String(),

      
        31
        32
         			"ua", r.UserAgent(),

      
        32
        33
         		)

      
        
        34
        +	})

      
        
        35
        +}

      
        
        36
        +

      
        
        37
        +func (a *App) authMiddleware(next http.Handler) http.Handler {

      
        
        38
        +	if a.Config == nil || strings.TrimSpace(a.Config.AuthToken) == "" {

      
        
        39
        +		return next

      
        
        40
        +	}

      
        
        41
        +

      
        
        42
        +	expected := strings.TrimSpace(a.Config.AuthToken)

      
        
        43
        +	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

      
        
        44
        +		queryToken := strings.TrimSpace(r.URL.Query().Get("token"))

      
        
        45
        +		headerToken := strings.TrimSpace(r.Header.Get("Authorization"))

      
        
        46
        +		if queryToken == expected || headerToken == expected {

      
        
        47
        +			next.ServeHTTP(w, r)

      
        
        48
        +			return

      
        
        49
        +		}

      
        
        50
        +

      
        
        51
        +		http.Error(w, "unauthorized", http.StatusUnauthorized)

      
        33
        52
         	})

      
        34
        53
         }

      
        35
        54
         

      
A app/http_test.go
···
        
        1
        +package app

      
        
        2
        +

      
        
        3
        +import (

      
        
        4
        +	"net/http"

      
        
        5
        +	"net/http/httptest"

      
        
        6
        +	"strings"

      
        
        7
        +	"testing"

      
        
        8
        +

      
        
        9
        +	"olexsmir.xyz/x/is"

      
        
        10
        +)

      
        
        11
        +

      
        
        12
        +func TestAuthMiddlewareDisabledWithoutToken(t *testing.T) {

      
        
        13
        +	a := &App{Config: &Config{}}

      
        
        14
        +	handler := a.authMiddleware(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {

      
        
        15
        +		w.WriteHeader(http.StatusNoContent)

      
        
        16
        +	}))

      
        
        17
        +

      
        
        18
        +	r := httptest.NewRequest(http.MethodGet, "/telegram", nil)

      
        
        19
        +	w := httptest.NewRecorder()

      
        
        20
        +	handler.ServeHTTP(w, r)

      
        
        21
        +

      
        
        22
        +	is.Equal(t, http.StatusNoContent, w.Code)

      
        
        23
        +}

      
        
        24
        +

      
        
        25
        +func TestAuthMiddlewareAllowsQueryToken(t *testing.T) {

      
        
        26
        +	a := &App{Config: &Config{AuthToken: "secret"}}

      
        
        27
        +	handler := a.authMiddleware(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {

      
        
        28
        +		w.WriteHeader(http.StatusNoContent)

      
        
        29
        +	}))

      
        
        30
        +

      
        
        31
        +	r := httptest.NewRequest(http.MethodGet, "/telegram?token=secret", nil)

      
        
        32
        +	w := httptest.NewRecorder()

      
        
        33
        +	handler.ServeHTTP(w, r)

      
        
        34
        +

      
        
        35
        +	is.Equal(t, http.StatusNoContent, w.Code)

      
        
        36
        +}

      
        
        37
        +

      
        
        38
        +func TestAuthMiddlewareAllowsAuthorizationHeader(t *testing.T) {

      
        
        39
        +	a := &App{Config: &Config{AuthToken: "secret"}}

      
        
        40
        +	handler := a.authMiddleware(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {

      
        
        41
        +		w.WriteHeader(http.StatusNoContent)

      
        
        42
        +	}))

      
        
        43
        +

      
        
        44
        +	r := httptest.NewRequest(http.MethodGet, "/telegram", nil)

      
        
        45
        +	r.Header.Set("Authorization", "secret")

      
        
        46
        +	w := httptest.NewRecorder()

      
        
        47
        +	handler.ServeHTTP(w, r)

      
        
        48
        +

      
        
        49
        +	is.Equal(t, http.StatusNoContent, w.Code)

      
        
        50
        +}

      
        
        51
        +

      
        
        52
        +func TestAuthMiddlewareRejectsBadToken(t *testing.T) {

      
        
        53
        +	a := &App{Config: &Config{AuthToken: "secret"}}

      
        
        54
        +	handler := a.authMiddleware(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {

      
        
        55
        +		w.WriteHeader(http.StatusNoContent)

      
        
        56
        +	}))

      
        
        57
        +

      
        
        58
        +	r := httptest.NewRequest(http.MethodGet, "/telegram?token=bad", nil)

      
        
        59
        +	w := httptest.NewRecorder()

      
        
        60
        +	handler.ServeHTTP(w, r)

      
        
        61
        +

      
        
        62
        +	is.Equal(t, http.StatusUnauthorized, w.Code)

      
        
        63
        +	if !strings.Contains(w.Body.String(), "unauthorized") {

      
        
        64
        +		t.Fatalf("unexpected body: %q", w.Body.String())

      
        
        65
        +	}

      
        
        66
        +}