v0.9.0 e5e4ded

proxy_test.go RawHistoryFolder

1package webterm
2
3import (
4	"context"
5	"net/http"
6	"net/http/httptest"
7	"net/url"
8	"strings"
9	"testing"
10	"time"
11
12	"github.com/coder/websocket"
13	"github.com/stretchr/testify/require"
14)
15
16func TestWebProxyTrustBoundary(t *testing.T) {
17	for _, scheme := range []string{"http", "https"} {
18		t.Run(scheme, func(t *testing.T) {
19			settings, err := ParseSettings("", scheme+"://terminal.example.internal")
20			require.NoError(t, err)
21			token := strings.Repeat("f", 43)
22			handler, err := NewServer(t.Context(), settings, token, func(context.Context, *Terminal) error { return nil })
23			require.NoError(t, err)
24			for _, tt := range []struct {
25				name, host, origin string
26				want               int
27			}{
28				{"valid", settings.Host(), settings.Origin, 204},
29				{"upstream host", Address, settings.Origin, 403},
30				{"foreign host", "attacker.invalid", settings.Origin, 403},
31				{"foreign origin", settings.Host(), "https://attacker.invalid", 403},
32				{"missing origin", settings.Host(), "", 403},
33			} {
34				t.Run(tt.name, func(t *testing.T) {
35					r := httptest.NewRequest("POST", "http://"+Address+"/login", strings.NewReader(url.Values{"token": {token}}.Encode()))
36					r.Host = tt.host
37					r.Header.Set("Origin", tt.origin)
38					r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
39					r.Header.Set("X-Forwarded-Host", settings.Host())
40					r.Header.Set("X-Forwarded-Proto", "https")
41					w := httptest.NewRecorder()
42					handler.ServeHTTP(w, r)
43					require.Equal(t, tt.want, w.Code)
44					if tt.want == 204 {
45						cookies := w.Result().Cookies()
46						require.Len(t, cookies, 1)
47						require.Equal(t, scheme == "https", cookies[0].Secure)
48						require.True(t, cookies[0].HttpOnly)
49						require.Equal(t, http.SameSiteStrictMode, cookies[0].SameSite)
50					} else {
51						require.Empty(t, w.Result().Cookies())
52					}
53				})
54			}
55		})
56	}
57}
58
59func TestWebProxyWebSocket(t *testing.T) {
60	ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second)
61	defer cancel()
62	settings, err := ParseSettings("", "https://terminal.example.internal")
63	require.NoError(t, err)
64	token := strings.Repeat("g", 43)
65	handler, err := NewServer(ctx, settings, token, func(ctx context.Context, terminal *Terminal) error {
66		<-ctx.Done()
67		return ctx.Err()
68	})
69	require.NoError(t, err)
70	// Model a proxy that preserves the browser-facing Host on HTTP upstream.
71	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
72		r.Host = settings.Host()
73		handler.ServeHTTP(w, r)
74	}))
75	defer server.Close()
76	headers := http.Header{"Origin": {settings.Origin}, "Cookie": {cookieName + "=" + token}}
77	conn, _, err := websocket.Dial(ctx, server.URL+"/ws", &websocket.DialOptions{HTTPHeader: headers})
78	require.NoError(t, err)
79	conn.CloseNow()
80	cancel()
81	handler.Wait()
82}

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 12

Tags 11

↑↓ moveenter openesc close