Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions cmd/etracker/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ import (
ucancap "github.com/storacha/go-libstoracha/capabilities/ucan"
"github.com/storacha/go-ucanto/core/delegation"
"github.com/storacha/go-ucanto/did"
"github.com/storacha/go-ucanto/principal"
ed25519 "github.com/storacha/go-ucanto/principal/ed25519/signer"
ed25519verifier "github.com/storacha/go-ucanto/principal/ed25519/verifier"
rsaverifier "github.com/storacha/go-ucanto/principal/rsa/verifier"
"github.com/storacha/go-ucanto/principal/signer"
"github.com/storacha/go-ucanto/ucan"

Expand Down Expand Up @@ -267,6 +270,21 @@ func startService(cmd *cobra.Command, args []string) error {
// Start consolidator in a goroutine
go cons.Start(ctx)

// Multi-format principal parser that supports both Ed25519 and RSA keys
parsePrincipal := func(str string) (principal.Verifier, error) {
// Try Ed25519 first
vf, err := ed25519verifier.Parse(str)
if err == nil {
return vf, nil
}
// Try RSA if Ed25519 fails
vf, err = rsaverifier.Parse(str)
if err == nil {
return vf, nil
}
return nil, fmt.Errorf("failed to parse principal as Ed25519 or RSA: %s", str)
}

// Create server
server, err := server.New(
id,
Expand All @@ -276,6 +294,7 @@ func startService(cmd *cobra.Command, args []string) error {
server.WithAdminCreds(cfg.AdminDashboardUser, cfg.AdminDashboardPassword),
server.WithPricing(cfg.ClientEgressUSDPerTiB, cfg.ProviderEgressUSDPerTiB),
server.WithPrincipalResolver(presolver),
server.WithPrincipalParser(parsePrincipal),
Copy link
Member Author

Choose a reason for hiding this comment

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

I'd love confirmation that it is expected that only Ed25519 keys are supported by default and this is the right approach.

Copy link
Member

Choose a reason for hiding this comment

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

Not sure I underatand - you added RSA so I assume you've run into RSA keys?

Currenty in the browser RSA keys are generated by default, since ed25519 support did not exist when it was built.

Copy link
Member Author

Choose a reason for hiding this comment

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

yes, I'm getting delegations signed with RSA keys from the web app. What I meant with my comment is that go-ucanto verifiers, by default, only handle ed25519 keys.

Are you saying I can set the client up in the browser to generate ed25519 keys instead? I think I'd prefer that, if ed25519 support is generally available across browsers now.

server.WithAuthorityProofs(authProofs...),
)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions deploy/app/external.tf
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ data "aws_iam_policy_document" "task_external_dynamodb_scan_query_document" {
actions = [
"dynamodb:Scan",
"dynamodb:Query",
"dynamodb:GetItem",
]
resources = [
data.aws_dynamodb_table.storage_provider_table.arn,
Expand Down
2 changes: 2 additions & 0 deletions internal/presets/principal_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ var principalMapping = map[string]string{
"did:web:staging.registrar.warm.storacha.network": "did:key:z6MkuQ8PfSMrzXCwZkbQv662nZC4FGGm1aucbH256HXXZyxo",
"did:web:indexer.forge.storacha.network": "did:key:z6Mkj8WmJQRy5jEnFN97uuc2qsjFdsYCuD5wE384Z1AMCFN7",
"did:web:staging.indexer.warm.storacha.network": "did:key:z6Mkr4QkdinnXQmJ9JdnzwhcEjR8nMnuVPEwREyh9jp2Pb7k",
"did:web:up.forge.storacha.network": "did:key:z6MkgSttS3n3R56yGX2Eufvbwc58fphomhAsLoBCZpZJzQbr",
"did:web:staging.up.warm.storacha.network": "did:key:z6MkpR58oZpK7L3cdZZciKT25ynGro7RZm6boFouWQ7AzF7v",
}

type resolver struct {
Expand Down
35 changes: 34 additions & 1 deletion internal/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type config struct {
clientEgressUSDPerTiB float64
providerEgressUSDPerTiB float64
principalResolver validator.PrincipalResolver
principalParser validator.PrincipalParserFunc
authProofs []delegation.Delegation
}

Expand Down Expand Up @@ -56,6 +57,12 @@ func WithPrincipalResolver(resolver validator.PrincipalResolver) Option {
}
}

func WithPrincipalParser(parser validator.PrincipalParserFunc) Option {
return func(c *config) {
c.principalParser = parser
}
}

func WithAuthorityProofs(authProofs ...delegation.Delegation) Option {
return func(c *config) {
c.authProofs = authProofs
Expand All @@ -81,6 +88,10 @@ func New(id principal.Signer, svc service.Service, cons *consolidator.Consolidat
ucantoOpts = append(ucantoOpts, ucanto.WithPrincipalResolver(cfg.principalResolver.ResolveDIDKey))
}

if cfg.principalParser != nil {
ucantoOpts = append(ucantoOpts, ucanto.WithPrincipalParser(cfg.principalParser))
}

ucantoOpts = append(ucantoOpts, ucanto.WithAuthorityProofs(cfg.authProofs...))

ucantoSrv, err := ucanto.NewServer(id, ucantoOpts...)
Expand Down Expand Up @@ -113,6 +124,28 @@ func (s *Server) ListenAndServe(addr string) error {
log.Warnf("Metrics endpoint is disabled")
}

// Wrap with CORS middleware
corsHandler := corsMiddleware(mux)

log.Infof("Listening on %s", addr)
return http.ListenAndServe(addr, mux)
return http.ListenAndServe(addr, corsHandler)
}

// corsMiddleware adds CORS headers to allow cross-origin requests
func corsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Allow all origins
w.Header().Set("Access-Control-Allow-Origin", "*")
Copy link
Member Author

Choose a reason for hiding this comment

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

we'll want to restrict this once we know where the dashboard gets deployed

w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "*")
w.Header().Set("Access-Control-Max-Age", "86400") // 24 hours

// Handle preflight requests
if r.Method == "OPTIONS" {
w.WriteHeader(http.StatusOK)
return
}

next.ServeHTTP(w, r)
})
}