feat/restructure #73

Merged
bagas merged 4 commits from feat/restructure into staging 2026-01-22 00:48:40 +07:00
6 changed files with 27 additions and 18 deletions
Showing only changes of commit 634c8321ef - Show all commits
+18 -9
View File
@@ -34,6 +34,15 @@ type registry struct {
slugIndex map[Key]string 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 { func NewRegistry() Registry {
return &registry{ return &registry{
byUser: make(map[string]map[Key]Session), 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] userID, ok := r.slugIndex[key]
if !ok { if !ok {
return nil, fmt.Errorf("session not found") return nil, ErrSessionNotFound
} }
client, ok := r.byUser[userID][key] client, ok := r.byUser[userID][key]
if !ok { if !ok {
return nil, fmt.Errorf("session not found") return nil, ErrSessionNotFound
} }
return client, nil 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] client, ok := r.byUser[user][key]
if !ok { if !ok {
return nil, fmt.Errorf("session not found") return nil, ErrSessionNotFound
} }
return client, nil return client, nil
} }
func (r *registry) Update(user string, oldKey, newKey Key) error { func (r *registry) Update(user string, oldKey, newKey Key) error {
if oldKey.Type != newKey.Type { if oldKey.Type != newKey.Type {
return fmt.Errorf("tunnel type cannot change") return ErrSlugUnchanged
} }
if newKey.Type != types.TunnelTypeHTTP { if newKey.Type != types.TunnelTypeHTTP {
return fmt.Errorf("non http tunnel cannot change slug") return ErrSlugChangeNotAllowed
} }
if isForbiddenSlug(newKey.Id) { if isForbiddenSlug(newKey.Id) {
return fmt.Errorf("this subdomain is reserved. Please choose a different one") return ErrForbiddenSlug
} }
if !isValidSlug(newKey.Id) { if !isValidSlug(newKey.Id) {
return fmt.Errorf("invalid subdomain. Follow the rules") return ErrInvalidSlug
} }
r.mu.Lock() r.mu.Lock()
defer r.mu.Unlock() defer r.mu.Unlock()
if _, exists := r.slugIndex[newKey]; exists && newKey != oldKey { if _, exists := r.slugIndex[newKey]; exists && newKey != oldKey {
return fmt.Errorf("someone already uses this subdomain") return ErrSlugInUse
} }
client, ok := r.byUser[user][oldKey] client, ok := r.byUser[user][oldKey]
if !ok { if !ok {
return fmt.Errorf("session not found") return ErrSessionNotFound
} }
delete(r.byUser[user], oldKey) delete(r.byUser[user], oldKey)
+4 -4
View File
@@ -34,7 +34,7 @@ func newHTTPHandler(domain string, sessionRegistry registry.Registry, redirectTL
} }
func (hh *httpHandler) redirect(conn net.Conn, status int, location string) error { 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) + fmt.Sprintf("Location: %s", location) +
"Content-Length: 0\r\n" + "Content-Length: 0\r\n" +
"Connection: close\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 { 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 err
} }
return nil return nil
@@ -87,7 +87,7 @@ func (hh *httpHandler) handler(conn net.Conn, isTLS bool) {
defer func(hw stream.HTTP) { defer func(hw stream.HTTP) {
err = hw.Close() err = hw.Close()
if err != nil { if err != nil {
log.Printf("Error closing TunnelTypeHTTP stream: %v", err) log.Printf("Error closing HTTP stream: %v", err)
} }
}(hw) }(hw)
hh.forwardRequest(hw, reqhf, sshSession) hh.forwardRequest(hw, reqhf, sshSession)
@@ -118,7 +118,7 @@ func (hh *httpHandler) handlePingRequest(slug string, conn net.Conn) bool {
} }
_, err := conn.Write([]byte( _, err := conn.Write([]byte(
"TunnelTypeHTTP/1.1 200 OK\r\n" + "HTTP/1.1 200 OK\r\n" +
"Content-Length: 0\r\n" + "Content-Length: 0\r\n" +
"Connection: close\r\n" + "Connection: close\r\n" +
"Access-Control-Allow-Origin: *\r\n" + "Access-Control-Allow-Origin: *\r\n" +
+1 -1
View File
@@ -67,7 +67,7 @@ func NewTLSConfig(config config.Config) (*tls.Config, error) {
tm.useCertMagic = false tm.useCertMagic = false
tm.startCertWatcher() tm.startCertWatcher()
} else { } 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 { if err := tm.initCertMagic(); err != nil {
initErr = fmt.Errorf("failed to initialize CertMagic: %w", err) initErr = fmt.Errorf("failed to initialize CertMagic: %w", err)
return return
+2 -2
View File
@@ -145,9 +145,9 @@ func (m *model) slugView() string {
var warningText string var warningText string
if isVeryCompact { if isVeryCompact {
warningText = "⚠️ TunnelTypeTCP tunnels don't support custom subdomains." warningText = "⚠️ TCP tunnels don't support custom subdomains."
} else { } 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(warningBoxStyle.Render(warningText))
b.WriteString("\n\n") b.WriteString("\n\n")
+1 -1
View File
@@ -160,7 +160,7 @@ func (s *session) setupInteractiveMode(channel ssh.NewChannel) error {
} }
func (s *session) handleMissingForwardRequest() 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 { if err != nil {
return err return err
} }
+1 -1
View File
@@ -44,7 +44,7 @@ type Detail struct {
StartedAt time.Time `json:"started_at,omitempty"` 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-Length: 11\r\n" +
"Content-Type: text/plain\r\n\r\n" + "Content-Type: text/plain\r\n\r\n" +
"Bad Gateway") "Bad Gateway")