diff --git a/api/auth_middleware.go b/api/auth_middleware.go index 90748081..1d29b1a1 100644 --- a/api/auth_middleware.go +++ b/api/auth_middleware.go @@ -97,10 +97,22 @@ func (app *ApiServer) isAuthorizedRequest(ctx context.Context, userId int32, aut return isAuthorized } +// get the wallet that signed the request func (app *ApiServer) getAuthedWallet(c *fiber.Ctx) string { return c.Locals("authedWallet").(string) } +// get the wallet that signed the request, or "" if not set +func (app *ApiServer) tryGetAuthedWallet(c *fiber.Ctx) string { + if c == nil { + return "" + } + if w, ok := c.Locals("authedWallet").(string); ok { + return w + } + return "" +} + // validateOAuthJWTTokenToUserId validates the OAuth JWT and returns the userId from the payload. func (app *ApiServer) validateOAuthJWTTokenToUserId(ctx context.Context, token string) (trashid.HashId, error) { tokenParts := strings.Split(token, ".") diff --git a/api/dbv1/get_tracks.sql.go b/api/dbv1/get_tracks.sql.go index 9794f5ec..97234f5c 100644 --- a/api/dbv1/get_tracks.sql.go +++ b/api/dbv1/get_tracks.sql.go @@ -224,7 +224,9 @@ LEFT JOIN aggregate_plays on play_item_id = t.track_id LEFT JOIN track_routes on t.track_id = track_routes.track_id and track_routes.is_current = true WHERE (is_unlisted = false OR t.owner_id = $1 OR $2::bool = TRUE) AND t.track_id = ANY($3::int[]) - AND t.access_authorities IS NULL + AND (t.access_authorities IS NULL + OR (COALESCE($4, '') <> '' + AND EXISTS (SELECT 1 FROM unnest(t.access_authorities) aa WHERE lower(aa) = lower($4)))) ORDER BY t.track_id ` @@ -232,6 +234,7 @@ type GetTracksParams struct { MyID interface{} `json:"my_id"` IncludeUnlisted bool `json:"include_unlisted"` Ids []int32 `json:"ids"` + AuthedWallet interface{} `json:"authed_wallet"` } type GetTracksRow struct { @@ -311,7 +314,12 @@ type GetTracksRow struct { } func (q *Queries) GetTracks(ctx context.Context, arg GetTracksParams) ([]GetTracksRow, error) { - rows, err := q.db.Query(ctx, getTracks, arg.MyID, arg.IncludeUnlisted, arg.Ids) + rows, err := q.db.Query(ctx, getTracks, + arg.MyID, + arg.IncludeUnlisted, + arg.Ids, + arg.AuthedWallet, + ) if err != nil { return nil, err } diff --git a/api/dbv1/parallel.go b/api/dbv1/parallel.go index 5b1b400b..efa8cd8a 100644 --- a/api/dbv1/parallel.go +++ b/api/dbv1/parallel.go @@ -7,10 +7,11 @@ import ( ) type ParallelParams struct { - UserIds []int32 - TrackIds []int32 - PlaylistIds []int32 - MyID int32 + UserIds []int32 + TrackIds []int32 + PlaylistIds []int32 + MyID int32 + AuthedWallet string } type ParallelResult struct { @@ -42,8 +43,9 @@ func (q *Queries) Parallel(ctx context.Context, arg ParallelParams) (*ParallelRe var err error trackMap, err = q.TracksKeyed(ctx, TracksParams{ GetTracksParams: GetTracksParams{ - Ids: arg.TrackIds, - MyID: arg.MyID, + Ids: arg.TrackIds, + MyID: arg.MyID, + AuthedWallet: arg.AuthedWallet, }, }) return err @@ -58,6 +60,7 @@ func (q *Queries) Parallel(ctx context.Context, arg ParallelParams) (*ParallelRe Ids: arg.PlaylistIds, MyID: arg.MyID, }, + AuthedWallet: arg.AuthedWallet, }) return err }) diff --git a/api/dbv1/playlists.go b/api/dbv1/playlists.go index 9394a25f..6e90df8f 100644 --- a/api/dbv1/playlists.go +++ b/api/dbv1/playlists.go @@ -9,8 +9,9 @@ import ( type PlaylistsParams struct { GetPlaylistsParams - OmitTracks bool - TrackLimit int // 0 means use default (200), positive values set the limit + OmitTracks bool + TrackLimit int // 0 means use default (200), positive values set the limit + AuthedWallet string // wallet that signed the request; tracks with matching access_authorities are shown } type Playlist struct { @@ -68,9 +69,10 @@ func (q *Queries) PlaylistsKeyed(ctx context.Context, arg PlaylistsParams) (map[ // fetch users + tracks in parallel loaded, err := q.Parallel(ctx, ParallelParams{ - UserIds: userIds, - TrackIds: trackIds, - MyID: arg.MyID.(int32), + UserIds: userIds, + TrackIds: trackIds, + MyID: arg.MyID.(int32), + AuthedWallet: arg.AuthedWallet, }) if err != nil { return nil, err diff --git a/api/dbv1/queries/get_tracks.sql b/api/dbv1/queries/get_tracks.sql index 351b3190..83699b0d 100644 --- a/api/dbv1/queries/get_tracks.sql +++ b/api/dbv1/queries/get_tracks.sql @@ -209,6 +209,8 @@ LEFT JOIN aggregate_plays on play_item_id = t.track_id LEFT JOIN track_routes on t.track_id = track_routes.track_id and track_routes.is_current = true WHERE (is_unlisted = false OR t.owner_id = @my_id OR @include_unlisted::bool = TRUE) AND t.track_id = ANY(@ids::int[]) - AND t.access_authorities IS NULL + AND (t.access_authorities IS NULL + OR (COALESCE(@authed_wallet, '') <> '' + AND EXISTS (SELECT 1 FROM unnest(t.access_authorities) aa WHERE lower(aa) = lower(@authed_wallet)))) ORDER BY t.track_id ; diff --git a/api/request_helpers.go b/api/request_helpers.go index ed507f14..4b52226b 100644 --- a/api/request_helpers.go +++ b/api/request_helpers.go @@ -10,7 +10,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/gofiber/fiber/v2" - "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgtype" ) @@ -139,22 +138,30 @@ func (app *ApiServer) getSignerFromApiAccessKey(ctx context.Context, apiAccessKe JOIN api_keys ak ON LOWER(ak.api_key) = LOWER(aak.api_key) WHERE aak.api_access_key = $1 AND aak.is_active = true `, apiAccessKey).Scan(&parentApiKey, &apiSecret) - if err == pgx.ErrNoRows || err != nil || apiSecret == "" { - return nil + if err == nil && apiSecret != "" { + privateKey, keyErr := crypto.HexToECDSA(strings.TrimPrefix(apiSecret, "0x")) + if keyErr != nil { + return nil + } + parentApiKeyLower := strings.ToLower(parentApiKey) + app.apiAccessKeySignerCache.Set(apiAccessKey, apiAccessKeySignerEntry{ + ApiKey: parentApiKeyLower, + ApiSecret: apiSecret, + }) + return &Signer{ + Address: parentApiKeyLower, + PrivateKey: privateKey, + } } - parentApiKeyLower := strings.ToLower(parentApiKey) - app.apiAccessKeySignerCache.Set(apiAccessKey, apiAccessKeySignerEntry{ - ApiKey: parentApiKeyLower, - ApiSecret: apiSecret, - }) - - privateKey, err := crypto.HexToECDSA(strings.TrimPrefix(apiSecret, "0x")) + // Fallback: use apiAccessKey as raw private key when no api_secret is found + privateKey, err := crypto.HexToECDSA(strings.TrimPrefix(apiAccessKey, "0x")) if err != nil { return nil } + address := crypto.PubkeyToAddress(privateKey.PublicKey) return &Signer{ - Address: parentApiKeyLower, + Address: address.Hex(), PrivateKey: privateKey, } } diff --git a/api/v1_comments.go b/api/v1_comments.go index 58e10b98..c0425b32 100644 --- a/api/v1_comments.go +++ b/api/v1_comments.go @@ -109,9 +109,10 @@ func (app *ApiServer) queryFullComments( } } related, err := app.queries.Parallel(c.Context(), dbv1.ParallelParams{ - UserIds: userIds, - TrackIds: trackIds, - MyID: app.getMyId(c), + UserIds: userIds, + TrackIds: trackIds, + MyID: app.getMyId(c), + AuthedWallet: app.tryGetAuthedWallet(c), }) if err != nil { return err diff --git a/api/v1_explore_best_selling.go b/api/v1_explore_best_selling.go index 5e580b66..d5bc0484 100644 --- a/api/v1_explore_best_selling.go +++ b/api/v1_explore_best_selling.go @@ -111,9 +111,10 @@ func (app *ApiServer) v1ExploreBestSelling(c *fiber.Ctx) error { } } related, err := app.queries.Parallel(c.Context(), dbv1.ParallelParams{ - PlaylistIds: playlistIds, - TrackIds: trackIds, - MyID: app.getMyId(c), + PlaylistIds: playlistIds, + TrackIds: trackIds, + MyID: app.getMyId(c), + AuthedWallet: app.tryGetAuthedWallet(c), }) if err != nil { return err diff --git a/api/v1_playlist.go b/api/v1_playlist.go index 8c624271..f9eab63d 100644 --- a/api/v1_playlist.go +++ b/api/v1_playlist.go @@ -81,6 +81,7 @@ func (app *ApiServer) v1Playlist(c *fiber.Ctx) error { MyID: myId, Ids: []int32{int32(playlistId)}, }, + AuthedWallet: app.tryGetAuthedWallet(c), }) if err != nil { return err diff --git a/api/v1_playlist_by_permalink.go b/api/v1_playlist_by_permalink.go index 3d75f77b..4ddb3ae3 100644 --- a/api/v1_playlist_by_permalink.go +++ b/api/v1_playlist_by_permalink.go @@ -33,6 +33,7 @@ func (app *ApiServer) v1PlaylistByPermalink(c *fiber.Ctx) error { MyID: myId, Ids: ids, }, + AuthedWallet: app.tryGetAuthedWallet(c), }) if err != nil { return err diff --git a/api/v1_playlist_stream.go b/api/v1_playlist_stream.go index 63d6a8e3..b493a256 100644 --- a/api/v1_playlist_stream.go +++ b/api/v1_playlist_stream.go @@ -18,6 +18,7 @@ func (app *ApiServer) v1PlaylistStream(c *fiber.Ctx) error { MyID: myId, Ids: []int32{int32(playlistId)}, }, + AuthedWallet: app.tryGetAuthedWallet(c), }) if err != nil { return err diff --git a/api/v1_playlist_tracks.go b/api/v1_playlist_tracks.go index 1003cdb9..55625ceb 100644 --- a/api/v1_playlist_tracks.go +++ b/api/v1_playlist_tracks.go @@ -58,8 +58,9 @@ func (app *ApiServer) v1PlaylistTracks(c *fiber.Ctx) error { tracks, err := app.queries.Tracks(c.Context(), dbv1.TracksParams{ GetTracksParams: dbv1.GetTracksParams{ - Ids: trackIds, - MyID: myId, + Ids: trackIds, + MyID: myId, + AuthedWallet: app.tryGetAuthedWallet(c), }, }) diff --git a/api/v1_playlists.go b/api/v1_playlists.go index a43e4a81..6be9c78d 100644 --- a/api/v1_playlists.go +++ b/api/v1_playlists.go @@ -54,7 +54,8 @@ func (app *ApiServer) v1Playlists(c *fiber.Ctx) error { MyID: myId, Ids: ids, }, - OmitTracks: !withTracks, + OmitTracks: !withTracks, + AuthedWallet: app.tryGetAuthedWallet(c), }) if err != nil { return err diff --git a/api/v1_playlists_top.go b/api/v1_playlists_top.go index 5555c5d5..aff06917 100644 --- a/api/v1_playlists_top.go +++ b/api/v1_playlists_top.go @@ -47,7 +47,8 @@ func (app *ApiServer) v1PlaylistsTop(c *fiber.Ctx) error { Ids: playlistsIds, MyID: myId, }, - OmitTracks: true, + OmitTracks: true, + AuthedWallet: app.tryGetAuthedWallet(c), }) return v1PlaylistsResponse(c, playlists) diff --git a/api/v1_playlists_trending.go b/api/v1_playlists_trending.go index 134b946e..39ac2296 100644 --- a/api/v1_playlists_trending.go +++ b/api/v1_playlists_trending.go @@ -63,7 +63,9 @@ func (app *ApiServer) v1PlaylistsTrending(c *fiber.Ctx) error { AND t.is_delete = false AND t.is_current = true AND t.stem_of IS NULL - AND t.access_authorities IS NULL + AND (t.access_authorities IS NULL + OR (COALESCE(@authed_wallet, '') <> '' + AND EXISTS (SELECT 1 FROM unnest(t.access_authorities) aa WHERE lower(aa) = lower(@authed_wallet)))) ) SELECT playlist_id @@ -95,9 +97,10 @@ func (app *ApiServer) v1PlaylistsTrending(c *fiber.Ctx) error { ` rows, err := app.pool.Query(c.Context(), sql, pgx.NamedArgs{ - "limit": params.Limit, - "offset": params.Offset, - "time": params.Time, + "limit": params.Limit, + "offset": params.Offset, + "time": params.Time, + "authed_wallet": app.tryGetAuthedWallet(c), }) if err != nil { return err @@ -113,7 +116,8 @@ func (app *ApiServer) v1PlaylistsTrending(c *fiber.Ctx) error { Ids: ids, MyID: myId, }, - OmitTracks: params.OmitTracks, + OmitTracks: params.OmitTracks, + AuthedWallet: app.tryGetAuthedWallet(c), // Limit these to 5 items to prevent slow load times TrackLimit: 5, }) diff --git a/api/v1_search.go b/api/v1_search.go index fb82a9bc..bad52a98 100644 --- a/api/v1_search.go +++ b/api/v1_search.go @@ -171,8 +171,9 @@ func (app *ApiServer) searchTracks(c *fiber.Ctx) ([]dbv1.Track, error) { tracks, err := app.queries.Tracks(c.Context(), dbv1.TracksParams{ GetTracksParams: dbv1.GetTracksParams{ - Ids: tracksIds, - MyID: myId, + Ids: tracksIds, + MyID: myId, + AuthedWallet: app.tryGetAuthedWallet(c), }, }) return tracks, err @@ -214,7 +215,8 @@ func (app *ApiServer) searchPlaylists(c *fiber.Ctx) ([]dbv1.Playlist, error) { Ids: playlistsIds, MyID: myId, }, - OmitTracks: true, + OmitTracks: true, + AuthedWallet: app.tryGetAuthedWallet(c), }) return playlists, err } @@ -256,7 +258,8 @@ func (app *ApiServer) searchAlbums(c *fiber.Ctx) ([]dbv1.Playlist, error) { Ids: playlistsIds, MyID: myId, }, - OmitTracks: true, + OmitTracks: true, + AuthedWallet: app.tryGetAuthedWallet(c), }) return playlists, err } diff --git a/api/v1_track.go b/api/v1_track.go index ea6e65b9..cdc9d311 100644 --- a/api/v1_track.go +++ b/api/v1_track.go @@ -201,8 +201,9 @@ func (app *ApiServer) v1Track(c *fiber.Ctx) error { tracks, err := app.queries.Tracks(c.Context(), dbv1.TracksParams{ GetTracksParams: dbv1.GetTracksParams{ - MyID: myId, - Ids: []int32{int32(trackId)}, + MyID: myId, + Ids: []int32{int32(trackId)}, + AuthedWallet: app.tryGetAuthedWallet(c), }, }) if err != nil { diff --git a/api/v1_track_access_info.go b/api/v1_track_access_info.go index 74307fc2..b877d30d 100644 --- a/api/v1_track_access_info.go +++ b/api/v1_track_access_info.go @@ -58,6 +58,7 @@ func (app *ApiServer) v1TrackAccessInfo(c *fiber.Ctx) error { GetTracksParams: dbv1.GetTracksParams{ MyID: myId, Ids: []int32{int32(trackId)}, + AuthedWallet: app.tryGetAuthedWallet(c), IncludeUnlisted: true, }, }) diff --git a/api/v1_track_comment_count.go b/api/v1_track_comment_count.go index ad1c0d96..a6ad45e9 100644 --- a/api/v1_track_comment_count.go +++ b/api/v1_track_comment_count.go @@ -16,7 +16,10 @@ func (app *ApiServer) v1TrackCommentCount(c *fiber.Ctx) error { track AS ( SELECT track_id, owner_id FROM tracks - WHERE track_id = @trackId AND access_authorities IS NULL + WHERE track_id = @trackId + AND (access_authorities IS NULL + OR (COALESCE(@authed_wallet, '') <> '' + AND EXISTS (SELECT 1 FROM unnest(access_authorities) aa WHERE lower(aa) = lower(@authed_wallet)))) ), -- Users muted by high-karma users @@ -107,6 +110,7 @@ func (app *ApiServer) v1TrackCommentCount(c *fiber.Ctx) error { "myId": myId, "trackId": trackId, "karmaCommentCountThreshold": karmaCommentCountThreshold, + "authed_wallet": app.tryGetAuthedWallet(c), }) if err != nil { return err diff --git a/api/v1_track_comments.go b/api/v1_track_comments.go index 1c3e5061..9a75652d 100644 --- a/api/v1_track_comments.go +++ b/api/v1_track_comments.go @@ -14,7 +14,10 @@ func (app *ApiServer) v1TrackComments(c *fiber.Ctx) error { track AS ( SELECT track_id, owner_id FROM tracks - WHERE track_id = @track_id AND access_authorities IS NULL + WHERE track_id = @track_id + AND (access_authorities IS NULL + OR (COALESCE(@authed_wallet, '') <> '' + AND EXISTS (SELECT 1 FROM unnest(access_authorities) aa WHERE lower(aa) = lower(@authed_wallet)))) ), -- Users muted by high-karma users @@ -107,6 +110,7 @@ func (app *ApiServer) v1TrackComments(c *fiber.Ctx) error { "myId": myId, "track_id": trackId, "karmaCommentCountThreshold": karmaCommentCountThreshold, + "authed_wallet": app.tryGetAuthedWallet(c), } return app.queryFullComments(c, sql, args, true) diff --git a/api/v1_track_download.go b/api/v1_track_download.go index c82bb04b..7dcaca30 100644 --- a/api/v1_track_download.go +++ b/api/v1_track_download.go @@ -27,8 +27,9 @@ func (app *ApiServer) v1TrackDownload(c *fiber.Ctx) error { tracks, err := app.queries.Tracks(c.Context(), dbv1.TracksParams{ GetTracksParams: dbv1.GetTracksParams{ - MyID: myId, - Ids: []int32{int32(trackId)}, + MyID: myId, + Ids: []int32{int32(trackId)}, + AuthedWallet: app.tryGetAuthedWallet(c), }, }) if err != nil { diff --git a/api/v1_track_inspect.go b/api/v1_track_inspect.go index 05f308f8..6b45ba8b 100644 --- a/api/v1_track_inspect.go +++ b/api/v1_track_inspect.go @@ -75,8 +75,9 @@ func (app *ApiServer) v1TrackInspect(c *fiber.Ctx) error { tracks, err := app.queries.Tracks(c.Context(), dbv1.TracksParams{ GetTracksParams: dbv1.GetTracksParams{ - MyID: myId, - Ids: []int32{int32(trackId)}, + MyID: myId, + Ids: []int32{int32(trackId)}, + AuthedWallet: app.tryGetAuthedWallet(c), }, }) if err != nil { @@ -105,8 +106,9 @@ func (app *ApiServer) v1TracksInspect(c *fiber.Ctx) error { tracks, err := app.queries.Tracks(c.Context(), dbv1.TracksParams{ GetTracksParams: dbv1.GetTracksParams{ - MyID: myId, - Ids: ids, + MyID: myId, + Ids: ids, + AuthedWallet: app.tryGetAuthedWallet(c), }, }) if err != nil { diff --git a/api/v1_track_remixes.go b/api/v1_track_remixes.go index 8970351a..3466d08b 100644 --- a/api/v1_track_remixes.go +++ b/api/v1_track_remixes.go @@ -118,8 +118,9 @@ func (app *ApiServer) v1TrackRemixes(c *fiber.Ctx) error { tracks, err := app.queries.Tracks(c.Context(), dbv1.TracksParams{ GetTracksParams: dbv1.GetTracksParams{ - Ids: ids, - MyID: myId, + Ids: ids, + MyID: myId, + AuthedWallet: app.tryGetAuthedWallet(c), }, }) if err != nil { diff --git a/api/v1_track_remixing.go b/api/v1_track_remixing.go index e05af564..e7955983 100644 --- a/api/v1_track_remixing.go +++ b/api/v1_track_remixing.go @@ -50,8 +50,9 @@ func (app *ApiServer) v1TrackRemixing(c *fiber.Ctx) error { tracks, err := app.queries.Tracks(c.Context(), dbv1.TracksParams{ GetTracksParams: dbv1.GetTracksParams{ - Ids: trackIds, - MyID: myId, + Ids: trackIds, + MyID: myId, + AuthedWallet: app.tryGetAuthedWallet(c), }, }) diff --git a/api/v1_track_stream.go b/api/v1_track_stream.go index 649a7b93..0d9d2fb5 100644 --- a/api/v1_track_stream.go +++ b/api/v1_track_stream.go @@ -11,8 +11,9 @@ func (app *ApiServer) v1TrackStream(c *fiber.Ctx) error { tracks, err := app.queries.Tracks(c.Context(), dbv1.TracksParams{ GetTracksParams: dbv1.GetTracksParams{ - MyID: myId, - Ids: []int32{int32(trackId)}, + MyID: myId, + Ids: []int32{int32(trackId)}, + AuthedWallet: app.tryGetAuthedWallet(c), }, }) if err != nil { diff --git a/api/v1_tracks.go b/api/v1_tracks.go index 1f4ebd4a..862d2cee 100644 --- a/api/v1_tracks.go +++ b/api/v1_tracks.go @@ -53,6 +53,7 @@ func (app *ApiServer) v1Tracks(c *fiber.Ctx) error { MyID: int32(myId), Ids: ids, IncludeUnlisted: true, + AuthedWallet: app.tryGetAuthedWallet(c), }, }) if err != nil { diff --git a/api/v1_tracks_feeling_lucky.go b/api/v1_tracks_feeling_lucky.go index 895e4d7b..35169b97 100644 --- a/api/v1_tracks_feeling_lucky.go +++ b/api/v1_tracks_feeling_lucky.go @@ -31,7 +31,7 @@ func (app *ApiServer) v1TracksFeelingLucky(c *fiber.Ctx) error { "is_delete = false", "is_unlisted = false", "stem_of IS NULL", - "access_authorities IS NULL", + "(tracks.access_authorities IS NULL OR (COALESCE(@authed_wallet, '') <> '' AND EXISTS (SELECT 1 FROM unnest(tracks.access_authorities) aa WHERE lower(aa) = lower(@authed_wallet))))", "aggregate_plays.count >= 250", } if params.MinFollowers != 0 { @@ -50,8 +50,9 @@ func (app *ApiServer) v1TracksFeelingLucky(c *fiber.Ctx) error { ` rows, err := app.pool.Query(c.Context(), sql, pgx.NamedArgs{ - "limit": params.Limit, - "minFollowers": params.MinFollowers, + "limit": params.Limit, + "minFollowers": params.MinFollowers, + "authed_wallet": app.tryGetAuthedWallet(c), }) if err != nil { return err @@ -64,8 +65,9 @@ func (app *ApiServer) v1TracksFeelingLucky(c *fiber.Ctx) error { tracks, err := app.queries.Tracks(c.Context(), dbv1.TracksParams{ GetTracksParams: dbv1.GetTracksParams{ - Ids: trackIds, - MyID: app.getMyId(c), + Ids: trackIds, + MyID: app.getMyId(c), + AuthedWallet: app.tryGetAuthedWallet(c), }, }) diff --git a/api/v1_tracks_most_shared.go b/api/v1_tracks_most_shared.go index d42043e0..68f60599 100644 --- a/api/v1_tracks_most_shared.go +++ b/api/v1_tracks_most_shared.go @@ -69,8 +69,9 @@ func (app *ApiServer) v1TracksMostShared(c *fiber.Ctx) error { tracks, err := app.queries.Tracks(c.Context(), dbv1.TracksParams{ GetTracksParams: dbv1.GetTracksParams{ - Ids: trackIds, - MyID: myId, + Ids: trackIds, + MyID: myId, + AuthedWallet: app.tryGetAuthedWallet(c), }, }) diff --git a/api/v1_tracks_recent_comments.go b/api/v1_tracks_recent_comments.go index d9722410..f48ccd4f 100644 --- a/api/v1_tracks_recent_comments.go +++ b/api/v1_tracks_recent_comments.go @@ -51,8 +51,9 @@ func (app *ApiServer) v1TracksRecentComments(c *fiber.Ctx) error { tracks, err := app.queries.Tracks(c.Context(), dbv1.TracksParams{ GetTracksParams: dbv1.GetTracksParams{ - Ids: trackIds, - MyID: myId, + Ids: trackIds, + MyID: myId, + AuthedWallet: app.tryGetAuthedWallet(c), }, }) diff --git a/api/v1_tracks_recent_premium.go b/api/v1_tracks_recent_premium.go index a69a3027..dacfabf7 100644 --- a/api/v1_tracks_recent_premium.go +++ b/api/v1_tracks_recent_premium.go @@ -29,7 +29,9 @@ func (app *ApiServer) v1TracksRecentPremium(c *fiber.Ctx) error { is_available = true AND is_delete = false AND stem_of IS NULL AND - access_authorities IS NULL AND + (access_authorities IS NULL + OR (COALESCE(@authed_wallet, '') <> '' + AND EXISTS (SELECT 1 FROM unnest(access_authorities) aa WHERE lower(aa) = lower(@authed_wallet)))) AND (stream_conditions ? 'usdc_purchase' OR download_conditions ? 'usdc_purchase') AND created_at >= now() - interval '1 month' ORDER BY owner_id, created_at DESC @@ -39,9 +41,11 @@ func (app *ApiServer) v1TracksRecentPremium(c *fiber.Ctx) error { LIMIT @limit OFFSET @offset; ` - args := pgx.NamedArgs{} - args["limit"] = params.Limit - args["offset"] = params.Offset + args := pgx.NamedArgs{ + "limit": params.Limit, + "offset": params.Offset, + "authed_wallet": app.tryGetAuthedWallet(c), + } rows, err := app.pool.Query(c.Context(), sql, args) if err != nil { @@ -55,8 +59,9 @@ func (app *ApiServer) v1TracksRecentPremium(c *fiber.Ctx) error { tracks, err := app.queries.Tracks(c.Context(), dbv1.TracksParams{ GetTracksParams: dbv1.GetTracksParams{ - Ids: trackIds, - MyID: myId, + Ids: trackIds, + MyID: myId, + AuthedWallet: app.tryGetAuthedWallet(c), }, }) diff --git a/api/v1_tracks_test.go b/api/v1_tracks_test.go index 39edc68d..4458446e 100644 --- a/api/v1_tracks_test.go +++ b/api/v1_tracks_test.go @@ -41,14 +41,23 @@ func TestGetTracksExcludesAccessAuthorities(t *testing.T) { ctx := context.Background() require.NotNil(t, app.writePool, "test requires write pool") + // Use a wallet that has test signature data + gateWallet := "0x7d273271690538cf855e5b3002a0dd8c154bb060" // Track 100 has title "T1" and is returned as id eYZmn. Set access_authorities so it is gated. - _, err := app.writePool.Exec(ctx, `UPDATE tracks SET access_authorities = ARRAY['0xgate']::text[] WHERE track_id = 100 AND is_current = true`) + _, err := app.writePool.Exec(ctx, `UPDATE tracks SET access_authorities = ARRAY[$1]::text[] WHERE track_id = 100 AND is_current = true`, gateWallet) require.NoError(t, err) + // Without auth: track must not be returned var resp struct { Data []dbv1.Track } status, _ := testGet(t, app, "/v1/full/tracks?id=eYZmn", &resp) assert.Equal(t, 200, status) - assert.Len(t, resp.Data, 0, "tracks with access_authorities must not be returned") + assert.Len(t, resp.Data, 0, "tracks with access_authorities must not be returned when unauthenticated") + + // With auth signed by access authority: track must be returned + status, _ = testGetWithWallet(t, app, "/v1/full/tracks?id=eYZmn", gateWallet, &resp) + assert.Equal(t, 200, status) + assert.Len(t, resp.Data, 1, "tracks with access_authorities must be returned when request is signed by matching authority") + assert.Equal(t, "T1", resp.Data[0].Title.String) } diff --git a/api/v1_tracks_trending.go b/api/v1_tracks_trending.go index ac1a5969..322137c4 100644 --- a/api/v1_tracks_trending.go +++ b/api/v1_tracks_trending.go @@ -34,8 +34,9 @@ func (app *ApiServer) v1TracksTrending(c *fiber.Ctx) error { tracks, err := app.queries.Tracks(c.Context(), dbv1.TracksParams{ GetTracksParams: dbv1.GetTracksParams{ - Ids: trackIds, - MyID: myId, + Ids: trackIds, + MyID: myId, + AuthedWallet: app.tryGetAuthedWallet(c), }, }) diff --git a/api/v1_tracks_trending_underground.go b/api/v1_tracks_trending_underground.go index 659f3de7..8fdab11a 100644 --- a/api/v1_tracks_trending_underground.go +++ b/api/v1_tracks_trending_underground.go @@ -84,8 +84,9 @@ func (app *ApiServer) v1TracksTrendingUnderground(c *fiber.Ctx) error { tracks, err := app.queries.Tracks(c.Context(), dbv1.TracksParams{ GetTracksParams: dbv1.GetTracksParams{ - Ids: trackIds, - MyID: myId, + Ids: trackIds, + MyID: myId, + AuthedWallet: app.tryGetAuthedWallet(c), }, }) diff --git a/api/v1_tracks_trending_underground_winners.go b/api/v1_tracks_trending_underground_winners.go index 4cbf579e..72dba1e7 100644 --- a/api/v1_tracks_trending_underground_winners.go +++ b/api/v1_tracks_trending_underground_winners.go @@ -29,8 +29,9 @@ func (app *ApiServer) v1TracksTrendingUndergroundWinners(c *fiber.Ctx) error { tracks, err := app.queries.Tracks(c.Context(), dbv1.TracksParams{ GetTracksParams: dbv1.GetTracksParams{ - Ids: trackIds, - MyID: myId, + Ids: trackIds, + MyID: myId, + AuthedWallet: app.tryGetAuthedWallet(c), }, }) if err != nil { diff --git a/api/v1_tracks_trending_winners.go b/api/v1_tracks_trending_winners.go index 31a477ca..8f189338 100644 --- a/api/v1_tracks_trending_winners.go +++ b/api/v1_tracks_trending_winners.go @@ -29,8 +29,9 @@ func (app *ApiServer) v1TracksTrendingWinners(c *fiber.Ctx) error { tracks, err := app.queries.Tracks(c.Context(), dbv1.TracksParams{ GetTracksParams: dbv1.GetTracksParams{ - Ids: trackIds, - MyID: myId, + Ids: trackIds, + MyID: myId, + AuthedWallet: app.tryGetAuthedWallet(c), }, }) if err != nil { diff --git a/api/v1_tracks_usdc_purchase.go b/api/v1_tracks_usdc_purchase.go index ca7fd80f..faf29ef8 100644 --- a/api/v1_tracks_usdc_purchase.go +++ b/api/v1_tracks_usdc_purchase.go @@ -59,8 +59,9 @@ func (app *ApiServer) v1TracksUsdcPurchase(c *fiber.Ctx) error { tracks, err := app.queries.Tracks(c.Context(), dbv1.TracksParams{ GetTracksParams: dbv1.GetTracksParams{ - Ids: trackIds, - MyID: myId, + Ids: trackIds, + MyID: myId, + AuthedWallet: app.tryGetAuthedWallet(c), }, }) diff --git a/api/v1_users_albums.go b/api/v1_users_albums.go index 5b9ea558..8b67f65b 100644 --- a/api/v1_users_albums.go +++ b/api/v1_users_albums.go @@ -87,7 +87,8 @@ func (app *ApiServer) v1UserAlbums(c *fiber.Ctx) error { Ids: ids, MyID: myId, }, - OmitTracks: true, + OmitTracks: true, + AuthedWallet: app.tryGetAuthedWallet(c), }) if err != nil { return err diff --git a/api/v1_users_feed.go b/api/v1_users_feed.go index b67bb5ff..024f85e6 100644 --- a/api/v1_users_feed.go +++ b/api/v1_users_feed.go @@ -92,7 +92,9 @@ func (app *ApiServer) v1UsersFeed(c *fiber.Ctx) error { AND is_unlisted = false AND is_delete = false AND stem_of is null - AND access_authorities IS NULL + AND (access_authorities IS NULL + OR (COALESCE(@authed_wallet, '') <> '' + AND EXISTS (SELECT 1 FROM unnest(access_authorities) aa WHERE lower(aa) = lower(@authed_wallet)))) ) UNION ALL @@ -124,12 +126,13 @@ func (app *ApiServer) v1UsersFeed(c *fiber.Ctx) error { ` rows, err := app.pool.Query(c.Context(), sql, pgx.NamedArgs{ - "userId": app.getUserId(c), - "before": time.Now(), - "limit": params.Limit, - "offset": params.Offset, - "filter": params.Filter, // original, repost - "followeeIds": followeeIds, + "userId": app.getUserId(c), + "before": time.Now(), + "limit": params.Limit, + "offset": params.Offset, + "filter": params.Filter, // original, repost + "followeeIds": followeeIds, + "authed_wallet": app.tryGetAuthedWallet(c), }) if err != nil { return err @@ -161,9 +164,10 @@ func (app *ApiServer) v1UsersFeed(c *fiber.Ctx) error { } loaded, err := app.queries.Parallel(c.Context(), dbv1.ParallelParams{ - TrackIds: trackIds, - PlaylistIds: playlistIds, - MyID: myId, + TrackIds: trackIds, + PlaylistIds: playlistIds, + MyID: myId, + AuthedWallet: app.tryGetAuthedWallet(c), }) if err != nil { return err diff --git a/api/v1_users_history.go b/api/v1_users_history.go index bc93ce85..15af83a3 100644 --- a/api/v1_users_history.go +++ b/api/v1_users_history.go @@ -135,6 +135,7 @@ func (app *ApiServer) v1UsersHistory(c *fiber.Ctx) error { GetTracksParams: dbv1.GetTracksParams{ Ids: trackIds, MyID: myId, + AuthedWallet: app.tryGetAuthedWallet(c), IncludeUnlisted: true, }, }) diff --git a/api/v1_users_library_playlists.go b/api/v1_users_library_playlists.go index 49e737d5..92a256f4 100644 --- a/api/v1_users_library_playlists.go +++ b/api/v1_users_library_playlists.go @@ -164,7 +164,8 @@ func (app *ApiServer) v1UsersLibraryPlaylists(c *fiber.Ctx) error { Ids: ids, MyID: myId, }, - OmitTracks: true, + OmitTracks: true, + AuthedWallet: app.tryGetAuthedWallet(c), }) if err != nil { return err diff --git a/api/v1_users_library_tracks.go b/api/v1_users_library_tracks.go index 0b6598d8..7fc74fd8 100644 --- a/api/v1_users_library_tracks.go +++ b/api/v1_users_library_tracks.go @@ -161,6 +161,7 @@ func (app *ApiServer) v1UsersLibraryTracks(c *fiber.Ctx) error { GetTracksParams: dbv1.GetTracksParams{ Ids: trackIds, MyID: myId, + AuthedWallet: app.tryGetAuthedWallet(c), IncludeUnlisted: true, }, }) diff --git a/api/v1_users_listen_counts_monthly.go b/api/v1_users_listen_counts_monthly.go index 3e6820f7..077aa01e 100644 --- a/api/v1_users_listen_counts_monthly.go +++ b/api/v1_users_listen_counts_monthly.go @@ -25,7 +25,10 @@ func (app *ApiServer) v1UsersListenCountsMonthly(c *fiber.Ctx) error { SUM(count) AS count FROM aggregate_monthly_plays WHERE play_item_id IN ( - SELECT track_id FROM tracks WHERE owner_id = @userId AND stem_of IS NULL AND access_authorities IS NULL + SELECT track_id FROM tracks WHERE owner_id = @userId AND stem_of IS NULL + AND (access_authorities IS NULL + OR (COALESCE(@authed_wallet, '') <> '' + AND EXISTS (SELECT 1 FROM unnest(access_authorities) aa WHERE lower(aa) = lower(@authed_wallet)))) ) AND timestamp >= @startTime AND timestamp < @endTime @@ -34,9 +37,10 @@ func (app *ApiServer) v1UsersListenCountsMonthly(c *fiber.Ctx) error { ` rows, err := app.pool.Query(c.Context(), sql, pgx.NamedArgs{ - "userId": app.getUserId(c), - "startTime": params.StartTime, - "endTime": params.EndTime, + "userId": app.getUserId(c), + "startTime": params.StartTime, + "endTime": params.EndTime, + "authed_wallet": app.tryGetAuthedWallet(c), }) if err != nil { return err diff --git a/api/v1_users_playlists.go b/api/v1_users_playlists.go index cc607b4a..dcfaad37 100644 --- a/api/v1_users_playlists.go +++ b/api/v1_users_playlists.go @@ -87,7 +87,8 @@ func (app *ApiServer) v1UserPlaylists(c *fiber.Ctx) error { Ids: ids, MyID: myId, }, - OmitTracks: true, + OmitTracks: true, + AuthedWallet: app.tryGetAuthedWallet(c), }) if err != nil { return err diff --git a/api/v1_users_recommended_tracks.go b/api/v1_users_recommended_tracks.go index 1dd7c855..26ff2c52 100644 --- a/api/v1_users_recommended_tracks.go +++ b/api/v1_users_recommended_tracks.go @@ -78,17 +78,20 @@ func (app *ApiServer) v1UsersRecommendedTracks(c *fiber.Ctx) error { AND t.is_current = true AND t.is_delete = false AND t.stem_of IS NULL - AND t.access_authorities IS NULL + AND (t.access_authorities IS NULL + OR (COALESCE(@authed_wallet, '') <> '' + AND EXISTS (SELECT 1 FROM unnest(t.access_authorities) aa WHERE lower(aa) = lower(@authed_wallet)))) AND u.is_deactivated = false ORDER BY random() LIMIT 10 ` rows, err := app.pool.Query(c.Context(), sql, pgx.NamedArgs{ - "limit": params.Limit, - "offset": params.Offset, - "timeRange": timeRange, - "userId": app.getUserId(c), + "limit": params.Limit, + "offset": params.Offset, + "timeRange": timeRange, + "userId": app.getUserId(c), + "authed_wallet": app.tryGetAuthedWallet(c), }) if err != nil { return err @@ -101,8 +104,9 @@ func (app *ApiServer) v1UsersRecommendedTracks(c *fiber.Ctx) error { tracks, err := app.queries.Tracks(c.Context(), dbv1.TracksParams{ GetTracksParams: dbv1.GetTracksParams{ - Ids: trackIds, - MyID: myId, + Ids: trackIds, + MyID: myId, + AuthedWallet: app.tryGetAuthedWallet(c), }, }) diff --git a/api/v1_users_related.go b/api/v1_users_related.go index 0d3ac9be..308f201a 100644 --- a/api/v1_users_related.go +++ b/api/v1_users_related.go @@ -49,7 +49,9 @@ func (app *ApiServer) v1UsersRelated(c *fiber.Ctx) error { AND t.is_unlisted IS false AND t.is_available IS true AND t.stem_of IS NULL - AND t.access_authorities IS NULL + AND (t.access_authorities IS NULL + OR (COALESCE(@authed_wallet, '') <> '' + AND EXISTS (SELECT 1 FROM unnest(t.access_authorities) aa WHERE lower(aa) = lower(@authed_wallet)))) AND owner_id = @userId GROUP BY genre ORDER BY count(*) DESC @@ -102,7 +104,9 @@ func (app *ApiServer) v1UsersRelated(c *fiber.Ctx) error { AND is_unlisted = false AND is_available = true AND stem_of IS NULL - AND access_authorities IS NULL + AND (access_authorities IS NULL + OR (COALESCE(@authed_wallet, '') <> '' + AND EXISTS (SELECT 1 FROM unnest(access_authorities) aa WHERE lower(aa) = lower(@authed_wallet)))) AND genre IS NOT NULL GROUP BY genre ORDER BY COUNT(*) DESC @@ -178,5 +182,6 @@ func (app *ApiServer) v1UsersRelated(c *fiber.Ctx) error { "filterFollowed": params.FilterFollowed, "limit": limit, "offset": params.Offset, + "authed_wallet": app.tryGetAuthedWallet(c), }) } diff --git a/api/v1_users_reposts.go b/api/v1_users_reposts.go index ab4bf0fe..fe7903db 100644 --- a/api/v1_users_reposts.go +++ b/api/v1_users_reposts.go @@ -80,9 +80,10 @@ func (app *ApiServer) v1UsersReposts(c *fiber.Ctx) error { } loaded, err := app.queries.Parallel(c.Context(), dbv1.ParallelParams{ - TrackIds: trackIds, - PlaylistIds: playlistIds, - MyID: myId, + TrackIds: trackIds, + PlaylistIds: playlistIds, + MyID: myId, + AuthedWallet: app.tryGetAuthedWallet(c), }) if err != nil { return err diff --git a/api/v1_users_tags.go b/api/v1_users_tags.go index 75e3cf80..c1ef0f95 100644 --- a/api/v1_users_tags.go +++ b/api/v1_users_tags.go @@ -27,7 +27,9 @@ func (app *ApiServer) v1UsersTags(c *fiber.Ctx) error { AND is_unlisted = false AND is_delete = false AND stem_of is null - AND access_authorities IS NULL + AND (access_authorities IS NULL + OR (COALESCE(@authed_wallet, '') <> '' + AND EXISTS (SELECT 1 FROM unnest(access_authorities) aa WHERE lower(aa) = lower(@authed_wallet)))) ) AS split_tags WHERE tag != '' GROUP BY tag @@ -36,8 +38,9 @@ func (app *ApiServer) v1UsersTags(c *fiber.Ctx) error { ` rows, err := app.pool.Query(c.Context(), sql, pgx.NamedArgs{ - "userId": app.getUserId(c), - "limit": params.Limit, + "userId": app.getUserId(c), + "limit": params.Limit, + "authed_wallet": app.tryGetAuthedWallet(c), }) if err != nil { return err diff --git a/api/v1_users_tracks.go b/api/v1_users_tracks.go index f81e7b02..26710beb 100644 --- a/api/v1_users_tracks.go +++ b/api/v1_users_tracks.go @@ -76,15 +76,18 @@ func (app *ApiServer) v1UserTracks(c *fiber.Ctx) error { AND t.is_available = true AND ` + trackFilter + ` AND t.stem_of is null - AND t.access_authorities IS NULL` + gateFilter + ` + AND (t.access_authorities IS NULL + OR (COALESCE(@authed_wallet, '') <> '' + AND EXISTS (SELECT 1 FROM unnest(t.access_authorities) aa WHERE lower(aa) = lower(@authed_wallet))))` + gateFilter + ` ORDER BY (CASE WHEN t.track_id = u.artist_pick_track_id THEN 0 ELSE 1 END), ` + orderClause + ` LIMIT @limit OFFSET @offset ` args := pgx.NamedArgs{ - "user_id": userId, - "my_id": myId, + "user_id": userId, + "my_id": myId, + "authed_wallet": app.tryGetAuthedWallet(c), } args["limit"] = params.Limit args["offset"] = params.Offset @@ -101,8 +104,9 @@ func (app *ApiServer) v1UserTracks(c *fiber.Ctx) error { tracks, err := app.queries.Tracks(c.Context(), dbv1.TracksParams{ GetTracksParams: dbv1.GetTracksParams{ - Ids: ids, - MyID: myId, + Ids: ids, + MyID: myId, + AuthedWallet: app.tryGetAuthedWallet(c), }, }) if err != nil { diff --git a/api/v1_users_tracks_ai_attributed.go b/api/v1_users_tracks_ai_attributed.go index 18d7c5ed..5d8f45c9 100644 --- a/api/v1_users_tracks_ai_attributed.go +++ b/api/v1_users_tracks_ai_attributed.go @@ -71,15 +71,18 @@ func (app *ApiServer) v1UserTracksAiAttributed(c *fiber.Ctx) error { AND t.is_available = true AND ` + trackFilter + ` AND t.stem_of is null - AND t.access_authorities IS NULL + AND (t.access_authorities IS NULL + OR (COALESCE(@authed_wallet, '') <> '' + AND EXISTS (SELECT 1 FROM unnest(t.access_authorities) aa WHERE lower(aa) = lower(@authed_wallet)))) ORDER BY ` + orderClause + ` LIMIT @limit OFFSET @offset ` args := pgx.NamedArgs{ - "user_id": userId, - "my_id": myId, + "user_id": userId, + "my_id": myId, + "authed_wallet": app.tryGetAuthedWallet(c), } args["limit"] = params.Limit args["offset"] = params.Offset @@ -96,8 +99,9 @@ func (app *ApiServer) v1UserTracksAiAttributed(c *fiber.Ctx) error { tracks, err := app.queries.Tracks(c.Context(), dbv1.TracksParams{ GetTracksParams: dbv1.GetTracksParams{ - Ids: ids, - MyID: myId, + Ids: ids, + MyID: myId, + AuthedWallet: app.tryGetAuthedWallet(c), }, }) if err != nil { diff --git a/api/v1_users_tracks_count.go b/api/v1_users_tracks_count.go index 4ae31a15..7c8abe1d 100644 --- a/api/v1_users_tracks_count.go +++ b/api/v1_users_tracks_count.go @@ -43,11 +43,14 @@ func (app *ApiServer) v1UserTracksCount(c *fiber.Ctx) error { AND t.is_available = true AND ` + trackFilter + ` AND t.stem_of is null - AND t.access_authorities IS NULL` + gateFilter + AND (t.access_authorities IS NULL + OR (COALESCE(@authed_wallet, '') <> '' + AND EXISTS (SELECT 1 FROM unnest(t.access_authorities) aa WHERE lower(aa) = lower(@authed_wallet))))` + gateFilter args := pgx.NamedArgs{ - "user_id": userId, - "my_id": myId, + "user_id": userId, + "my_id": myId, + "authed_wallet": app.tryGetAuthedWallet(c), } var count int