about summary refs log tree commit diff
path: root/bskyweb
diff options
context:
space:
mode:
Diffstat (limited to 'bskyweb')
-rw-r--r--bskyweb/README.md2
-rw-r--r--bskyweb/cmd/bskyweb/.gitignore1
-rw-r--r--bskyweb/cmd/bskyweb/server.go46
-rw-r--r--bskyweb/static/.well-known/apple-app-site-association13
-rw-r--r--bskyweb/static/.well-known/assetlinks.json11
-rw-r--r--bskyweb/templates/base.html4
6 files changed, 71 insertions, 6 deletions
diff --git a/bskyweb/README.md b/bskyweb/README.md
index a74cda0d5..d60647379 100644
--- a/bskyweb/README.md
+++ b/bskyweb/README.md
@@ -2,7 +2,7 @@
 
 ### SPA Bundle (monolithic static javascript file)
 
-To build the SPA bundle (`bundle.web.js`), first get a Javascript development
+To build the SPA bundle (`bundle.web.js`), first get a JavaScript development
 environment set up. Either follow the top-level README, or something quick
 like:
 
diff --git a/bskyweb/cmd/bskyweb/.gitignore b/bskyweb/cmd/bskyweb/.gitignore
new file mode 100644
index 000000000..45883bf13
--- /dev/null
+++ b/bskyweb/cmd/bskyweb/.gitignore
@@ -0,0 +1 @@
+bskyweb
diff --git a/bskyweb/cmd/bskyweb/server.go b/bskyweb/cmd/bskyweb/server.go
index 7c230041e..cdd4dd1d2 100644
--- a/bskyweb/cmd/bskyweb/server.go
+++ b/bskyweb/cmd/bskyweb/server.go
@@ -2,8 +2,10 @@ package main
 
 import (
 	"context"
+	"encoding/json"
 	"fmt"
 	"io/fs"
+	"io/ioutil"
 	"net/http"
 	"os"
 	"strings"
@@ -62,6 +64,7 @@ func serve(cctx *cli.Context) error {
 
 	staticHandler := http.FileServer(func() http.FileSystem {
 		if debug {
+			log.Debugf("serving static file from the local file system")
 			return http.FS(os.DirFS("static"))
 		}
 		fsys, err := fs.Sub(bskyweb.StaticFS, "static")
@@ -98,13 +101,22 @@ func serve(cctx *cli.Context) error {
 		RedirectCode: http.StatusFound,
 	}))
 
+	//
 	// configure routes
+	//
+
+	// static files
 	e.GET("/robots.txt", echo.WrapHandler(staticHandler))
 	e.GET("/static/*", echo.WrapHandler(http.StripPrefix("/static/", staticHandler)))
+	e.GET("/.well-known/*", echo.WrapHandler(staticHandler))
+
+	// home
 	e.GET("/", server.WebHome)
 
 	// generic routes
 	e.GET("/search", server.WebGeneric)
+	e.GET("/search/feeds", server.WebGeneric)
+	e.GET("/feeds", server.WebGeneric)
 	e.GET("/notifications", server.WebGeneric)
 	e.GET("/moderation", server.WebGeneric)
 	e.GET("/moderation/mute-lists", server.WebGeneric)
@@ -112,6 +124,7 @@ func serve(cctx *cli.Context) error {
 	e.GET("/moderation/blocked-accounts", server.WebGeneric)
 	e.GET("/settings", server.WebGeneric)
 	e.GET("/settings/app-passwords", server.WebGeneric)
+	e.GET("/settings/saved-feeds", server.WebGeneric)
 	e.GET("/sys/debug", server.WebGeneric)
 	e.GET("/sys/log", server.WebGeneric)
 	e.GET("/support", server.WebGeneric)
@@ -125,6 +138,8 @@ func serve(cctx *cli.Context) error {
 	e.GET("/profile/:handle/follows", server.WebGeneric)
 	e.GET("/profile/:handle/followers", server.WebGeneric)
 	e.GET("/profile/:handle/lists/:rkey", server.WebGeneric)
+	e.GET("/profile/:handle/feed/:rkey", server.WebGeneric)
+	e.GET("/profile/:handle/feed/:rkey/liked-by", server.WebGeneric)
 
 	// post endpoints; only first populates info
 	e.GET("/profile/:handle/post/:rkey", server.WebPost)
@@ -132,11 +147,36 @@ func serve(cctx *cli.Context) error {
 	e.GET("/profile/:handle/post/:rkey/reposted-by", server.WebGeneric)
 
 	// Mailmodo
-	e.POST("/waitlist", func(c echo.Context) error {
-		email := strings.TrimSpace(c.FormValue("email"))
-		if err := mailmodo.AddToList(c.Request().Context(), mailmodoListName, email); err != nil {
+	e.POST("/api/waitlist", func(c echo.Context) error {
+		type jsonError struct {
+			Error string `json:"error"`
+		}
+
+		// Read the API request.
+		type apiRequest struct {
+			Email string `json:"email"`
+		}
+
+		bodyReader := http.MaxBytesReader(c.Response(), c.Request().Body, 16*1024)
+		payload, err := ioutil.ReadAll(bodyReader)
+		if err != nil {
 			return err
 		}
+		var req apiRequest
+		if err := json.Unmarshal(payload, &req); err != nil {
+			return c.JSON(http.StatusBadRequest, jsonError{Error: "Invalid API request"})
+		}
+
+		if req.Email == "" {
+			return c.JSON(http.StatusBadRequest, jsonError{Error: "Please enter a valid email address."})
+		}
+
+		if err := mailmodo.AddToList(c.Request().Context(), mailmodoListName, req.Email); err != nil {
+			log.Errorf("adding email to waitlist failed: %s", err)
+			return c.JSON(http.StatusBadRequest, jsonError{
+				Error: "Storing email in waitlist failed. Please enter a valid email address.",
+			})
+		}
 		return c.JSON(http.StatusOK, map[string]bool{"success": true})
 	})
 
diff --git a/bskyweb/static/.well-known/apple-app-site-association b/bskyweb/static/.well-known/apple-app-site-association
new file mode 100644
index 000000000..232acdf25
--- /dev/null
+++ b/bskyweb/static/.well-known/apple-app-site-association
@@ -0,0 +1,13 @@
+{
+  "applinks": {
+    "apps": [],
+    "details": [
+      {
+        "appID": "B3LX46C5HS.xyz.blueskyweb.app",
+        "paths": [
+          "*"
+        ]
+      }
+    ]
+  }
+}
\ No newline at end of file
diff --git a/bskyweb/static/.well-known/assetlinks.json b/bskyweb/static/.well-known/assetlinks.json
new file mode 100644
index 000000000..5ca12d5b3
--- /dev/null
+++ b/bskyweb/static/.well-known/assetlinks.json
@@ -0,0 +1,11 @@
+[
+  {
+    "relation": ["delegate_permission/common.handle_all_urls"],
+    "target": {
+      "namespace": "android_app",
+      "package_name": "xyz.blueskyweb.app",
+      "sha256_cert_fingerprints":
+        ["C1:4D:3C:6B:B5:D6:D9:AE:CF:C5:0B:BC:C1:9B:29:6D:D4:E6:87:46:36:D5:4C:1A:64:1C:14:08:BF:7E:F9:62", "FA:C6:17:45:DC:09:03:78:6F:B9:ED:E6:2A:96:2B:39:9F:73:48:F0:BB:6F:89:9B:83:32:66:75:91:03:3B:9C"]
+    }
+  }
+]
diff --git a/bskyweb/templates/base.html b/bskyweb/templates/base.html
index 5725b7af0..abd312ed5 100644
--- a/bskyweb/templates/base.html
+++ b/bskyweb/templates/base.html
@@ -122,8 +122,8 @@
 {%- block body_all %}
 	<div id="root"></div>
     <noscript>
-      <h1>Javascript Required</h1>
-      <p>This is a heavily interactive web application, and Javascript is required. Simple HTML interfaces are possible, but that is not what this is.
+      <h1>JavaScript Required</h1>
+      <p>This is a heavily interactive web application, and JavaScript is required. Simple HTML interfaces are possible, but that is not what this is.
       <p>Learn more about Bluesky at <a href="https://blueskyweb.xyz">blueskyweb.xyz</a> and <a href="https://atproto.com">atproto.com</a>.
 			{% block noscript_extra %}{% endblock %}
     </noscript>