mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-09-20 09:14:16 +00:00
remove older endpoints add docs for blob migration to xrpc
This commit is contained in:
@@ -8,8 +8,6 @@ import (
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"atcr.io/pkg/atproto"
|
||||
)
|
||||
|
||||
// PresignedURLOperation defines the type of presigned URL operation
|
||||
@@ -496,92 +494,3 @@ func (s *HoldService) HandleAbortMultipart(w http.ResponseWriter, r *http.Reques
|
||||
"status": "aborted",
|
||||
})
|
||||
}
|
||||
|
||||
// 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 {
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
var req RegisterRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
http.Error(w, fmt.Sprintf("invalid request: %v", err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Validate required fields
|
||||
if req.DID == "" || req.AccessToken == "" || req.PDSEndpoint == "" {
|
||||
http.Error(w, "missing required fields: did, access_token, pds_endpoint", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Get public URL from config
|
||||
publicURL := s.config.Server.PublicURL
|
||||
if publicURL == "" {
|
||||
// Fallback to constructing URL from request
|
||||
scheme := "http"
|
||||
if r.TLS != nil {
|
||||
scheme = "https"
|
||||
}
|
||||
publicURL = fmt.Sprintf("%s://%s", scheme, r.Host)
|
||||
}
|
||||
|
||||
// Derive hold name from URL
|
||||
holdName, err := extractHostname(publicURL)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to extract hostname: %v", err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := r.Context()
|
||||
|
||||
// Create ATProto client with user's credentials
|
||||
client := atproto.NewClient(req.PDSEndpoint, req.DID, req.AccessToken)
|
||||
|
||||
// Create HoldRecord
|
||||
holdRecord := atproto.NewHoldRecord(publicURL, req.DID, s.config.Server.Public)
|
||||
|
||||
holdResult, err := client.PutRecord(ctx, atproto.HoldCollection, holdName, holdRecord)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to create hold record: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("Created hold record: %s", holdResult.URI)
|
||||
|
||||
// Create HoldCrewRecord for the owner
|
||||
crewRecord := atproto.NewHoldCrewRecord(holdResult.URI, req.DID, "owner")
|
||||
|
||||
crewRKey := fmt.Sprintf("%s-%s", holdName, req.DID)
|
||||
crewResult, err := client.PutRecord(ctx, atproto.HoldCrewCollection, crewRKey, crewRecord)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to create crew record: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("Created crew record: %s", crewResult.URI)
|
||||
|
||||
resp := RegisterResponse{
|
||||
HoldURI: holdResult.URI,
|
||||
CrewURI: crewResult.URI,
|
||||
Message: fmt.Sprintf("Successfully registered hold service. Storage endpoint: %s", publicURL),
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(resp)
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
package hold
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// matchPattern checks if a handle matches a pattern
|
||||
// Supports wildcards: "*" (all), "*.domain.com" (suffix), "prefix.*" (prefix), "*.mid.*" (contains)
|
||||
func matchPattern(pattern, handle string) bool {
|
||||
if pattern == "*" {
|
||||
// Wildcard matches all
|
||||
return true
|
||||
}
|
||||
|
||||
// Convert glob to regex and match
|
||||
regex := globToRegex(pattern)
|
||||
matched, err := regexp.MatchString(regex, handle)
|
||||
if err != nil {
|
||||
// Log error but fail closed (don't grant access on regex error)
|
||||
return false
|
||||
}
|
||||
return matched
|
||||
}
|
||||
|
||||
// globToRegex converts a glob pattern to a regex pattern
|
||||
// Examples:
|
||||
// - "*.example.com" → "^.*\.example\.com$"
|
||||
// - "subdomain.*" → "^subdomain\..*$"
|
||||
// - "*.bsky.*" → "^.*\.bsky\..*$"
|
||||
func globToRegex(pattern string) string {
|
||||
// Escape special regex characters (except *)
|
||||
escaped := regexp.QuoteMeta(pattern)
|
||||
|
||||
// Replace escaped \* with .*
|
||||
regex := strings.ReplaceAll(escaped, "\\*", ".*")
|
||||
|
||||
// Anchor to start and end
|
||||
return "^" + regex + "$"
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"atcr.io/pkg/auth"
|
||||
@@ -96,12 +95,6 @@ func (s *HoldService) isAuthorizedWrite(did string) bool {
|
||||
return allowed
|
||||
}
|
||||
|
||||
// HealthHandler handles health check requests
|
||||
func (s *HoldService) HealthHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write([]byte(`{"status":"ok"}`))
|
||||
}
|
||||
|
||||
// extractHostname extracts the hostname from a URL
|
||||
func extractHostname(urlStr string) (string, error) {
|
||||
u, err := url.Parse(urlStr)
|
||||
|
||||
Reference in New Issue
Block a user