mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-09-19 00:34:16 +00:00
code clean up
This commit is contained in:
+1
-1
@@ -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() {
|
||||
|
||||
+12
-13
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -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"]
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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"`
|
||||
}
|
||||
Reference in New Issue
Block a user