Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

A free and open-source forge that lives in your Git repo.

Harden sign-in input bounds and private response caching

25343521418945b250da2fb29d27cffe34ee2a6e · Keenan Nemetz · 3d ago · parent b492b557

Harden sign-in input bounds and private response caching

Bound the account name in LoginBegin before it reaches the per-account rate
limiter or the ceremony store, and bound the passkey label and the credential
fields copied from an authenticator. Rate-limit keys are capped by hashing a
long value, forwarding headers used as addresses are capped, and expired limiter
entries are swept as the table grows.

Mark downloads and rendered pages private unless the repository is readable
anonymously. A private repository's artifact, archive, run artifact, raw file,
and HTML pages previously either carried a public cache directive or no
directive at all, so a shared cache could serve them to an anonymous reader.

Refs #209 (01M6S78Y7EQY596Y9TQRSNRVSE).
Refs #210 (01M6S7936QAYM9TMSCXCYP2CF9).

server/web/web.go +18

@@ -180,6 +180,12 @@ func (w *Web) serverError(rw http.ResponseWriter, r *http.Request, detail string
180 180 }
181 181
182 182 func (w *Web) render(rw http.ResponseWriter, name string, data any, status int) {
183 // Pages are rendered for the viewer who asked for them. Only the explicit
184 // no-store pages set their own directive; everything else is private and
185 // revalidated, so a shared cache cannot hand one account's page to another.
186 if rw.Header().Get("Cache-Control") == "" {
187 rw.Header().Set("Cache-Control", "private, no-cache")
188 }
183 189 // Render into a buffer first. html/template stops at the first execution error
184 190 // and keeps everything it already wrote, which used to leave a page that looked
185 191 // complete up to the row that failed and silently dropped the rest. A failed
@@ -209,3 +215,15 @@ func (w *Web) open(rw http.ResponseWriter, r *http.Request) (*repo.Meta, bool) {
209 215 }
210 216 return m, true
211 217 }
218
219 // downloadCacheControl is the Cache-Control for bytes that belong to m. A shared
220 // cache may keep what an anonymous reader could fetch; it may not keep a private
221 // repository's artifact or archive just because the current request happens to
222 // be authenticated.
223 func (w *Web) downloadCacheControl(m *repo.Meta) string {
224 acl, err := m.ACL()
225 if err == nil && acl.Can("", access.Read) {
226 return "public, max-age=300"
227 }
228 return "private, no-store"
229 }