• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

gameap / gameap / 19686361200

25 Nov 2025 10:44PM UTC coverage: 61.858% (-0.03%) from 61.887%
19686361200

push

github

et-nik
bugfixes and changes

2 of 26 new or added lines in 4 files covered. (7.69%)

2 existing lines in 1 file now uncovered.

24768 of 40040 relevant lines covered (61.86%)

328.57 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.74
/internal/api/filemanager/content/handler.go
1
package content
2

3
import (
4
        "context"
5
        "net/http"
6
        "path/filepath"
7
        "strings"
8

9
        "github.com/gameap/gameap/internal/api/base"
10
        serversbase "github.com/gameap/gameap/internal/api/servers/base"
11
        "github.com/gameap/gameap/internal/daemon"
12
        "github.com/gameap/gameap/internal/domain"
13
        "github.com/gameap/gameap/internal/filters"
14
        "github.com/gameap/gameap/internal/repositories"
15
        "github.com/gameap/gameap/pkg/api"
16
        "github.com/gameap/gameap/pkg/auth"
17
        "github.com/pkg/errors"
18
)
19

20
type fileService interface {
21
        ReadDir(ctx context.Context, node *domain.Node, directory string) ([]*daemon.FileInfo, error)
22
}
23

24
type Handler struct {
25
        serverFinder   *serversbase.ServerFinder
26
        abilityChecker *serversbase.AbilityChecker
27
        nodeRepo       repositories.NodeRepository
28
        daemonFiles    fileService
29
        responder      base.Responder
30
}
31

32
func NewHandler(
33
        serverRepo repositories.ServerRepository,
34
        nodeRepo repositories.NodeRepository,
35
        rbac base.RBAC,
36
        daemonFiles fileService,
37
        responder base.Responder,
38
) *Handler {
14✔
39
        return &Handler{
14✔
40
                serverFinder:   serversbase.NewServerFinder(serverRepo, rbac),
14✔
41
                abilityChecker: serversbase.NewAbilityChecker(rbac),
14✔
42
                nodeRepo:       nodeRepo,
14✔
43
                daemonFiles:    daemonFiles,
14✔
44
                responder:      responder,
14✔
45
        }
14✔
46
}
14✔
47

48
func (h *Handler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
14✔
49
        ctx := r.Context()
14✔
50

14✔
51
        session := auth.SessionFromContext(ctx)
14✔
52
        if !session.IsAuthenticated() {
15✔
53
                h.responder.WriteError(ctx, rw, api.WrapHTTPError(
1✔
54
                        errors.New("user not authenticated"),
1✔
55
                        http.StatusUnauthorized,
1✔
56
                ))
1✔
57

1✔
58
                return
1✔
59
        }
1✔
60

61
        input := api.NewInputReader(r)
13✔
62

13✔
63
        serverID, err := input.ReadUint("server")
13✔
64
        if err != nil {
14✔
65
                h.responder.WriteError(ctx, rw, api.WrapHTTPError(
1✔
66
                        errors.WithMessage(err, "invalid server id"),
1✔
67
                        http.StatusBadRequest,
1✔
68
                ))
1✔
69

1✔
70
                return
1✔
71
        }
1✔
72

73
        server, err := h.serverFinder.FindUserServer(ctx, session.User, serverID)
12✔
74
        if err != nil {
14✔
75
                h.responder.WriteError(ctx, rw, err)
2✔
76

2✔
77
                return
2✔
78
        }
2✔
79

80
        err = h.abilityChecker.CheckOrError(
10✔
81
                ctx,
10✔
82
                session.User.ID,
10✔
83
                server.ID,
10✔
84
                []domain.AbilityName{domain.AbilityNameGameServerFiles},
10✔
85
        )
10✔
86
        if err != nil {
11✔
87
                h.responder.WriteError(ctx, rw, err)
1✔
88

1✔
89
                return
1✔
90
        }
1✔
91

92
        // Read disk parameter
93
        disk := r.URL.Query().Get("disk")
9✔
94
        if disk == "" {
14✔
95
                disk = "server"
5✔
96
        }
5✔
97

98
        // Validate disk parameter - only "server" is supported
99
        if disk != "server" {
10✔
100
                h.responder.WriteError(ctx, rw, api.WrapHTTPError(
1✔
101
                        errors.Errorf("unsupported disk: %s, only 'server' disk is supported", disk),
1✔
102
                        http.StatusBadRequest,
1✔
103
                ))
1✔
104

1✔
105
                return
1✔
106
        }
1✔
107

108
        // Read path parameter
109
        path := r.URL.Query().Get("path")
8✔
110
        if path == "" {
14✔
111
                path = "."
6✔
112
        }
6✔
113

114
        if err = validatePath(path); err != nil {
9✔
115
                h.responder.WriteError(ctx, rw, api.WrapHTTPError(
1✔
116
                        err,
1✔
117
                        http.StatusBadRequest,
1✔
118
                ))
1✔
119

1✔
120
                return
1✔
121
        }
1✔
122

123
        fullPath := filepath.Join(server.Dir, path)
7✔
124

7✔
125
        nodes, err := h.nodeRepo.Find(ctx, &filters.FindNode{
7✔
126
                IDs: []uint{server.DSID},
7✔
127
        }, nil, &filters.Pagination{
7✔
128
                Limit: 1,
7✔
129
        })
7✔
130
        if err != nil {
7✔
131
                h.responder.WriteError(ctx, rw, errors.WithMessage(err, "failed to find node"))
×
132

×
133
                return
×
134
        }
×
135

136
        if len(nodes) == 0 {
8✔
137
                h.responder.WriteError(ctx, rw, api.NewNotFoundError("node not found"))
1✔
138

1✔
139
                return
1✔
140
        }
1✔
141

142
        node := &nodes[0]
6✔
143

6✔
144
        fileInfoList, err := h.daemonFiles.ReadDir(ctx, node, fullPath)
6✔
145
        if err != nil {
6✔
NEW
146
                h.responder.WriteError(ctx, rw, errors.WithMessagef(err, "failed to read directory: %s", fullPath))
×
147

×
148
                return
×
149
        }
×
150

151
        h.responder.Write(ctx, rw, newContentResponse(fileInfoList, path))
6✔
152
}
153

154
func validatePath(path string) error {
20✔
155
        if strings.Contains(path, "..") {
27✔
156
                return errors.New("path contains invalid directory traversal")
7✔
157
        }
7✔
158

159
        cleanPath := filepath.Clean(path)
13✔
160
        if strings.HasPrefix(cleanPath, "..") {
13✔
161
                return errors.New("path attempts to escape base directory")
×
162
        }
×
163

164
        return nil
13✔
165
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc