this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

fixes to admin routes and UI

+68 -24
+7 -2
cmd/rerelay/handlers.go
··· 28 28 } 29 29 30 30 if noSSL && !s.relay.Config.SSL { 31 - return c.JSON(http.StatusBadRequest, xrpc.XRPCError{ErrStr: "BadRequest", Message: "This relay requires SSL"}) 31 + return c.JSON(http.StatusBadRequest, xrpc.XRPCError{ErrStr: "BadRequest", Message: "this relay requires SSL"}) 32 32 } 33 33 34 34 // TODO: could ensure that query and path are empty ··· 47 47 } 48 48 } 49 49 50 - if err := s.relay.HostChecker.CheckHost(ctx, hostname); err != nil { 50 + hostURL := "https://" + hostname 51 + if noSSL { 52 + hostURL = "http://" + hostname 53 + } 54 + 55 + if err := s.relay.HostChecker.CheckHost(ctx, hostURL); err != nil { 51 56 return c.JSON(http.StatusBadRequest, xrpc.XRPCError{ErrStr: "HostNotFound", Message: fmt.Sprintf("host server unreachable: %s", err)}) 52 57 } 53 58
+36 -8
cmd/rerelay/handlers_admin.go
··· 6 6 "net/http" 7 7 "strconv" 8 8 "strings" 9 + "time" 9 10 10 11 comatproto "github.com/bluesky-social/indigo/api/atproto" 11 12 "github.com/bluesky-social/indigo/atproto/syntax" ··· 171 172 } 172 173 173 174 type hostInfo struct { 174 - models.Host 175 + // fields from old models.PDS 176 + ID uint64 177 + CreatedAt time.Time 178 + Host string 179 + SSL bool 180 + Cursor int64 181 + Registered bool 182 + Blocked bool 183 + RateLimit float64 184 + CrawlRateLimit float64 185 + RepoCount int64 186 + RepoLimit int64 187 + HourlyEventLimit int64 188 + DailyEventLimit int64 189 + 175 190 HasActiveConnection bool `json:"HasActiveConnection"` 176 191 EventsSeenSinceStartup uint64 `json:"EventsSeenSinceStartup"` 177 192 PerSecondEventRate rateLimit `json:"PerSecondEventRate"` ··· 189 204 return err 190 205 } 191 206 192 - hostInfos := make([]hostInfo, len(hosts)) 193 - 194 - var activeHosts map[string]bool 195 207 activeHostnames := s.relay.Slurper.GetActiveSubHostnames() 208 + activeHosts := make(map[string]bool, len(activeHostnames)) 196 209 for _, hostname := range activeHostnames { 197 210 activeHosts[hostname] = true 198 211 } 199 212 213 + hostInfos := make([]hostInfo, len(hosts)) 200 214 for i, host := range hosts { 201 - hostInfos[i].Host = *host 202 215 _, isActive := activeHosts[host.Hostname] 203 - hostInfos[i].HasActiveConnection = isActive 216 + hostInfos[i] = hostInfo{ 217 + ID: host.ID, 218 + CreatedAt: host.CreatedAt, 219 + Host: host.Hostname, 220 + SSL: !host.NoSSL, 221 + Cursor: host.LastSeq, 222 + Registered: host.Status == models.HostStatusActive, // is this right? 223 + Blocked: host.Status == models.HostStatusBanned, 224 + //TODO: RateLimit 225 + //TODO: CrawlRateLimit 226 + RepoCount: host.AccountCount, 227 + RepoLimit: host.AccountLimit, 228 + //HourlyEventLimit 229 + //DailyEventLimit 230 + 231 + HasActiveConnection: isActive, 232 + UserCount: host.AccountCount, 233 + } 204 234 205 235 // pull event counter metrics from prometheus 206 236 var m = &dto.Metric{} ··· 209 239 continue 210 240 } 211 241 hostInfos[i].EventsSeenSinceStartup = uint64(m.Counter.GetValue()) 212 - 213 - hostInfos[i].UserCount = host.AccountCount 214 242 215 243 /* XXX: compute these from account limit 216 244 hostInfos[i].PerSecondEventRate = rateLimit{
+1 -1
cmd/rerelay/main.go
··· 230 230 relayConfig.TrustedDomains = cctx.StringSlice("trusted-domains") 231 231 232 232 svcConfig := DefaultServiceConfig() 233 - svcConfig.DisableRequestCrawl = !cctx.Bool("disable-request-crawl") 233 + svcConfig.DisableRequestCrawl = cctx.Bool("disable-request-crawl") 234 234 svcConfig.ForwardCrawlRequestHosts = cctx.StringSlice("forward-crawl-requests") 235 235 if len(svcConfig.ForwardCrawlRequestHosts) > 0 { 236 236 logger.Info("crawl request forwarding enabled", "servers", svcConfig.ForwardCrawlRequestHosts)
+6
cmd/rerelay/relay/host.go
··· 84 84 // 85 85 // Hostnames much be DNS names, not IP addresses 86 86 func ParseHostname(raw string) (hostname string, noSSL bool, err error) { 87 + 88 + // handle case of bare hostname 89 + if !strings.Contains(raw, "://") { 90 + raw = "https://" + raw 91 + } 92 + 87 93 u, err := url.Parse(raw) 88 94 noSSL = false 89 95 switch u.Scheme {
+4 -1
cmd/rerelay/relay/host_test.go
··· 21 21 HostnameFixture{Val: "https://pds.example.com", Hostname: "pds.example.com", NoSSL: false}, 22 22 HostnameFixture{Val: "http://pds.example.com", Hostname: "pds.example.com", NoSSL: true}, 23 23 HostnameFixture{Val: "ws://pds.example.com", Hostname: "pds.example.com", NoSSL: true}, 24 - HostnameFixture{Val: "pds.example.com", Error: true}, 24 + HostnameFixture{Val: "pds.example.com", Hostname: "pds.example.com", NoSSL: false}, 25 + HostnameFixture{Val: "morel.us-east.host.bsky.network", Hostname: "morel.us-east.host.bsky.network", NoSSL: false}, 25 26 HostnameFixture{Val: "https://8.8.8.8", Error: true}, 26 27 HostnameFixture{Val: "https://internal", Error: true}, 28 + HostnameFixture{Val: "at://pds.example.com", Error: true}, 29 + HostnameFixture{Val: "ftp://pds.example.com", Error: true}, 27 30 HostnameFixture{Val: "https://service.local", Hostname: "service.local", NoSSL: false}, // TODO: SSRF 28 31 } 29 32
+1
cmd/rerelay/relay/slurper.go
··· 71 71 // NOTE: many of these defaults are overruled by DefaultRelayConfig, or even process CLI arg defaults 72 72 return &SlurperConfig{ 73 73 SSL: false, 74 + NewHostPerDayLimit: 50, 74 75 DefaultPerSecondLimit: 50, 75 76 DefaultPerHourLimit: 2500, 76 77 DefaultPerDayLimit: 20_000,
+12 -11
cmd/rerelay/service.go
··· 107 107 108 108 e.Use(svcutil.MetricsMiddleware) 109 109 110 - e.HTTPErrorHandler = func(err error, ctx echo.Context) { 110 + e.HTTPErrorHandler = func(err error, c echo.Context) { 111 111 switch err := err.(type) { 112 112 case *echo.HTTPError: 113 - if err2 := ctx.JSON(err.Code, map[string]any{ 113 + if err2 := c.JSON(err.Code, map[string]any{ 114 114 "error": err.Message, 115 115 }); err2 != nil { 116 116 svc.logger.Error("Failed to write http error", "err", err2) 117 117 } 118 118 default: 119 119 sendHeader := true 120 - if ctx.Path() == "/xrpc/com.atproto.sync.subscribeRepos" { 120 + if c.Path() == "/xrpc/com.atproto.sync.subscribeRepos" { 121 121 sendHeader = false 122 122 } 123 123 124 - svc.logger.Warn("HANDLER ERROR: (%s) %s", ctx.Path(), err) 124 + svc.logger.Error("API handler error", "path", c.Path(), "err", err) 125 125 126 - if strings.HasPrefix(ctx.Path(), "/admin/") { 127 - ctx.JSON(500, map[string]any{ 126 + if strings.HasPrefix(c.Path(), "/admin/") { 127 + c.JSON(http.StatusInternalServerError, map[string]any{ 128 128 "error": err.Error(), 129 129 }) 130 130 return 131 131 } 132 132 133 133 if sendHeader { 134 - ctx.Response().WriteHeader(500) 134 + c.Response().WriteHeader(http.StatusInternalServerError) 135 135 } 136 136 } 137 137 } ··· 166 166 admin.POST("/subs/unbanDomain", svc.handleAdminUnbanDomain) 167 167 168 168 // Repo-related Admin API 169 - admin.GET("/repo/takedowns", svc.handleAdminListRepoTakeDowns) 169 + admin.GET("/repo/takedowns", svc.handleAdminListRepoTakeDowns) // NOTE: unused 170 170 admin.POST("/repo/takeDown", svc.handleAdminTakeDownRepo) 171 171 admin.POST("/repo/reverseTakedown", svc.handleAdminReverseTakedown) 172 172 ··· 205 205 206 206 func (svc *Service) checkAdminAuth(next echo.HandlerFunc) echo.HandlerFunc { 207 207 headerVal := "Basic " + base64.StdEncoding.EncodeToString([]byte("admin:"+svc.config.AdminPassword)) 208 - return func(e echo.Context) error { 209 - if svc.config.AdminPassword != headerVal { 208 + return func(c echo.Context) error { 209 + hdr := c.Request().Header.Get("Authorization") 210 + if hdr != headerVal { 210 211 return echo.ErrForbidden 211 212 } 212 - return next(e) 213 + return next(c) 213 214 } 214 215 }
+1 -1
cmd/rerelay/stubs.go
··· 147 147 } 148 148 149 149 u := c.Request().URL 150 - if u != nil { 150 + if u == nil { 151 151 return fmt.Errorf("unexpected nil URL on request") 152 152 } 153 153 u.Host = pdsHost