Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions api/auth_middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -347,8 +347,16 @@ func (app *ApiServer) authMiddleware(c *fiber.Ctx) error {
return fiber.NewError(fiber.StatusUnauthorized, "Invalid or expired access token")
}

// Not authorized to act on behalf of myId
if myId != 0 && !pkceAuthed && !app.isAuthorizedRequest(c.Context(), myId, wallet) {
// Not authorized to act on behalf of myId.
//
// Exception: /users/:userId/feed/for-you accepts user_id as a viewer hint
// used only for response decoration (has_current_user_reposted etc.); the
// path :userId — not user_id — controls what gets personalized. Treat the
// query user_id as advisory rather than authoritative on this route so
// the endpoint can be called like the other public read endpoints.
allowUnauthenticatedViewerId := strings.HasSuffix(c.Path(), "/feed/for-you")

if myId != 0 && !pkceAuthed && !allowUnauthenticatedViewerId && !app.isAuthorizedRequest(c.Context(), myId, wallet) {
return fiber.NewError(
fiber.StatusForbidden,
fmt.Sprintf(
Expand Down
19 changes: 19 additions & 0 deletions api/v1_users_feed_for_you_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,25 @@ func TestV1FeedForYou_RequiresValidUserId(t *testing.T) {
assert.Equal(t, 400, status)
}

// /feed/for-you is exempt from authMiddleware's "if user_id is set, wallet
// must match" 403 — the query user_id is a viewer hint, not an authorization
// claim. This test pins that exemption: with skipAuthCheck OFF (so the real
// auth path runs) and no signature headers, the call still returns 200.
func TestV1FeedForYou_UnauthenticatedViewerIdAllowed(t *testing.T) {
app := emptyTestApp(t)
// Deliberately NOT setting app.skipAuthCheck — exercise the real
// authMiddleware exemption added for this route.
database.Seed(app.pool.Replicas[0], feedForYouFixtures())

var response struct {
Data []dbv1.Track
}
encodedId := trashid.MustEncodeHashID(1)
path := "/v1/users/" + encodedId + "/feed/for-you?user_id=" + encodedId
status, body := testGet(t, app, path, &response)
require.Equal(t, 200, status, string(body))
}

func TestV1FeedForYou_ExcludesAlreadySavedTracks(t *testing.T) {
app := emptyTestApp(t)
app.skipAuthCheck = true
Expand Down
Loading