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.
Allow opt-in open registration
f920a9f12c4ff12e4f47497a084f0201d8914181 · Keenan Nemetz · 15d ago · parent 6c84d387
Allow opt-in open registration Add open_registration, off by default and effective only with an HTTPS public_url. /register creates an account and its first passkey without an administrator; the account row is written only after the WebAuthn ceremony succeeds, so an abandoned registration reserves no name. New accounts start with no repository-specific ACL entries. Add self-service SSH key management on the Account page so a registered contributor can add the key needed to push to their contributor namespace. Cover registration enablement, name validation, deferred account creation, and self-service key add/remove in tests, and document the policy.
server/server.go +7
| @@ -99,6 +99,8 @@ func New(cfg *config.Config, binPath string, log *slog.Logger) (*Server, error) | |||
| 99 | 99 | wp.Logger = func(format string, args ...any) { log.Warn(fmt.Sprintf(format, args...)) } | |
| 100 | 100 | if wp.Auth != nil && !wp.Auth.Enabled() { | |
| 101 | 101 | log.Info("browser login disabled", "reason", wp.Auth.Disabled) | |
| 102 | } else if cfg.OpenRegistration { | ||
| 103 | log.Info("open registration enabled", "url", cfg.BaseURL()+"/register") | ||
| 102 | 104 | } | |
| 103 | 105 | ||
| 104 | 106 | s := &Server{ | |
| @@ -139,6 +141,9 @@ func (s *Server) routes() *http.ServeMux { | |||
| 139 | 141 | ||
| 140 | 142 | mux.HandleFunc("GET /{$}", w.IndexPage) | |
| 141 | 143 | mux.HandleFunc("GET /login", w.LoginPage) | |
| 144 | mux.HandleFunc("GET /register", w.RegisterPage) | ||
| 145 | mux.HandleFunc("POST /auth/register/begin", w.RegisterBegin) | ||
| 146 | mux.HandleFunc("POST /auth/register/finish", w.RegisterFinish) | ||
| 142 | 147 | mux.HandleFunc("POST /auth/login/begin", w.LoginBegin) | |
| 143 | 148 | mux.HandleFunc("POST /auth/login/finish", w.LoginFinish) | |
| 144 | 149 | mux.HandleFunc("POST /logout", w.Logout) | |
| @@ -146,6 +151,8 @@ func (s *Server) routes() *http.ServeMux { | |||
| 146 | 151 | mux.HandleFunc("POST /auth/invite/begin", w.InviteBegin) | |
| 147 | 152 | mux.HandleFunc("POST /auth/invite/finish", w.InviteFinish) | |
| 148 | 153 | mux.HandleFunc("GET /account", w.AccountPage) | |
| 154 | mux.HandleFunc("POST /account/keys", w.AddAccountKey) | ||
| 155 | mux.HandleFunc("POST /account/keys/remove", w.RemoveAccountKey) | ||
| 149 | 156 | mux.HandleFunc("POST /account/passkeys/begin", w.AddPasskeyBegin) | |
| 150 | 157 | mux.HandleFunc("POST /account/passkeys/finish", w.AddPasskeyFinish) | |
| 151 | 158 | mux.HandleFunc("GET /auth.js", w.AuthJS) | |