From 634c8321efae97c9bff8ebba2db82faee0210741 Mon Sep 17 00:00:00 2001 From: bagas Date: Wed, 21 Jan 2026 22:11:24 +0700 Subject: [PATCH] refactor(registry): define reusable constant errors - Introduced package-level error variables in registry to replace repeated fmt.Errorf calls - Added errors like ErrSessionNotFound, ErrSlugInUse, ErrInvalidSlug, ErrForbiddenSlug, ErrSlugChangeNotAllowed, and ErrSlugUnchanged --- internal/registry/registry.go | 27 ++++++++++++++++++--------- internal/transport/httphandler.go | 8 ++++---- internal/transport/tls.go | 2 +- session/interaction/slug.go | 4 ++-- session/session.go | 2 +- types/types.go | 2 +- 6 files changed, 27 insertions(+), 18 deletions(-) diff --git a/internal/registry/registry.go b/internal/registry/registry.go index 86898b0..89cac48 100644 --- a/internal/registry/registry.go +++ b/internal/registry/registry.go @@ -34,6 +34,15 @@ type registry struct { slugIndex map[Key]string } +var ( + ErrSessionNotFound = fmt.Errorf("session not found") + ErrSlugInUse = fmt.Errorf("slug already in use") + ErrInvalidSlug = fmt.Errorf("invalid slug") + ErrForbiddenSlug = fmt.Errorf("forbidden slug") + ErrSlugChangeNotAllowed = fmt.Errorf("slug change not allowed for this tunnel type") + ErrSlugUnchanged = fmt.Errorf("slug is unchanged") +) + func NewRegistry() Registry { return ®istry{ byUser: make(map[string]map[Key]Session), @@ -47,12 +56,12 @@ func (r *registry) Get(key Key) (session Session, err error) { userID, ok := r.slugIndex[key] if !ok { - return nil, fmt.Errorf("session not found") + return nil, ErrSessionNotFound } client, ok := r.byUser[userID][key] if !ok { - return nil, fmt.Errorf("session not found") + return nil, ErrSessionNotFound } return client, nil } @@ -63,37 +72,37 @@ func (r *registry) GetWithUser(user string, key Key) (session Session, err error client, ok := r.byUser[user][key] if !ok { - return nil, fmt.Errorf("session not found") + return nil, ErrSessionNotFound } return client, nil } func (r *registry) Update(user string, oldKey, newKey Key) error { if oldKey.Type != newKey.Type { - return fmt.Errorf("tunnel type cannot change") + return ErrSlugUnchanged } if newKey.Type != types.TunnelTypeHTTP { - return fmt.Errorf("non http tunnel cannot change slug") + return ErrSlugChangeNotAllowed } if isForbiddenSlug(newKey.Id) { - return fmt.Errorf("this subdomain is reserved. Please choose a different one") + return ErrForbiddenSlug } if !isValidSlug(newKey.Id) { - return fmt.Errorf("invalid subdomain. Follow the rules") + return ErrInvalidSlug } r.mu.Lock() defer r.mu.Unlock() if _, exists := r.slugIndex[newKey]; exists && newKey != oldKey { - return fmt.Errorf("someone already uses this subdomain") + return ErrSlugInUse } client, ok := r.byUser[user][oldKey] if !ok { - return fmt.Errorf("session not found") + return ErrSessionNotFound } delete(r.byUser[user], oldKey) diff --git a/internal/transport/httphandler.go b/internal/transport/httphandler.go index b6f128d..8bab4a0 100644 --- a/internal/transport/httphandler.go +++ b/internal/transport/httphandler.go @@ -34,7 +34,7 @@ func newHTTPHandler(domain string, sessionRegistry registry.Registry, redirectTL } func (hh *httpHandler) redirect(conn net.Conn, status int, location string) error { - _, err := conn.Write([]byte(fmt.Sprintf("TunnelTypeHTTP/1.1 %d Moved Permanently\r\n", status) + + _, err := conn.Write([]byte(fmt.Sprintf("HTTP/1.1 %d Moved Permanently\r\n", status) + fmt.Sprintf("Location: %s", location) + "Content-Length: 0\r\n" + "Connection: close\r\n" + @@ -46,7 +46,7 @@ func (hh *httpHandler) redirect(conn net.Conn, status int, location string) erro } func (hh *httpHandler) badRequest(conn net.Conn) error { - if _, err := conn.Write([]byte("TunnelTypeHTTP/1.1 400 Bad Request\r\n\r\n")); err != nil { + if _, err := conn.Write([]byte("HTTP/1.1 400 Bad Request\r\n\r\n")); err != nil { return err } return nil @@ -87,7 +87,7 @@ func (hh *httpHandler) handler(conn net.Conn, isTLS bool) { defer func(hw stream.HTTP) { err = hw.Close() if err != nil { - log.Printf("Error closing TunnelTypeHTTP stream: %v", err) + log.Printf("Error closing HTTP stream: %v", err) } }(hw) hh.forwardRequest(hw, reqhf, sshSession) @@ -118,7 +118,7 @@ func (hh *httpHandler) handlePingRequest(slug string, conn net.Conn) bool { } _, err := conn.Write([]byte( - "TunnelTypeHTTP/1.1 200 OK\r\n" + + "HTTP/1.1 200 OK\r\n" + "Content-Length: 0\r\n" + "Connection: close\r\n" + "Access-Control-Allow-Origin: *\r\n" + diff --git a/internal/transport/tls.go b/internal/transport/tls.go index 6824a54..877afb4 100644 --- a/internal/transport/tls.go +++ b/internal/transport/tls.go @@ -67,7 +67,7 @@ func NewTLSConfig(config config.Config) (*tls.Config, error) { tm.useCertMagic = false tm.startCertWatcher() } else { - log.Printf("User certificates missing or don't cover %s and *.%s, using CertMagic", config.Domain, config.Domain) + log.Printf("User certificates missing or don't cover %s and *.%s, using CertMagic", config.Domain(), config.Domain()) if err := tm.initCertMagic(); err != nil { initErr = fmt.Errorf("failed to initialize CertMagic: %w", err) return diff --git a/session/interaction/slug.go b/session/interaction/slug.go index 08c7c7d..2b871d4 100644 --- a/session/interaction/slug.go +++ b/session/interaction/slug.go @@ -145,9 +145,9 @@ func (m *model) slugView() string { var warningText string if isVeryCompact { - warningText = "⚠️ TunnelTypeTCP tunnels don't support custom subdomains." + warningText = "⚠️ TCP tunnels don't support custom subdomains." } else { - warningText = "⚠️ TunnelTypeTCP tunnels cannot have custom subdomains. Only TunnelTypeHTTP/HTTPS tunnels support subdomain customization." + warningText = "⚠️ TCP tunnels cannot have custom subdomains. Only HTTP/HTTPS tunnels support subdomain customization." } b.WriteString(warningBoxStyle.Render(warningText)) b.WriteString("\n\n") diff --git a/session/session.go b/session/session.go index 65bbc54..b1895ab 100644 --- a/session/session.go +++ b/session/session.go @@ -160,7 +160,7 @@ func (s *session) setupInteractiveMode(channel ssh.NewChannel) error { } func (s *session) handleMissingForwardRequest() error { - err := s.interaction.Send(fmt.Sprintf("PortRegistry forwarding request not received. Ensure you ran the correct command with -R flag. Example: ssh %s -p %s -R 80:localhost:3000", s.config.Domain, s.config.SSHPort)) + err := s.interaction.Send(fmt.Sprintf("PortRegistry forwarding request not received. Ensure you ran the correct command with -R flag. Example: ssh %s -p %s -R 80:localhost:3000", s.config.Domain(), s.config.SSHPort())) if err != nil { return err } diff --git a/types/types.go b/types/types.go index 8e7d1e5..34ccfb4 100644 --- a/types/types.go +++ b/types/types.go @@ -44,7 +44,7 @@ type Detail struct { StartedAt time.Time `json:"started_at,omitempty"` } -var BadGatewayResponse = []byte("TunnelTypeHTTP/1.1 502 Bad Gateway\r\n" + +var BadGatewayResponse = []byte("HTTP/1.1 502 Bad Gateway\r\n" + "Content-Length: 11\r\n" + "Content-Type: text/plain\r\n\r\n" + "Bad Gateway")