Merge branch 'main' into hailey/add-license-info

This commit is contained in:
Hailey
2024-08-15 13:51:46 -07:00
817 changed files with 93886 additions and 48560 deletions
+21 -1
View File
@@ -35,11 +35,17 @@ func run(args []string) {
Flags: []cli.Flag{
&cli.StringFlag{
Name: "appview-host",
Usage: "method, hostname, and port of PDS instance",
Usage: "scheme, hostname, and port of PDS instance",
Value: "http://localhost:2584",
// retain old PDS env var for easy transition
EnvVars: []string{"ATP_APPVIEW_HOST", "ATP_PDS_HOST"},
},
&cli.StringFlag{
Name: "ogcard-host",
Usage: "scheme, hostname, and port of ogcard service",
Required: false,
EnvVars: []string{"OGCARD_HOST"},
},
&cli.StringFlag{
Name: "http-address",
Usage: "Specify the local IP/port to bind to",
@@ -47,6 +53,13 @@ func run(args []string) {
Value: ":8100",
EnvVars: []string{"HTTP_ADDRESS"},
},
&cli.StringFlag{
Name: "link-host",
Usage: "scheme, hostname, and port of link service",
Required: false,
Value: "",
EnvVars: []string{"LINK_HOST"},
},
&cli.BoolFlag{
Name: "debug",
Usage: "Enable debug mode",
@@ -54,6 +67,13 @@ func run(args []string) {
Required: false,
EnvVars: []string{"DEBUG"},
},
&cli.StringFlag{
Name: "basic-auth-password",
Usage: "optional password to restrict access to web interface",
Required: false,
Value: "",
EnvVars: []string{"BASIC_AUTH_PASSWORD"},
},
},
},
}
+114
View File
@@ -2,10 +2,12 @@ package main
import (
"context"
"crypto/subtle"
"errors"
"fmt"
"io/fs"
"net/http"
"net/url"
"os"
"os/signal"
"strings"
@@ -30,12 +32,24 @@ type Server struct {
echo *echo.Echo
httpd *http.Server
xrpcc *xrpc.Client
cfg *Config
}
type Config struct {
debug bool
httpAddress string
appviewHost string
ogcardHost string
linkHost string
}
func serve(cctx *cli.Context) error {
debug := cctx.Bool("debug")
httpAddress := cctx.String("http-address")
appviewHost := cctx.String("appview-host")
ogcardHost := cctx.String("ogcard-host")
linkHost := cctx.String("link-host")
basicAuthPassword := cctx.String("basic-auth-password")
// Echo
e := echo.New()
@@ -71,6 +85,13 @@ func serve(cctx *cli.Context) error {
server := &Server{
echo: e,
xrpcc: xrpcc,
cfg: &Config{
debug: debug,
httpAddress: httpAddress,
appviewHost: appviewHost,
ogcardHost: ogcardHost,
linkHost: linkHost,
},
}
// Create the HTTP server.
@@ -121,6 +142,18 @@ func serve(cctx *cli.Context) error {
},
}))
// optional password gating of entire web interface
if basicAuthPassword != "" {
e.Use(middleware.BasicAuth(func(username, password string, c echo.Context) (bool, error) {
// Be careful to use constant time comparison to prevent timing attacks
if subtle.ConstantTimeCompare([]byte(username), []byte("admin")) == 1 &&
subtle.ConstantTimeCompare([]byte(password), []byte(basicAuthPassword)) == 1 {
return true, nil
}
return false, nil
}))
}
// redirect trailing slash to non-trailing slash.
// all of our current endpoints have no trailing slash.
e.Use(middleware.RemoveTrailingSlashWithConfig(middleware.TrailingSlashConfig{
@@ -179,6 +212,7 @@ func serve(cctx *cli.Context) error {
e.GET("/search", server.WebGeneric)
e.GET("/feeds", server.WebGeneric)
e.GET("/notifications", server.WebGeneric)
e.GET("/notifications/settings", server.WebGeneric)
e.GET("/lists", server.WebGeneric)
e.GET("/moderation", server.WebGeneric)
e.GET("/moderation/modlists", server.WebGeneric)
@@ -192,6 +226,7 @@ func serve(cctx *cli.Context) error {
e.GET("/settings/threads", server.WebGeneric)
e.GET("/settings/external-embeds", server.WebGeneric)
e.GET("/settings/accessibility", server.WebGeneric)
e.GET("/settings/appearance", server.WebGeneric)
e.GET("/sys/debug", server.WebGeneric)
e.GET("/sys/debug-mod", server.WebGeneric)
e.GET("/sys/log", server.WebGeneric)
@@ -208,6 +243,7 @@ func serve(cctx *cli.Context) error {
e.GET("/profile/:handleOrDID", server.WebProfile)
e.GET("/profile/:handleOrDID/follows", server.WebGeneric)
e.GET("/profile/:handleOrDID/followers", server.WebGeneric)
e.GET("/profile/:handleOrDID/known-followers", server.WebGeneric)
e.GET("/profile/:handleOrDID/lists/:rkey", server.WebGeneric)
e.GET("/profile/:handleOrDID/feed/:rkey", server.WebGeneric)
e.GET("/profile/:handleOrDID/feed/:rkey/liked-by", server.WebGeneric)
@@ -221,6 +257,21 @@ func serve(cctx *cli.Context) error {
e.GET("/profile/:handleOrDID/post/:rkey/liked-by", server.WebGeneric)
e.GET("/profile/:handleOrDID/post/:rkey/reposted-by", server.WebGeneric)
// video download
e.GET("/video-download", server.WebGeneric)
// starter packs
e.GET("/starter-pack/:handleOrDID/:rkey", server.WebStarterPack)
e.GET("/start/:handleOrDID/:rkey", server.WebStarterPack)
if linkHost != "" {
linkUrl, err := url.Parse(linkHost)
if err != nil {
return err
}
e.Group("/:linkId", server.LinkProxyMiddleware(linkUrl))
}
// Start the server.
log.Infof("starting server address=%s", httpAddress)
go func() {
@@ -292,6 +343,30 @@ func (srv *Server) Download(c echo.Context) error {
return c.Redirect(http.StatusFound, "/")
}
// Handler for proxying top-level paths to link service, which ends up serving a redirect
func (srv *Server) LinkProxyMiddleware(url *url.URL) echo.MiddlewareFunc {
return middleware.ProxyWithConfig(
middleware.ProxyConfig{
Balancer: middleware.NewRoundRobinBalancer(
[]*middleware.ProxyTarget{{URL: url}},
),
Skipper: func(c echo.Context) bool {
req := c.Request()
if req.Method == "GET" &&
strings.LastIndex(strings.TrimRight(req.URL.Path, "/"), "/") == 0 && // top-level path
!strings.HasPrefix(req.URL.Path, "/_") { // e.g. /_health endpoint
return false
}
return true
},
RetryCount: 2,
ErrorHandler: func(c echo.Context, err error) error {
return c.Redirect(302, "/")
},
},
)
}
// handler for endpoint that have no specific server-side handling
func (srv *Server) WebGeneric(c echo.Context) error {
data := pongo2.Context{}
@@ -377,6 +452,45 @@ func (srv *Server) WebPost(c echo.Context) error {
return c.Render(http.StatusOK, "post.html", data)
}
func (srv *Server) WebStarterPack(c echo.Context) error {
req := c.Request()
ctx := req.Context()
data := pongo2.Context{}
data["requestURI"] = fmt.Sprintf("https://%s%s", req.Host, req.URL.Path)
// sanity check arguments. don't 4xx, just let app handle if not expected format
rkeyParam := c.Param("rkey")
rkey, err := syntax.ParseRecordKey(rkeyParam)
if err != nil {
log.Errorf("bad rkey: %v", err)
return c.Render(http.StatusOK, "starterpack.html", data)
}
handleOrDIDParam := c.Param("handleOrDID")
handleOrDID, err := syntax.ParseAtIdentifier(handleOrDIDParam)
if err != nil {
log.Errorf("bad identifier: %v", err)
return c.Render(http.StatusOK, "starterpack.html", data)
}
identifier := handleOrDID.Normalize().String()
starterPackURI := fmt.Sprintf("at://%s/app.bsky.graph.starterpack/%s", identifier, rkey)
spv, err := appbsky.GraphGetStarterPack(ctx, srv.xrpcc, starterPackURI)
if err != nil {
log.Errorf("failed to fetch starter pack view for: %s\t%v", starterPackURI, err)
return c.Render(http.StatusOK, "starterpack.html", data)
}
if spv.StarterPack == nil || spv.StarterPack.Record == nil {
return c.Render(http.StatusOK, "starterpack.html", data)
}
rec, ok := spv.StarterPack.Record.Val.(*appbsky.GraphStarterpack)
if !ok {
return c.Render(http.StatusOK, "starterpack.html", data)
}
data["title"] = rec.Name
if srv.cfg.ogcardHost != "" {
data["imgThumbUrl"] = fmt.Sprintf("%s/start/%s/%s", srv.cfg.ogcardHost, identifier, rkey)
}
return c.Render(http.StatusOK, "starterpack.html", data)
}
func (srv *Server) WebProfile(c echo.Context) error {
ctx := c.Request().Context()
data := pongo2.Context{}