Skip to content

Commit 335d037

Browse files
committed
security fixes
1 parent f9d50ca commit 335d037

8 files changed

Lines changed: 40 additions & 24 deletions

File tree

charts/keepup/Chart.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
apiVersion: v1
22
name: keepup
3-
version: 1.3.4
4-
appVersion: 1.2.0
3+
version: 1.4.0
4+
appVersion: 1.3.0

charts/keepup/values.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ main:
77

88
redis:
99
enabled: true
10-
image: "redis:8.2.3"
10+
image: "redis:8.2.5"
1111
pullPolicy: "IfNotPresent"
1212

1313
ingress:

docker/Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
FROM golang:1.25.5-trixie AS builder
2-
ARG BUILD_VERSION='v1.2.3'
1+
FROM golang:1.25.9-trixie AS builder
2+
ARG BUILD_VERSION='v1.3.0'
33
ENV LISTEN_PORT=9101
44
WORKDIR /opt/keepup/
55
COPY go.mod ./

src/config/config.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ func init() {
4646
numFields := refl.NumField()
4747
for i := 0; i < numFields; i++ {
4848
envName := refl.Type().Field(i).Name
49-
envVal, foud := os.LookupEnv(envName)
50-
if !foud {
49+
envVal, found := os.LookupEnv(envName)
50+
if !found {
5151
panic("Environment [" + envName + "] not found.")
5252
}
5353
refl.Field(i).SetString(envVal)

src/handler/middleware.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package handler
22

33
import (
44
"context"
5+
"crypto/subtle"
56
"encoding/json"
67
"io"
78
"log"
@@ -67,7 +68,7 @@ type IDClusterDocument struct {
6768

6869
func (s *OsReleasesMiddleware) HandleOsRelease(w http.ResponseWriter, r *http.Request) {
6970
token := r.Header.Get("x-api-token")
70-
if token != s.ApiToken {
71+
if subtle.ConstantTimeCompare([]byte(token), []byte(s.ApiToken)) != 1 {
7172
w.Header().Set("Content-Type", "text/plain")
7273
w.WriteHeader(http.StatusForbidden)
7374
io.WriteString(w, "FORBIDDEN")
@@ -87,6 +88,7 @@ func (s *OsReleasesMiddleware) HandleOsRelease(w http.ResponseWriter, r *http.Re
8788
func (s *OsReleasesMiddleware) handleInsert(w http.ResponseWriter, r *http.Request) {
8889
var req ReleaseDocument
8990
var res IDDocument
91+
r.Body = http.MaxBytesReader(w, r.Body, 1<<20)
9092
err := json.NewDecoder(r.Body).Decode(&req)
9193
if err != nil {
9294
http.Error(w, err.Error(), http.StatusBadRequest)
@@ -108,6 +110,7 @@ func (s *OsReleasesMiddleware) handleInsert(w http.ResponseWriter, r *http.Reque
108110

109111
func (s *OsReleasesMiddleware) handleGetByID(w http.ResponseWriter, r *http.Request) {
110112
var req IDDocument
113+
r.Body = http.MaxBytesReader(w, r.Body, 1<<20)
111114
err := json.NewDecoder(r.Body).Decode(&req)
112115
if err != nil {
113116
http.Error(w, err.Error(), http.StatusBadRequest)
@@ -161,6 +164,7 @@ func (p *PackageVersionsHandler) handleInsertPackages(w http.ResponseWriter, r *
161164
var req PackageDocument
162165
var res IDDocumentPackage
163166

167+
r.Body = http.MaxBytesReader(w, r.Body, 1<<20)
164168
err := json.NewDecoder(r.Body).Decode(&req)
165169
if err != nil {
166170
http.Error(w, "Invalid request payload", http.StatusBadRequest)
@@ -210,6 +214,7 @@ func (p *PackageVersionsHandler) handleInsertPackages(w http.ResponseWriter, r *
210214
func (p *PackageVersionsHandler) handleGetPackages(w http.ResponseWriter, r *http.Request) {
211215
var req IDDocumentPackage
212216

217+
r.Body = http.MaxBytesReader(w, r.Body, 1<<20)
213218
err := json.NewDecoder(r.Body).Decode(&req)
214219
if err != nil {
215220
http.Error(w, err.Error(), http.StatusBadRequest)
@@ -238,7 +243,7 @@ func (p *PackageVersionsHandler) handleGetPackages(w http.ResponseWriter, r *htt
238243

239244
func (s *PackageVersionsHandler) HandlePackage(w http.ResponseWriter, r *http.Request) {
240245
token := r.Header.Get("x-api-token")
241-
if token != s.ApiToken {
246+
if subtle.ConstantTimeCompare([]byte(token), []byte(s.ApiToken)) != 1 {
242247
w.Header().Set("Content-Type", "text/plain")
243248
w.WriteHeader(http.StatusForbidden)
244249
io.WriteString(w, "FORBIDDEN")
@@ -259,7 +264,7 @@ func (s *PackageVersionsHandler) HandlePackage(w http.ResponseWriter, r *http.Re
259264
// Simplife new endpoint handling logic. Maybe define common handler for all endpoints.
260265
func (s *KubernetesClusterMiddleware) HandleKubernetesCluster(w http.ResponseWriter, r *http.Request) {
261266
token := r.Header.Get("x-api-token")
262-
if token != s.ApiToken {
267+
if subtle.ConstantTimeCompare([]byte(token), []byte(s.ApiToken)) != 1 {
263268
http.Error(w, "FORBIDDEN", http.StatusForbidden)
264269
return
265270
}

src/handler/osrelease.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ type OsReleases struct {
2929

3030
var (
3131
ErrInsertFailed = errors.New("Insert failed")
32-
ErrMarshlFailed = errors.New("Marshal failed")
32+
ErrMarshalFailed = errors.New("Marshal failed")
3333
ErrIDNotFound = errors.New("Id not found")
3434
ErrNoKeysFound = errors.New("No keys found")
3535
)
@@ -39,7 +39,7 @@ func (c *OsReleases) Insert(rel OsRelease, ctx context.Context, con *redis.Clien
3939
rel.UpdatedAt = fmt.Sprint(time.Now().Unix())
4040
srt, err := json.Marshal(rel)
4141
if err != nil {
42-
return rel.ID, ErrMarshlFailed
42+
return rel.ID, ErrMarshalFailed
4343
}
4444
result, err := con.Set(ctx, fmt.Sprint(rel.ID), srt, time.Duration(ttl)*time.Second).Result()
4545
if err != nil {
@@ -78,7 +78,8 @@ func (c *OsReleases) Scan(ctx context.Context, con *redis.Client) (OsReleases, e
7878
}
7979
}
8080
if err := iter.Err(); err != nil {
81-
panic(err)
81+
log.Printf("Error scanning Redis keys: %v", err)
82+
return rels, err
8283
}
8384
return rels, nil
8485
}

src/handler/packageversions.go

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -216,21 +216,13 @@ func updateEOLCache(ctx context.Context, con *redis.Client) error {
216216
"package": map[string][]EndOfLifeEntry{},
217217
}
218218

219+
httpClient := &http.Client{Timeout: 10 * time.Second}
219220
for _, packageName := range supportedPackages {
220221
apiURL := fmt.Sprintf("https://endoflife.date/api/%s.json", packageName)
221-
httpClient := &http.Client{Timeout: 10 * time.Second}
222-
223-
resp, err := httpClient.Get(apiURL)
222+
entries, err := fetchEOLEntries(httpClient, apiURL)
224223
if err != nil {
225224
continue
226225
}
227-
defer resp.Body.Close()
228-
229-
var entries []EndOfLifeEntry
230-
if err := json.NewDecoder(resp.Body).Decode(&entries); err != nil {
231-
continue
232-
}
233-
234226
cacheDocument["package"].(map[string][]EndOfLifeEntry)[packageName] = entries
235227
}
236228

@@ -247,6 +239,20 @@ func updateEOLCache(ctx context.Context, con *redis.Client) error {
247239
return nil
248240
}
249241

242+
func fetchEOLEntries(client *http.Client, url string) ([]EndOfLifeEntry, error) {
243+
resp, err := client.Get(url)
244+
if err != nil {
245+
return nil, err
246+
}
247+
defer resp.Body.Close()
248+
249+
var entries []EndOfLifeEntry
250+
if err := json.NewDecoder(resp.Body).Decode(&entries); err != nil {
251+
return nil, err
252+
}
253+
return entries, nil
254+
}
255+
250256
func getEOLData(ctx context.Context, con *redis.Client, packageName string) ([]EndOfLifeEntry, error) {
251257
key := "eol_cache:all_packages"
252258

src/main.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"strconv"
1414
"sync"
1515
"syscall"
16+
"time"
1617

1718
"github.com/google/uuid"
1819
"github.com/prometheus/client_golang/prometheus"
@@ -104,7 +105,10 @@ func main() {
104105
func configureServer() {
105106
log.Printf("Creating server on port %s.", config.GetConfig().LISTEN_PORT)
106107
server = &http.Server{
107-
Addr: fmt.Sprintf(":%s", config.GetConfig().LISTEN_PORT),
108+
Addr: fmt.Sprintf(":%s", config.GetConfig().LISTEN_PORT),
109+
ReadTimeout: 10 * time.Second,
110+
WriteTimeout: 30 * time.Second,
111+
IdleTimeout: 60 * time.Second,
108112
}
109113
server.RegisterOnShutdown(func() {
110114
log.Println("Shutting down server.")

0 commit comments

Comments
 (0)