website/pkg/controller/api/static_auth.go

85 lines
2.1 KiB
Go
Raw Normal View History

package api
import (
"fmt"
"net/http"
"net/url"
"strings"
"code.nonshy.com/nonshy/website/pkg/config"
"code.nonshy.com/nonshy/website/pkg/encryption"
"code.nonshy.com/nonshy/website/pkg/session"
"github.com/golang-jwt/jwt/v4"
)
// StaticAuth API protects paths like /static/photos/ to authenticated user requests only.
func StaticAuth() http.HandlerFunc {
type Response struct {
Success bool `json:"success"`
Error string `json:",omitempty"`
Username string `json:"username"`
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// We only protect the /static/photos subpath.
// And check if the SignedPhoto feature is enabled and enforcing.
var originalURI = r.Header.Get("X-Original-URI")
if !config.Current.SignedPhoto.Enabled || !strings.HasPrefix(originalURI, config.PhotoWebPath) {
SendJSON(w, http.StatusOK, Response{
Success: true,
})
return
}
// Parse the JWT token parameter from the original URL.
var token string
if path, err := url.Parse(originalURI); err == nil {
query := path.Query()
token = query.Get("jwt")
}
// The token is required from here.
if token == "" {
SendJSON(w, http.StatusForbidden, Response{
Error: "JWT token is required",
})
return
}
// Check if we're logged in.
currentUser, err := session.CurrentUser(r)
if err != nil {
SendJSON(w, http.StatusForbidden, Response{
Error: "Login Required",
})
return
}
// Validate the JWT token.
claims, ok, err := encryption.ValidateClaims(
token,
[]byte(config.Current.SignedPhoto.JWTSecret),
&jwt.RegisteredClaims{},
)
if !ok || err != nil {
SendJSON(w, http.StatusForbidden, Response{
Error: fmt.Sprintf("JWT claims: %v", err),
})
return
}
// Sanity check that the username in these claims is the same as the viewer.
if c, ok := claims.(*jwt.RegisteredClaims); !ok || c.Subject != currentUser.Username {
SendJSON(w, http.StatusForbidden, Response{
Error: "That photo was not for you",
})
return
}
SendJSON(w, http.StatusOK, Response{
Success: true,
Username: currentUser.Username,
})
})
}