Skip to content

fix(mediorum): case-insensitive access authority check#203

Open
rickyrombo wants to merge 4 commits intomainfrom
fix/case-insensitive-access-authority
Open

fix(mediorum): case-insensitive access authority check#203
rickyrombo wants to merge 4 commits intomainfrom
fix/case-insensitive-access-authority

Conversation

@rickyrombo
Copy link
Copy Markdown
Contributor

Summary

  • Ethereum addresses can have mixed casing (EIP-55 checksummed vs lowercase), causing access authority lookups in management_keys to fail when casing doesn't match exactly.
  • Updated all three streaming auth paths (requireRegisteredSignature, serveTrack, streamTrackGRPC) to use LOWER(address) = LOWER(?) for case-insensitive comparison.
  • This is consistent with the existing strings.EqualFold used for validator/peer wallet checks.

Test plan

  • Verify streaming works when signer wallet is checksummed but DB stores lowercase address (and vice versa)
  • Confirm gated content access still enforces management_keys correctly
  • Run make test-mediorum

🤖 Generated with Claude Code

Ethereum addresses can vary in casing (checksummed vs lowercase). Use
LOWER() on both sides of the management_keys address comparison so
streaming auth matches regardless of case, consistent with the existing
EqualFold check for validator/peer wallets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes gated streaming authorization failures caused by mixed-case Ethereum addresses by making management_keys address checks case-insensitive across Mediorum’s HTTP middleware, dev HTTP track streaming, and dev gRPC streaming paths.

Changes:

  • Update management_keys authorization queries to compare address case-insensitively via LOWER(address) = LOWER(?).
  • Apply the same logic consistently across requireRegisteredSignature, serveTrack, and streamTrackGRPC.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
pkg/mediorum/server/serve_blob.go Makes access-authority (management_keys) checks case-insensitive in HTTP streaming auth + dev track streaming.
pkg/mediorum/server/serve_blob_grpc.go Makes access-authority (management_keys) checks case-insensitive in the dev gRPC streaming path.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pkg/mediorum/server/serve_blob.go Outdated
if trackID != "" && managementKeyCount > 0 {
var count int
s.crud.DB.Raw("SELECT COUNT(*) FROM management_keys WHERE track_id = ? AND address = ?", trackID, sig.SignerWallet).Scan(&count)
s.crud.DB.Raw("SELECT COUNT(*) FROM management_keys WHERE track_id = ? AND LOWER(address) = LOWER(?)", trackID, sig.SignerWallet).Scan(&count)
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using LOWER(address) in the WHERE clause will generally prevent Postgres from using the existing btree index on (track_id, address) (see migration adding idx_management_keys_track_id_address). Since this check runs on the streaming auth path, consider normalizing addresses on write (store lowercase) and compare with address = LOWER(?) OR add a functional/composite index on (track_id, LOWER(address)) to avoid scanning all keys for a track.

Suggested change
s.crud.DB.Raw("SELECT COUNT(*) FROM management_keys WHERE track_id = ? AND LOWER(address) = LOWER(?)", trackID, sig.SignerWallet).Scan(&count)
normalizedSignerWallet := strings.ToLower(sig.SignerWallet)
s.crud.DB.Raw("SELECT COUNT(*) FROM management_keys WHERE track_id = ? AND address = ?", trackID, normalizedSignerWallet).Scan(&count)

Copilot uses AI. Check for mistakes.
Comment thread pkg/mediorum/server/serve_blob.go Outdated

var count int
ss.crud.DB.Raw("SELECT COUNT(*) FROM management_keys WHERE track_id = ? AND address = ?", trackId, sig.SignerWallet).Scan(&count)
ss.crud.DB.Raw("SELECT COUNT(*) FROM management_keys WHERE track_id = ? AND LOWER(address) = LOWER(?)", trackId, sig.SignerWallet).Scan(&count)
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same index-usage concern here: LOWER(address) likely bypasses the existing (track_id, address) index, which can increase per-request DB work on this endpoint. Consider normalizing stored addresses to lowercase and comparing directly, or adding an index on (track_id, LOWER(address)).

Suggested change
ss.crud.DB.Raw("SELECT COUNT(*) FROM management_keys WHERE track_id = ? AND LOWER(address) = LOWER(?)", trackId, sig.SignerWallet).Scan(&count)
normalizedSignerWallet := strings.ToLower(sig.SignerWallet)
ss.crud.DB.Raw("SELECT COUNT(*) FROM management_keys WHERE track_id = ? AND address = ?", trackId, normalizedSignerWallet).Scan(&count)

Copilot uses AI. Check for mistakes.
Comment thread pkg/mediorum/server/serve_blob_grpc.go Outdated

var count int
s.crud.DB.Raw("SELECT COUNT(*) FROM management_keys WHERE track_id = ? AND address = ?", trackId, ethAddress).Scan(&count)
s.crud.DB.Raw("SELECT COUNT(*) FROM management_keys WHERE track_id = ? AND LOWER(address) = LOWER(?)", trackId, ethAddress).Scan(&count)
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This query change to LOWER(address) is likely to bypass the existing (track_id, address) index in Postgres. Because gRPC streaming can be high-volume, consider normalizing stored addresses (lowercase) and comparing directly, or adding a functional/composite index on (track_id, LOWER(address)) to keep auth checks efficient.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied in dceccd0. All three locations now normalize the address to lowercase in Go (strings.ToLower) before passing it to the SQL query, so the existing (track_id, address) index is preserved.

Comment on lines 526 to 530
// If track has access_authorities (management_keys), ONLY those signers may authorize - not validator keys
if trackID != "" && managementKeyCount > 0 {
var count int
s.crud.DB.Raw("SELECT COUNT(*) FROM management_keys WHERE track_id = ? AND address = ?", trackID, sig.SignerWallet).Scan(&count)
s.crud.DB.Raw("SELECT COUNT(*) FROM management_keys WHERE track_id = ? AND LOWER(address) = LOWER(?)", trackID, sig.SignerWallet).Scan(&count)
if count == 0 {
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are existing unit tests for requireRegisteredSignature, but none cover the access_authorities/management_keys path with mixed-case addresses. Add a test where the stored management_keys.address casing differs from the signer wallet (checksummed vs lowercase) to ensure this regression stays fixed.

Copilot uses AI. Check for mistakes.
Copilot AI and others added 2 commits April 10, 2026 19:02
Ensures management_keys.address is always stored lowercase so streaming
auth comparisons match regardless of the casing in the original tx.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants