From 0706132186ff69e2d000349f10781d23de489573 Mon Sep 17 00:00:00 2001 From: Evan Jarrett Date: Sat, 11 Oct 2025 23:29:56 -0500 Subject: [PATCH] code clean up --- cmd/appview/main.go | 2 +- cmd/appview/serve.go | 25 +++--- pkg/{ => appview}/middleware/registry.go | 2 +- pkg/{ => appview}/storage/hold_cache.go | 0 pkg/{ => appview}/storage/proxy_blob_store.go | 0 .../storage/routing_repository.go | 0 pkg/auth/scope.go | 7 ++ pkg/auth/types.go | 8 -- pkg/hold/handlers.go | 84 +++++++++++++++++ pkg/hold/types.go | 89 ------------------- 10 files changed, 105 insertions(+), 112 deletions(-) rename pkg/{ => appview}/middleware/registry.go (99%) rename pkg/{ => appview}/storage/hold_cache.go (100%) rename pkg/{ => appview}/storage/proxy_blob_store.go (100%) rename pkg/{ => appview}/storage/routing_repository.go (100%) delete mode 100644 pkg/auth/types.go delete mode 100644 pkg/hold/types.go diff --git a/cmd/appview/main.go b/cmd/appview/main.go index 9f98904..85e117d 100644 --- a/cmd/appview/main.go +++ b/cmd/appview/main.go @@ -8,7 +8,7 @@ import ( _ "github.com/distribution/distribution/v3/registry/storage/driver/inmemory" // Register our custom middleware - _ "atcr.io/pkg/middleware" + _ "atcr.io/pkg/appview/middleware" ) func main() { diff --git a/cmd/appview/serve.go b/cmd/appview/serve.go index 461b2bc..e00312b 100644 --- a/cmd/appview/serve.go +++ b/cmd/appview/serve.go @@ -19,16 +19,15 @@ import ( sqlite3 "github.com/mattn/go-sqlite3" "github.com/spf13/cobra" + "atcr.io/pkg/appview/middleware" "atcr.io/pkg/auth/oauth" "atcr.io/pkg/auth/token" - "atcr.io/pkg/middleware" // UI components "atcr.io/pkg/appview" "atcr.io/pkg/appview/db" uihandlers "atcr.io/pkg/appview/handlers" "atcr.io/pkg/appview/jetstream" - appmiddleware "atcr.io/pkg/appview/middleware" "github.com/gorilla/mux" ) @@ -474,7 +473,7 @@ func initializeUIRoutes(database *sql.DB, readOnlyDB *sql.DB, sessionStore *db.S // Public routes (with optional auth for navbar) // SECURITY: Public pages use read-only DB - router.Handle("/", appmiddleware.OptionalAuth(sessionStore, database)( + router.Handle("/", middleware.OptionalAuth(sessionStore, database)( &uihandlers.HomeHandler{ DB: readOnlyDB, Templates: templates, @@ -482,7 +481,7 @@ func initializeUIRoutes(database *sql.DB, readOnlyDB *sql.DB, sessionStore *db.S }, )).Methods("GET") - router.Handle("/api/recent-pushes", appmiddleware.OptionalAuth(sessionStore, database)( + router.Handle("/api/recent-pushes", middleware.OptionalAuth(sessionStore, database)( &uihandlers.RecentPushesHandler{ DB: readOnlyDB, Templates: templates, @@ -491,7 +490,7 @@ func initializeUIRoutes(database *sql.DB, readOnlyDB *sql.DB, sessionStore *db.S )).Methods("GET") // SECURITY: Search uses read-only DB to prevent writes and limit access to sensitive tables - router.Handle("/search", appmiddleware.OptionalAuth(sessionStore, database)( + router.Handle("/search", middleware.OptionalAuth(sessionStore, database)( &uihandlers.SearchHandler{ DB: readOnlyDB, Templates: templates, @@ -499,7 +498,7 @@ func initializeUIRoutes(database *sql.DB, readOnlyDB *sql.DB, sessionStore *db.S }, )).Methods("GET") - router.Handle("/api/search-results", appmiddleware.OptionalAuth(sessionStore, database)( + router.Handle("/api/search-results", middleware.OptionalAuth(sessionStore, database)( &uihandlers.SearchResultsHandler{ DB: readOnlyDB, Templates: templates, @@ -508,7 +507,7 @@ func initializeUIRoutes(database *sql.DB, readOnlyDB *sql.DB, sessionStore *db.S )).Methods("GET") // API route for repository stats (public, read-only) - router.Handle("/api/stats/{handle}/{repository}", appmiddleware.OptionalAuth(sessionStore, database)( + router.Handle("/api/stats/{handle}/{repository}", middleware.OptionalAuth(sessionStore, database)( &uihandlers.GetStatsHandler{ DB: readOnlyDB, Directory: oauthApp.Directory(), @@ -516,7 +515,7 @@ func initializeUIRoutes(database *sql.DB, readOnlyDB *sql.DB, sessionStore *db.S )).Methods("GET") // API routes for stars (require authentication) - router.Handle("/api/stars/{handle}/{repository}", appmiddleware.RequireAuth(sessionStore, database)( + router.Handle("/api/stars/{handle}/{repository}", middleware.RequireAuth(sessionStore, database)( &uihandlers.StarRepositoryHandler{ DB: database, // Needs write access Directory: oauthApp.Directory(), @@ -524,7 +523,7 @@ func initializeUIRoutes(database *sql.DB, readOnlyDB *sql.DB, sessionStore *db.S }, )).Methods("POST") - router.Handle("/api/stars/{handle}/{repository}", appmiddleware.RequireAuth(sessionStore, database)( + router.Handle("/api/stars/{handle}/{repository}", middleware.RequireAuth(sessionStore, database)( &uihandlers.UnstarRepositoryHandler{ DB: database, // Needs write access Directory: oauthApp.Directory(), @@ -532,7 +531,7 @@ func initializeUIRoutes(database *sql.DB, readOnlyDB *sql.DB, sessionStore *db.S }, )).Methods("DELETE") - router.Handle("/api/stars/{handle}/{repository}", appmiddleware.OptionalAuth(sessionStore, database)( + router.Handle("/api/stars/{handle}/{repository}", middleware.OptionalAuth(sessionStore, database)( &uihandlers.CheckStarHandler{ DB: readOnlyDB, // Read-only check Directory: oauthApp.Directory(), @@ -540,7 +539,7 @@ func initializeUIRoutes(database *sql.DB, readOnlyDB *sql.DB, sessionStore *db.S }, )).Methods("GET") - router.Handle("/u/{handle}", appmiddleware.OptionalAuth(sessionStore, database)( + router.Handle("/u/{handle}", middleware.OptionalAuth(sessionStore, database)( &uihandlers.UserPageHandler{ DB: readOnlyDB, Templates: templates, @@ -548,7 +547,7 @@ func initializeUIRoutes(database *sql.DB, readOnlyDB *sql.DB, sessionStore *db.S }, )).Methods("GET") - router.Handle("/r/{handle}/{repository}", appmiddleware.OptionalAuth(sessionStore, database)( + router.Handle("/r/{handle}/{repository}", middleware.OptionalAuth(sessionStore, database)( &uihandlers.RepositoryPageHandler{ DB: readOnlyDB, Templates: templates, @@ -560,7 +559,7 @@ func initializeUIRoutes(database *sql.DB, readOnlyDB *sql.DB, sessionStore *db.S // Authenticated routes authRouter := router.NewRoute().Subrouter() - authRouter.Use(appmiddleware.RequireAuth(sessionStore, database)) + authRouter.Use(middleware.RequireAuth(sessionStore, database)) authRouter.Handle("/settings", &uihandlers.SettingsHandler{ Templates: templates, diff --git a/pkg/middleware/registry.go b/pkg/appview/middleware/registry.go similarity index 99% rename from pkg/middleware/registry.go rename to pkg/appview/middleware/registry.go index a0e9660..782383c 100644 --- a/pkg/middleware/registry.go +++ b/pkg/appview/middleware/registry.go @@ -14,10 +14,10 @@ import ( "github.com/distribution/distribution/v3/registry/storage/driver" "github.com/distribution/reference" + "atcr.io/pkg/appview/storage" "atcr.io/pkg/atproto" "atcr.io/pkg/auth" "atcr.io/pkg/auth/oauth" - "atcr.io/pkg/storage" ) // Global refresher instance (set by main.go) diff --git a/pkg/storage/hold_cache.go b/pkg/appview/storage/hold_cache.go similarity index 100% rename from pkg/storage/hold_cache.go rename to pkg/appview/storage/hold_cache.go diff --git a/pkg/storage/proxy_blob_store.go b/pkg/appview/storage/proxy_blob_store.go similarity index 100% rename from pkg/storage/proxy_blob_store.go rename to pkg/appview/storage/proxy_blob_store.go diff --git a/pkg/storage/routing_repository.go b/pkg/appview/storage/routing_repository.go similarity index 100% rename from pkg/storage/routing_repository.go rename to pkg/appview/storage/routing_repository.go diff --git a/pkg/auth/scope.go b/pkg/auth/scope.go index faaff55..93b517b 100644 --- a/pkg/auth/scope.go +++ b/pkg/auth/scope.go @@ -5,6 +5,13 @@ import ( "strings" ) +// AccessEntry represents access permissions for a resource +type AccessEntry struct { + Type string `json:"type"` // "repository" + Name string `json:"name,omitempty"` // e.g., "alice/myapp" + Actions []string `json:"actions,omitempty"` // e.g., ["pull", "push"] +} + // ParseScope parses Docker registry scope strings into AccessEntry structures // Scope format: "repository:alice/myapp:pull,push" // Multiple scopes can be provided diff --git a/pkg/auth/types.go b/pkg/auth/types.go deleted file mode 100644 index e5ffa1c..0000000 --- a/pkg/auth/types.go +++ /dev/null @@ -1,8 +0,0 @@ -package auth - -// AccessEntry represents access permissions for a resource -type AccessEntry struct { - Type string `json:"type"` // "repository" - Name string `json:"name,omitempty"` // e.g., "alice/myapp" - Actions []string `json:"actions,omitempty"` // e.g., ["pull", "push"] -} diff --git a/pkg/hold/handlers.go b/pkg/hold/handlers.go index 5b628e3..dda4a28 100644 --- a/pkg/hold/handlers.go +++ b/pkg/hold/handlers.go @@ -12,6 +12,29 @@ import ( "atcr.io/pkg/atproto" ) +// PresignedURLOperation defines the type of presigned URL operation +type PresignedURLOperation string + +const ( + OperationGet PresignedURLOperation = "GET" + OperationHead PresignedURLOperation = "HEAD" + OperationPut PresignedURLOperation = "PUT" +) + +// PresignedURLRequest represents a request for a presigned URL (GET, HEAD, or PUT) +type PresignedURLRequest struct { + Operation PresignedURLOperation `json:"operation"` + DID string `json:"did"` + Digest string `json:"digest"` + Size int64 `json:"size,omitempty"` // Only required for PUT operations +} + +// PresignedURLResponse contains the presigned URL +type PresignedURLResponse struct { + URL string `json:"url"` + ExpiresAt time.Time `json:"expires_at"` +} + // HandlePresignedURL handles presigned URL requests (GET, HEAD, or PUT) // Operation type is specified in the request body func (s *HoldService) HandlePresignedURL(w http.ResponseWriter, r *http.Request) { @@ -232,6 +255,18 @@ func (s *HoldService) HandleProxyPut(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusCreated) } +// StartMultipartUploadRequest initiates a multipart upload +type StartMultipartUploadRequest struct { + DID string `json:"did"` + Digest string `json:"digest"` +} + +// StartMultipartUploadResponse contains the multipart upload ID +type StartMultipartUploadResponse struct { + UploadID string `json:"upload_id"` + ExpiresAt time.Time `json:"expires_at"` +} + // HandleStartMultipart initiates a multipart upload func (s *HoldService) HandleStartMultipart(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { @@ -276,6 +311,20 @@ func (s *HoldService) HandleStartMultipart(w http.ResponseWriter, r *http.Reques json.NewEncoder(w).Encode(resp) } +// GetPartURLRequest requests a presigned URL for a specific part +type GetPartURLRequest struct { + DID string `json:"did"` + Digest string `json:"digest"` + UploadID string `json:"upload_id"` + PartNumber int `json:"part_number"` +} + +// GetPartURLResponse contains the presigned URL for a part +type GetPartURLResponse struct { + URL string `json:"url"` + ExpiresAt time.Time `json:"expires_at"` +} + // HandleGetPartURL generates a presigned URL for uploading a specific part func (s *HoldService) HandleGetPartURL(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { @@ -325,6 +374,20 @@ func (s *HoldService) HandleGetPartURL(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(resp) } +// CompleteMultipartRequest completes a multipart upload +type CompleteMultipartRequest struct { + DID string `json:"did"` + Digest string `json:"digest"` + UploadID string `json:"upload_id"` + Parts []CompletedPart `json:"parts"` +} + +// CompletedPart represents an uploaded part with its ETag +type CompletedPart struct { + PartNumber int `json:"part_number"` + ETag string `json:"etag"` +} + // HandleCompleteMultipart completes a multipart upload func (s *HoldService) HandleCompleteMultipart(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { @@ -381,6 +444,13 @@ func (s *HoldService) HandleCompleteMultipart(w http.ResponseWriter, r *http.Req }) } +// AbortMultipartRequest aborts an in-progress upload +type AbortMultipartRequest struct { + DID string `json:"did"` + Digest string `json:"digest"` + UploadID string `json:"upload_id"` +} + // HandleAbortMultipart aborts an in-progress multipart upload func (s *HoldService) HandleAbortMultipart(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { @@ -427,6 +497,20 @@ func (s *HoldService) HandleAbortMultipart(w http.ResponseWriter, r *http.Reques }) } +// RegisterRequest represents a request to register this hold in a user's PDS +type RegisterRequest struct { + DID string `json:"did"` + AccessToken string `json:"access_token"` + PDSEndpoint string `json:"pds_endpoint"` +} + +// RegisterResponse contains the registration result +type RegisterResponse struct { + HoldURI string `json:"hold_uri"` + CrewURI string `json:"crew_uri"` + Message string `json:"message"` +} + // HandleRegister registers this hold service in a user's PDS (manual endpoint) func (s *HoldService) HandleRegister(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { diff --git a/pkg/hold/types.go b/pkg/hold/types.go deleted file mode 100644 index 44d491e..0000000 --- a/pkg/hold/types.go +++ /dev/null @@ -1,89 +0,0 @@ -package hold - -import ( - "time" -) - -// PresignedURLOperation defines the type of presigned URL operation -type PresignedURLOperation string - -const ( - OperationGet PresignedURLOperation = "GET" - OperationHead PresignedURLOperation = "HEAD" - OperationPut PresignedURLOperation = "PUT" -) - -// PresignedURLRequest represents a request for a presigned URL (GET, HEAD, or PUT) -type PresignedURLRequest struct { - Operation PresignedURLOperation `json:"operation"` - DID string `json:"did"` - Digest string `json:"digest"` - Size int64 `json:"size,omitempty"` // Only required for PUT operations -} - -// PresignedURLResponse contains the presigned URL -type PresignedURLResponse struct { - URL string `json:"url"` - ExpiresAt time.Time `json:"expires_at"` -} - -// StartMultipartUploadRequest initiates a multipart upload -type StartMultipartUploadRequest struct { - DID string `json:"did"` - Digest string `json:"digest"` -} - -// StartMultipartUploadResponse contains the multipart upload ID -type StartMultipartUploadResponse struct { - UploadID string `json:"upload_id"` - ExpiresAt time.Time `json:"expires_at"` -} - -// GetPartURLRequest requests a presigned URL for a specific part -type GetPartURLRequest struct { - DID string `json:"did"` - Digest string `json:"digest"` - UploadID string `json:"upload_id"` - PartNumber int `json:"part_number"` -} - -// GetPartURLResponse contains the presigned URL for a part -type GetPartURLResponse struct { - URL string `json:"url"` - ExpiresAt time.Time `json:"expires_at"` -} - -// CompleteMultipartRequest completes a multipart upload -type CompleteMultipartRequest struct { - DID string `json:"did"` - Digest string `json:"digest"` - UploadID string `json:"upload_id"` - Parts []CompletedPart `json:"parts"` -} - -// CompletedPart represents an uploaded part with its ETag -type CompletedPart struct { - PartNumber int `json:"part_number"` - ETag string `json:"etag"` -} - -// AbortMultipartRequest aborts an in-progress upload -type AbortMultipartRequest struct { - DID string `json:"did"` - Digest string `json:"digest"` - UploadID string `json:"upload_id"` -} - -// RegisterRequest represents a request to register this hold in a user's PDS -type RegisterRequest struct { - DID string `json:"did"` - AccessToken string `json:"access_token"` - PDSEndpoint string `json:"pds_endpoint"` -} - -// RegisterResponse contains the registration result -type RegisterResponse struct { - HoldURI string `json:"hold_uri"` - CrewURI string `json:"crew_uri"` - Message string `json:"message"` -}