From 38375d44d89e697e683726fb7ece9d4b868f033c Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Sun, 25 Feb 2024 09:47:40 -0500 Subject: [PATCH] feat: initial DNS link support --- account/account.go | 9 +++++ api/account/account.go | 12 ++++++- api/s5/s5.go | 78 +++++++++++++++++++++++++++++++++++++++++- db/db.go | 1 + db/models/dnslink.go | 11 ++++++ go.mod | 2 ++ go.sum | 13 +++++++ 7 files changed, 124 insertions(+), 2 deletions(-) create mode 100644 db/models/dnslink.go diff --git a/account/account.go b/account/account.go index 4123266..9f6883e 100644 --- a/account/account.go +++ b/account/account.go @@ -367,6 +367,15 @@ func (s AccountServiceDefault) OTPDisable(userId uint) error { return s.updateAccountInfo(userId, models.User{OTPEnabled: false, OTPSecret: ""}) } +func (s AccountServiceDefault) DNSLinkExists(hash []byte) (bool, *models.DNSLink, error) { + dnsLink := &models.DNSLink{} + exists, model, err := s.exists(dnsLink, map[string]interface{}{"upload": hash}) + if !exists || err != nil { + return false, nil, err + } + return true, model.(*models.DNSLink), nil +} + func (s AccountServiceDefault) doLogin(user *models.User, ip string) (string, error) { purpose := JWTPurposeLogin diff --git a/api/account/account.go b/api/account/account.go index a2d486f..d53d376 100644 --- a/api/account/account.go +++ b/api/account/account.go @@ -5,6 +5,8 @@ import ( "crypto/ed25519" "net/http" + "git.lumeweb.com/LumeWeb/portal/api/router" + "git.lumeweb.com/LumeWeb/portal/config" "go.uber.org/zap" @@ -19,7 +21,8 @@ import ( ) var ( - _ registry.API = (*AccountAPI)(nil) + _ registry.API = (*AccountAPI)(nil) + _ router.RoutableAPI = (*AccountAPI)(nil) ) type AccountAPI struct { @@ -223,3 +226,10 @@ func (a AccountAPI) Routes() (*httprouter.Router, error) { "POST /api/auth/otp/disable": middleware.ApplyMiddlewares(a.otpDisable, authMw, middleware.ProxyMiddleware), }), nil } +func (a AccountAPI) Can(w http.ResponseWriter, r *http.Request) bool { + return false +} + +func (a AccountAPI) Handle(w http.ResponseWriter, r *http.Request) { + // noop +} diff --git a/api/s5/s5.go b/api/s5/s5.go index f8146f1..e4e54d2 100644 --- a/api/s5/s5.go +++ b/api/s5/s5.go @@ -10,6 +10,7 @@ import ( "encoding/hex" "errors" "fmt" + "git.lumeweb.com/LumeWeb/portal/api/router" "git.lumeweb.com/LumeWeb/portal/bao" "git.lumeweb.com/LumeWeb/portal/renter" "github.com/aws/aws-sdk-go-v2/aws" @@ -56,13 +57,15 @@ import ( protoRegistry "git.lumeweb.com/LumeWeb/portal/protocols/registry" "git.lumeweb.com/LumeWeb/portal/protocols/s5" "github.com/ddo/rq" + "github.com/dnslink-std/go" "github.com/rs/cors" "go.sia.tech/jape" "go.uber.org/fx" ) var ( - _ registry.API = (*S5API)(nil) + _ registry.API = (*S5API)(nil) + _ router.RoutableAPI = (*S5API)(nil) ) //go:embed swagger.yaml @@ -218,6 +221,79 @@ func (s *S5API) Routes() (*httprouter.Router, error) { return s.protocol.Node().Services().HTTP().GetHttpRouter(routes), nil } +func (s *S5API) Can(w http.ResponseWriter, r *http.Request) bool { + resolve, err := dnslink.Resolve(r.Host) + if err != nil { + return false + } + + if _, ok := resolve.Links[s.Name()]; !ok { + return false + } + + decodedCid, err := encoding.CIDFromString(resolve.Links[s.Name()][0].Identifier) + + if err != nil { + s.logger.Error("Error decoding CID", zap.Error(err)) + return false + } + + hash := decodedCid.Hash.HashBytes() + + upload, err := s.metadata.GetUpload(r.Context(), hash) + if err != nil { + return false + } + + if upload.Protocol != s.Name() { + return false + } + + exists, _, err := s.accounts.DNSLinkExists(hash) + if err != nil { + return false + } + + if !exists { + return false + } + + ctx := context.WithValue(r.Context(), "cid", decodedCid) + + r = r.WithContext(ctx) + + return true +} + +func (s *S5API) Handle(w http.ResponseWriter, r *http.Request) { + cidVal := r.Context().Value("cid") + + if cidVal == nil { + w.WriteHeader(http.StatusNotFound) + return + } + + cid := cidVal.(encoding.CID) + + file := s.newFile(s.protocol, cid.Hash.HashBytes()) + + if !file.Exists() { + w.WriteHeader(http.StatusNotFound) + return + } + + defer func(file io.ReadCloser) { + err := file.Close() + if err != nil { + s.logger.Error("error closing file", zap.Error(err)) + } + }(file) + + w.Header().Set("Content-Type", file.Mime()) + + http.ServeContent(w, r, file.Name(), file.Modtime(), file) +} + type s5TusJwtResponseWriter struct { http.ResponseWriter req *http.Request diff --git a/db/db.go b/db/db.go index e3d1de2..6cdb911 100644 --- a/db/db.go +++ b/db/db.go @@ -63,6 +63,7 @@ func NewDatabase(lc fx.Lifecycle, params DatabaseParams) *gorm.DB { return db.AutoMigrate( &models.APIKey{}, &models.Blocklist{}, + &models.DNSLink{}, &models.Download{}, &models.Pin{}, &models.PublicKey{}, diff --git a/db/models/dnslink.go b/db/models/dnslink.go new file mode 100644 index 0000000..5d4424d --- /dev/null +++ b/db/models/dnslink.go @@ -0,0 +1,11 @@ +package models + +import "gorm.io/gorm" + +type DNSLink struct { + gorm.Model + UserID uint `gorm:"uniqueIndex:idx_user_id_upload"` + User User + UploadID uint `gorm:"uniqueIndex:idx_user_id_upload"` + Upload Upload +} diff --git a/go.mod b/go.mod index 436be9f..5de6b24 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/s3 v1.50.3 github.com/casbin/casbin/v2 v2.82.0 github.com/ddo/rq v0.0.0-20190828174524-b3daa55fcaba + github.com/dnslink-std/go v0.6.0 github.com/docker/go-units v0.5.0 github.com/getkin/kin-openapi v0.118.0 github.com/go-co-op/gocron/v2 v2.2.4 @@ -90,6 +91,7 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect + github.com/miekg/dns v1.1.43 // indirect github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/mr-tron/base58 v1.1.0 // indirect diff --git a/go.sum b/go.sum index e2dde78..7d123f4 100644 --- a/go.sum +++ b/go.sum @@ -96,6 +96,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dnslink-std/go v0.6.0 h1:i+5HdSFNrpKxozvyebtvUgjXdqm7SW35NWkO4mnxyjQ= +github.com/dnslink-std/go v0.6.0/go.mod h1:LZoJk4C4PpPZdJhsfi3ADdOVz7teVr1q2MZTtRrCTLE= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= @@ -134,6 +136,7 @@ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9 github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -242,6 +245,8 @@ github.com/mattn/go-sqlite3 v1.14.18/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= +github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg= +github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 h1:7GoSOOW2jpsfkntVKaS2rAr1TJqfcxotyaUcuxoZSzg= github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= @@ -340,10 +345,12 @@ github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -466,6 +473,7 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= @@ -480,8 +488,11 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -494,6 +505,7 @@ golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -571,6 +583,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=