v2.31.0-dev18 7b9923f

handler_test.go RawHistoryFolder

1package acme
2
3import (
4	"context"
5	"io"
6	"net/http"
7	"net/http/httptest"
8	"testing"
9
10	"github.com/stretchr/testify/assert"
11	"github.com/stretchr/testify/require"
12)
13
14// challengeSvc is a simple map-backed implementation of ChallengeService for testing.
15type challengeSvc map[string]string
16
17func (s challengeSvc) GetHTTP01Challenge(_ context.Context, token string) (string, bool) {
18	keyAuth, ok := s[token]
19	return keyAuth, ok
20}
21
22func newTestServer(t *testing.T, svc ChallengeService) *httptest.Server {
23	t.Helper()
24	server := httptest.NewServer(NewHandler(svc))
25	t.Cleanup(server.Close)
26	return server
27}
28
29func readBody(t *testing.T, resp *http.Response) string {
30	t.Helper()
31	defer resp.Body.Close()
32	body, err := io.ReadAll(resp.Body)
33	require.NoError(t, err)
34	return string(body)
35}
36
37func TestHandlerServesGETChallenge(t *testing.T) {
38	server := newTestServer(t, challengeSvc{"abc": "key-auth"})
39
40	resp, err := http.Get(server.URL + "/.well-known/acme-challenge/abc")
41	require.NoError(t, err)
42
43	assert.Equal(t, http.StatusOK, resp.StatusCode)
44	assert.Equal(t, "text/plain; charset=utf-8", resp.Header.Get("Content-Type"))
45	assert.Equal(t, "no-store", resp.Header.Get("Cache-Control"))
46	assert.Equal(t, "key-auth", readBody(t, resp))
47}
48
49func TestHandlerServesHEADChallenge(t *testing.T) {
50	server := newTestServer(t, challengeSvc{"abc": "key-auth"})
51
52	resp, err := http.Head(server.URL + "/.well-known/acme-challenge/abc")
53	require.NoError(t, err)
54	defer resp.Body.Close()
55
56	assert.Equal(t, http.StatusOK, resp.StatusCode)
57	assert.Equal(t, "text/plain; charset=utf-8", resp.Header.Get("Content-Type"))
58	assert.Equal(t, "no-store", resp.Header.Get("Cache-Control"))
59}
60
61func TestHandlerRejectsUnsafeToken(t *testing.T) {
62	tests := []struct {
63		name string
64		path string
65	}{
66		{name: "path traversal", path: "/.well-known/acme-challenge/../secret"},
67		{name: "slash in token", path: "/.well-known/acme-challenge/foo/bar"},
68		{name: "empty token", path: "/.well-known/acme-challenge/"},
69		{name: "backslash in token", path: "/.well-known/acme-challenge/foo%5Cbar"},
70	}
71
72	for _, tt := range tests {
73		t.Run(tt.name, func(t *testing.T) {
74			server := newTestServer(t, challengeSvc{"abc": "key-auth"})
75			resp, err := http.Get(server.URL + tt.path)
76			require.NoError(t, err)
77			defer resp.Body.Close()
78
79			assert.Equal(t, http.StatusNotFound, resp.StatusCode, "path: %s", tt.path)
80		})
81	}
82}
83
84func TestHandlerRejectsPOST(t *testing.T) {
85	server := newTestServer(t, challengeSvc{"abc": "key-auth"})
86
87	resp, err := http.Post(server.URL+"/.well-known/acme-challenge/abc", "text/plain", nil)
88	require.NoError(t, err)
89	defer resp.Body.Close()
90
91	assert.Equal(t, http.StatusMethodNotAllowed, resp.StatusCode)
92	assert.Equal(t, "GET, HEAD", resp.Header.Get("Allow"))
93}
94
95func TestHandlerRejectsMissingPrefix(t *testing.T) {
96	server := newTestServer(t, challengeSvc{"abc": "key-auth"})
97
98	resp, err := http.Get(server.URL + "/some-other-path")
99	require.NoError(t, err)
100	defer resp.Body.Close()
101
102	assert.Equal(t, http.StatusNotFound, resp.StatusCode)
103}
104
105func TestHandlerRejectsUnknownToken(t *testing.T) {
106	server := newTestServer(t, challengeSvc{"abc": "key-auth"})
107
108	resp, err := http.Get(server.URL + "/.well-known/acme-challenge/unknown")
109	require.NoError(t, err)
110	defer resp.Body.Close()
111
112	assert.Equal(t, http.StatusNotFound, resp.StatusCode)
113}
114
115func TestHandlerRejectsNilService(t *testing.T) {
116	server := newTestServer(t, nil)
117
118	resp, err := http.Get(server.URL + "/.well-known/acme-challenge/abc")
119	require.NoError(t, err)
120	defer resp.Body.Close()
121
122	assert.Equal(t, http.StatusNotFound, resp.StatusCode)
123}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close