// SPDX-License-Identifier: AGPL-3.0-or-later package web import ( "fmt" "net/http" "net/http/httptest" "net/url" "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "bnema.dev/ermite/internal/domain" "bnema.dev/ermite/internal/ports" "bnema.dev/ermite/internal/ports/mocks" ) type formRig struct { *issueRig form *mocks.IssueSubmissionService } func newFormRig(t *testing.T, mode domain.IssuesMode) *formRig { t.Helper() r := &formRig{issueRig: &issueRig{issues: mocks.NewIssueService(t), mrs: mocks.NewMergeRequestService(t)}, form: mocks.NewIssueSubmissionService(t)} browse := mocks.NewBrowseService(t) browse.EXPECT().ListRefs(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(ports.RefPage{}, nil).Maybe() r.mrs.EXPECT().CountOpen(mock.Anything, mock.Anything, mock.Anything).Return(0, nil).Maybe() r.srv = newTestServer(t, Config{ Repos: reposServing(t, issueRepoView(t, mode)), Browse: browse, MergeRequests: r.mrs, Issues: r.issues, IssueForm: r.form, Sessions: newSessions(t, "tok"), Limiter: &countingLimiter{}, }) return r } func challenge(n int) ports.IssueChallenge { return ports.IssueChallenge{ Token: fmt.Sprintf("tok-%d.sig", n), Nonce: "AAECAwQFBgcICQoLDA0ODw", Difficulty: 18, FormToken: fmt.Sprintf("form-%d", n), IssuedAt: time.UnixMilli(1_700_000_000_000), MinSubmitAt: time.UnixMilli(1_700_000_003_000), ExpiresAt: time.UnixMilli(1_700_000_600_000), } } // post sends a submission as a browser of this site would. func (r *formRig) post(path string, hdr map[string]string, body string) *httptest.ResponseRecorder { req := httptest.NewRequest(http.MethodPost, path, strings.NewReader(body)) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") for k, v := range hdr { req.Header.Set(k, v) } rec := httptest.NewRecorder() r.srv.ServeHTTP(rec, req) return rec } var fromSite = map[string]string{"Origin": testPublicURL} func goodForm() url.Values { return url.Values{"title": {"It crashes"}, "body": {"line1\r\nline2"}, "author": {"Alex"}, "token": {"tok-1.sig"}, "form_token": {"form-1"}, "solution": {"42"}, "website": {""}} } func TestIssueFormGet(t *testing.T) { t.Parallel() r := newFormRig(t, domain.IssuesPublic) r.form.EXPECT().Challenge(mock.Anything, repoName(t, "proj"), mock.Anything).Return(challenge(1), nil).Once() rec := r.do("GET", "/proj/issues/new", false, nil) require.Equal(t, 200, rec.Code, rec.Body.String()) assert.Equal(t, "no-store", rec.Header().Get("Cache-Control")) body := rec.Body.String() for _, want := range []string{ `")] assert.NotContains(t, noscript, "