| @@ -0,0 +1,219 @@ | |||
| package cmdline | |||
| import ( | |||
| "crypto/ecdsa" | |||
| "crypto/elliptic" | |||
| "crypto/rand" | |||
| "crypto/x509" | |||
| "crypto/x509/pkix" | |||
| "encoding/pem" | |||
| "fmt" | |||
| "math/big" | |||
| "os" | |||
| "path/filepath" | |||
| "time" | |||
| "github.com/spf13/cobra" | |||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/auth" | |||
| ) | |||
| func init() { | |||
| certCmd := cobra.Command{ | |||
| Use: "cert", | |||
| } | |||
| RootCmd.AddCommand(&certCmd) | |||
| certRoot := cobra.Command{ | |||
| Use: "root [outputDir]", | |||
| Args: cobra.ExactArgs(1), | |||
| Run: func(cmd *cobra.Command, args []string) { | |||
| certRoot(args[0]) | |||
| }, | |||
| } | |||
| certCmd.AddCommand(&certRoot) | |||
| var certFilePath string | |||
| var keyFilePath string | |||
| certServer := cobra.Command{ | |||
| Use: "server [outputDir]", | |||
| Args: cobra.ExactArgs(1), | |||
| Run: func(cmd *cobra.Command, args []string) { | |||
| certServer(certFilePath, keyFilePath, args[0]) | |||
| }, | |||
| } | |||
| certServer.Flags().StringVar(&certFilePath, "cert", "", "CA certificate file path") | |||
| certServer.Flags().StringVar(&keyFilePath, "key", "", "CA key file path") | |||
| certCmd.AddCommand(&certServer) | |||
| certClient := cobra.Command{ | |||
| Use: "client [outputDir]", | |||
| Args: cobra.ExactArgs(1), | |||
| Run: func(cmd *cobra.Command, args []string) { | |||
| certClient(certFilePath, keyFilePath, args[0]) | |||
| }, | |||
| } | |||
| certClient.Flags().StringVar(&certFilePath, "cert", "", "CA certificate file path") | |||
| certClient.Flags().StringVar(&keyFilePath, "key", "", "CA key file path") | |||
| certCmd.AddCommand(&certClient) | |||
| } | |||
| func certRoot(output string) { | |||
| caPriv, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | |||
| // 创建 CA 证书模板 | |||
| caTemplate := &x509.Certificate{ | |||
| SerialNumber: big.NewInt(1), | |||
| Subject: pkix.Name{ | |||
| Organization: []string{"JCS"}, | |||
| }, | |||
| NotBefore: time.Now(), | |||
| NotAfter: time.Now().AddDate(10, 0, 0), // 有效期10年 | |||
| KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature, | |||
| BasicConstraintsValid: true, | |||
| IsCA: true, | |||
| } | |||
| // 自签名 CA 证书 | |||
| caCertDER, _ := x509.CreateCertificate(rand.Reader, caTemplate, caTemplate, &caPriv.PublicKey, caPriv) | |||
| // 保存 CA 证书和私钥 | |||
| writePem(filepath.Join(output, "ca_cert.pem"), "CERTIFICATE", caCertDER) | |||
| privDER, _ := x509.MarshalECPrivateKey(caPriv) | |||
| writePem(filepath.Join(output, "ca_key.pem"), "EC PRIVATE KEY", privDER) | |||
| fmt.Println("CA certificate and key saved to", output) | |||
| } | |||
| func certServer(certFile string, keyFile string, output string) { | |||
| // 读取 CA 证书和私钥 | |||
| caCertPEM, err := os.ReadFile(certFile) | |||
| if err != nil { | |||
| fmt.Println("Failed to read CA certificate:", err) | |||
| return | |||
| } | |||
| caKeyPEM, err := os.ReadFile(keyFile) | |||
| if err != nil { | |||
| fmt.Println("Failed to read CA key:", err) | |||
| return | |||
| } | |||
| caCertPEMBlock, _ := pem.Decode(caCertPEM) | |||
| if caCertPEMBlock == nil { | |||
| fmt.Println("Failed to decode CA certificate") | |||
| return | |||
| } | |||
| caKeyPEMBlock, _ := pem.Decode(caKeyPEM) | |||
| if caKeyPEMBlock == nil { | |||
| fmt.Println("Failed to decode CA key") | |||
| return | |||
| } | |||
| caCert, err := x509.ParseCertificate(caCertPEMBlock.Bytes) | |||
| if err != nil { | |||
| fmt.Println("Failed to parse CA certificate:", err) | |||
| return | |||
| } | |||
| caKey, err := x509.ParseECPrivateKey(caKeyPEMBlock.Bytes) | |||
| if err != nil { | |||
| fmt.Println("Failed to parse CA key:", err) | |||
| return | |||
| } | |||
| // 生成服务端私钥 | |||
| serverPriv, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | |||
| // 服务端证书模板 | |||
| serverTemplate := &x509.Certificate{ | |||
| SerialNumber: big.NewInt(2), | |||
| Subject: pkix.Name{ | |||
| CommonName: "localhost", | |||
| }, | |||
| NotBefore: time.Now(), | |||
| NotAfter: time.Now().AddDate(1, 0, 0), // 有效期1年 | |||
| KeyUsage: x509.KeyUsageDigitalSignature, | |||
| ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, | |||
| BasicConstraintsValid: true, | |||
| } | |||
| // 添加主机名/IP 到证书 | |||
| serverTemplate.DNSNames = []string{auth.ClientInternalSNI} | |||
| // 用 CA 签发服务端证书 | |||
| serverCertDER, _ := x509.CreateCertificate(rand.Reader, serverTemplate, caCert, &serverPriv.PublicKey, caKey) | |||
| // 保存服务端证书和私钥 | |||
| writePem(filepath.Join(output, "server_cert.pem"), "CERTIFICATE", serverCertDER) | |||
| privPem, _ := x509.MarshalECPrivateKey(serverPriv) | |||
| writePem(filepath.Join(output, "server_key.pem"), "EC PRIVATE KEY", privPem) | |||
| fmt.Println("Server certificate and key saved to", output) | |||
| } | |||
| func certClient(certFile string, keyFile string, output string) { | |||
| // 读取 CA 证书和私钥 | |||
| caCertPEM, err := os.ReadFile(certFile) | |||
| if err != nil { | |||
| fmt.Println("Failed to read CA certificate:", err) | |||
| return | |||
| } | |||
| caKeyPEM, err := os.ReadFile(keyFile) | |||
| if err != nil { | |||
| fmt.Println("Failed to read CA key:", err) | |||
| return | |||
| } | |||
| caCertPEMBlock, _ := pem.Decode(caCertPEM) | |||
| if caCertPEMBlock == nil { | |||
| fmt.Println("Failed to decode CA certificate") | |||
| return | |||
| } | |||
| caKeyPEMBlock, _ := pem.Decode(caKeyPEM) | |||
| if caKeyPEMBlock == nil { | |||
| fmt.Println("Failed to decode CA key") | |||
| return | |||
| } | |||
| caCert, err := x509.ParseCertificate(caCertPEMBlock.Bytes) | |||
| if err != nil { | |||
| fmt.Println("Failed to parse CA certificate:", err) | |||
| return | |||
| } | |||
| caKey, err := x509.ParseECPrivateKey(caKeyPEMBlock.Bytes) | |||
| if err != nil { | |||
| fmt.Println("Failed to parse CA key:", err) | |||
| return | |||
| } | |||
| // 生成客户端私钥 | |||
| clientPriv, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | |||
| // 客户端证书模板 | |||
| clientTemplate := &x509.Certificate{ | |||
| SerialNumber: big.NewInt(3), | |||
| Subject: pkix.Name{ | |||
| CommonName: "client", | |||
| }, | |||
| NotBefore: time.Now(), | |||
| NotAfter: time.Now().AddDate(1, 0, 0), // 有效期1年 | |||
| KeyUsage: x509.KeyUsageDigitalSignature, | |||
| ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, | |||
| BasicConstraintsValid: true, | |||
| } | |||
| // 用 CA 签发客户端证书 | |||
| clientCertDER, _ := x509.CreateCertificate(rand.Reader, clientTemplate, caCert, &clientPriv.PublicKey, caKey) | |||
| // 保存客户端证书和私钥 | |||
| writePem(filepath.Join(output, "client_cert.pem"), "CERTIFICATE", clientCertDER) | |||
| privPem, _ := x509.MarshalECPrivateKey(clientPriv) | |||
| writePem(filepath.Join(output, "client_key.pem"), "EC PRIVATE KEY", privPem) | |||
| fmt.Println("Client certificate and key saved to", output) | |||
| } | |||
| func writePem(filename, pemType string, bytes []byte) { | |||
| f, _ := os.Create(filename) | |||
| pem.Encode(f, &pem.Block{Type: pemType, Bytes: bytes}) | |||
| f.Close() | |||
| } | |||
| @@ -192,13 +192,20 @@ func serveHTTP(configPath string, opts serveHTTPOptions) { | |||
| svc := services.NewService(publock, dlder, acStat, uploader, strgSel, stgMeta, db, evtPub, mnt, stgPool) | |||
| // HTTP接口 | |||
| httpCfg := config.Cfg().HTTP | |||
| if !opts.DisableHTTP && httpCfg != nil && httpCfg.Enabled { | |||
| httpCfgJSON := config.Cfg().HTTP | |||
| if !opts.DisableHTTP && httpCfgJSON != nil && httpCfgJSON.Enabled { | |||
| if opts.HTTPListenAddr != "" { | |||
| httpCfg.Listen = opts.HTTPListenAddr | |||
| httpCfgJSON.Listen = opts.HTTPListenAddr | |||
| } | |||
| } else { | |||
| httpCfg = nil | |||
| httpCfgJSON = &http.ConfigJSON{ | |||
| Enabled: false, | |||
| } | |||
| } | |||
| httpCfg, err := httpCfgJSON.Build() | |||
| if err != nil { | |||
| logger.Errorf("build http config: %v", err) | |||
| os.Exit(1) | |||
| } | |||
| httpSvr := http.NewServer(httpCfg, svc) | |||
| httpChan := httpSvr.Start() | |||
| @@ -174,13 +174,20 @@ func vfsTest(configPath string, opts serveHTTPOptions) { | |||
| svc := services.NewService(publock, dlder, acStat, uploader, strgSel, stgMeta, db, evtPub, mnt, stgPool) | |||
| // HTTP接口 | |||
| httpCfg := config.Cfg().HTTP | |||
| if !opts.DisableHTTP && httpCfg != nil && httpCfg.Enabled { | |||
| httpCfgJSON := config.Cfg().HTTP | |||
| if !opts.DisableHTTP && httpCfgJSON != nil && httpCfgJSON.Enabled { | |||
| if opts.HTTPListenAddr != "" { | |||
| httpCfg.Listen = opts.HTTPListenAddr | |||
| httpCfgJSON.Listen = opts.HTTPListenAddr | |||
| } | |||
| } else { | |||
| httpCfg = nil | |||
| httpCfgJSON = &http.ConfigJSON{ | |||
| Enabled: false, | |||
| } | |||
| } | |||
| httpCfg, err := httpCfgJSON.Build() | |||
| if err != nil { | |||
| logger.Errorf("build http config: %v", err) | |||
| os.Exit(1) | |||
| } | |||
| httpSvr := http.NewServer(httpCfg, svc) | |||
| httpChan := httpSvr.Start() | |||
| @@ -28,7 +28,7 @@ type Config struct { | |||
| Downloader downloader.Config `json:"downloader"` | |||
| DownloadStrategy strategy.Config `json:"downloadStrategy"` | |||
| TickTock ticktock.Config `json:"tickTock"` | |||
| HTTP *http.Config `json:"http"` | |||
| HTTP *http.ConfigJSON `json:"http"` | |||
| Mount *mntcfg.Config `json:"mount"` | |||
| AccessToken *accesstoken.Config `json:"accessToken"` | |||
| } | |||
| @@ -0,0 +1,80 @@ | |||
| package auth | |||
| import ( | |||
| "crypto/tls" | |||
| "github.com/gin-gonic/gin" | |||
| "gitlink.org.cn/cloudream/common/pkgs/logger" | |||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/types" | |||
| "gitlink.org.cn/cloudream/jcs-pub/client/sdk/signer" | |||
| "gitlink.org.cn/cloudream/jcs-pub/common/ecode" | |||
| ) | |||
| const ( | |||
| ClientInternalSNI = "client.jcs-pub.internal" | |||
| ) | |||
| type Auth struct { | |||
| cfg *types.Config | |||
| } | |||
| func New(cfg *types.Config) *Auth { | |||
| return &Auth{ | |||
| cfg: cfg, | |||
| } | |||
| } | |||
| func (a *Auth) TLSConfigSelector(hello *tls.ClientHelloInfo) (*tls.Config, error) { | |||
| switch hello.ServerName { | |||
| case ClientInternalSNI: | |||
| return &tls.Config{ | |||
| Certificates: []tls.Certificate{a.cfg.ServerCert}, | |||
| ClientAuth: tls.RequireAndVerifyClientCert, | |||
| ClientCAs: a.cfg.RootCA, | |||
| NextProtos: []string{"h2", "http/1.1"}, | |||
| }, nil | |||
| default: | |||
| return &tls.Config{ | |||
| Certificates: []tls.Certificate{a.cfg.ServerCert}, | |||
| ClientAuth: tls.NoClientCert, | |||
| NextProtos: []string{"h2", "http/1.1"}, | |||
| }, nil | |||
| } | |||
| } | |||
| func (a *Auth) RejectNoCertAuth(c *gin.Context) { | |||
| if c.Request.TLS == nil || c.Request.TLS.ServerName != ClientInternalSNI { | |||
| c.AbortWithStatusJSON(401, types.Failed(ecode.Unauthorized, "must provide client certificate")) | |||
| return | |||
| } | |||
| c.Next() | |||
| } | |||
| func (a *Auth) Presigned(c *gin.Context) { | |||
| log := logger.WithField("HTTP", "Auth") | |||
| accID := signer.GetAccessKeyID(c.Request.URL) | |||
| if accID == "" { | |||
| log.Warn("access key id not found in query string") | |||
| c.AbortWithStatusJSON(401, types.Failed(ecode.Unauthorized, "access key id not found in query string")) | |||
| return | |||
| } | |||
| cliCert := a.cfg.ClientCerts[accID] | |||
| if cliCert == nil { | |||
| log.Warnf("client cert not found for access key id %s", accID) | |||
| c.AbortWithStatusJSON(401, types.Failed(ecode.Unauthorized, "client cert not found for access key id %s", accID)) | |||
| return | |||
| } | |||
| err := signer.VerifyPresigned(cliCert.VerifyKey, c.Request.Method, c.Request.URL) | |||
| if err != nil { | |||
| log.Warn(err.Error()) | |||
| c.AbortWithStatusJSON(401, types.Failed(ecode.Unauthorized, err.Error())) | |||
| return | |||
| } | |||
| c.Next() | |||
| } | |||
| @@ -2,4 +2,4 @@ package http | |||
| import "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/types" | |||
| type Config = types.Config | |||
| type ConfigJSON = types.ConfigJSON | |||
| @@ -2,11 +2,13 @@ package http | |||
| import ( | |||
| "context" | |||
| "crypto/tls" | |||
| "net/http" | |||
| "github.com/gin-gonic/gin" | |||
| "gitlink.org.cn/cloudream/common/pkgs/async" | |||
| "gitlink.org.cn/cloudream/common/pkgs/logger" | |||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/auth" | |||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/types" | |||
| v1 "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/v1" | |||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/services" | |||
| @@ -24,25 +26,26 @@ type ExitEvent struct { | |||
| } | |||
| type Server struct { | |||
| cfg *types.Config | |||
| cfg types.Config | |||
| httpSrv *http.Server | |||
| svc *services.Service | |||
| eventChan *ServerEventChan | |||
| auth *auth.Auth | |||
| v1Svr *v1.Server | |||
| } | |||
| func NewServer(cfg *types.Config, svc *services.Service) *Server { | |||
| func NewServer(cfg types.Config, svc *services.Service) *Server { | |||
| return &Server{ | |||
| cfg: cfg, | |||
| svc: svc, | |||
| eventChan: async.NewUnboundChannel[ServerEvent](), | |||
| v1Svr: v1.NewServer(cfg, svc), | |||
| v1Svr: v1.NewServer(&cfg, svc), | |||
| } | |||
| } | |||
| func (s *Server) Start() *ServerEventChan { | |||
| go func() { | |||
| if s.cfg == nil { | |||
| if !s.cfg.Enabled { | |||
| return | |||
| } | |||
| @@ -51,12 +54,16 @@ func (s *Server) Start() *ServerEventChan { | |||
| Addr: s.cfg.Listen, | |||
| Handler: engine, | |||
| } | |||
| s.auth = auth.New(&s.cfg) | |||
| s.httpSrv.TLSConfig = &tls.Config{ | |||
| GetConfigForClient: s.auth.TLSConfigSelector, | |||
| } | |||
| s.v1Svr.InitRouters(engine.Group("/v1")) | |||
| s.v1Svr.InitRouters(engine.Group("/v1"), s.auth) | |||
| logger.Infof("start serving http at: %s", s.cfg.Listen) | |||
| err := s.httpSrv.ListenAndServe() | |||
| err := s.httpSrv.ListenAndServeTLS("", "") | |||
| s.eventChan.Send(ExitEvent{Err: err}) | |||
| }() | |||
| return s.eventChan | |||
| @@ -1,12 +1,109 @@ | |||
| package types | |||
| import "gitlink.org.cn/cloudream/jcs-pub/client/types" | |||
| import ( | |||
| "crypto/ecdsa" | |||
| "crypto/sha256" | |||
| "crypto/tls" | |||
| "crypto/x509" | |||
| "encoding/hex" | |||
| "encoding/pem" | |||
| "fmt" | |||
| "os" | |||
| "gitlink.org.cn/cloudream/jcs-pub/client/sdk/signer" | |||
| "gitlink.org.cn/cloudream/jcs-pub/client/types" | |||
| ) | |||
| type ConfigJSON struct { | |||
| Enabled bool `json:"enabled"` | |||
| Listen string `json:"listen"` | |||
| RootCA string `json:"rootCA"` | |||
| ServerCert string `json:"serverCert"` | |||
| ServerKey string `json:"serverKey"` | |||
| // 可信的客户端证书列表,在进行预签名接口中会用到。 | |||
| ClientCerts []string `json:"clientCerts"` | |||
| MaxBodySize int64 `json:"maxBodySize"` | |||
| UserSpaceID types.UserSpaceID `json:"userSpaceID"` // TODO 进行访问量统计时,当前客户端所属的存储ID。临时解决方案。 | |||
| } | |||
| func (c *ConfigJSON) Build() (Config, error) { | |||
| if !c.Enabled { | |||
| return Config{ | |||
| Enabled: false, | |||
| }, nil | |||
| } | |||
| rootCAPool := x509.NewCertPool() | |||
| rootCAPem, err := os.ReadFile(c.RootCA) | |||
| if err != nil { | |||
| return Config{}, fmt.Errorf("reading root CA: %w", err) | |||
| } | |||
| if !rootCAPool.AppendCertsFromPEM(rootCAPem) { | |||
| return Config{}, fmt.Errorf("parsing root CA failed") | |||
| } | |||
| svrCert, err := tls.LoadX509KeyPair(c.ServerCert, c.ServerKey) | |||
| if err != nil { | |||
| return Config{}, fmt.Errorf("loading server cert: %w", err) | |||
| } | |||
| clientCerts := make(map[string]*ClientCert) | |||
| for _, p := range c.ClientCerts { | |||
| certPEM, err := os.ReadFile(p) | |||
| if err != nil { | |||
| return Config{}, fmt.Errorf("reading client cert %v: %w", p, err) | |||
| } | |||
| b, _ := pem.Decode(certPEM) | |||
| if len(b.Bytes) == 0 { | |||
| return Config{}, fmt.Errorf("decode client cert %v failed", p) | |||
| } | |||
| if b.Type != "CERTIFICATE" { | |||
| return Config{}, fmt.Errorf("invalid client cert %v: not a certificate", p) | |||
| } | |||
| cert, err := x509.ParseCertificate(b.Bytes) | |||
| if err != nil { | |||
| return Config{}, fmt.Errorf("parsing client cert %v: %w", p, err) | |||
| } | |||
| pubKey, ok := cert.PublicKey.(*ecdsa.PublicKey) | |||
| if !ok { | |||
| return Config{}, fmt.Errorf("invalid client cert %v: not an ECDSA public key", p) | |||
| } | |||
| pubKeyDer, _ := x509.MarshalPKIXPublicKey(pubKey) | |||
| pubHash := sha256.Sum256(pubKeyDer) | |||
| clientCerts[hex.EncodeToString(pubHash[:])] = &ClientCert{ | |||
| Cert: cert, | |||
| VerifyKey: signer.NewVerifyKey(pubKey), | |||
| } | |||
| } | |||
| return Config{ | |||
| Enabled: c.Enabled, | |||
| Listen: c.Listen, | |||
| RootCA: rootCAPool, | |||
| ServerCert: svrCert, | |||
| ClientCerts: clientCerts, | |||
| MaxBodySize: c.MaxBodySize, | |||
| UserSpaceID: c.UserSpaceID, | |||
| }, nil | |||
| } | |||
| type Config struct { | |||
| Enabled bool `json:"enabled"` | |||
| Listen string `json:"listen"` | |||
| AuthAccessKey string `json:"authAccessKey"` // TODO 临时办法 | |||
| AuthSecretKey string `json:"authSecretKey"` | |||
| MaxBodySize int64 `json:"maxBodySize"` | |||
| UserSpaceID types.UserSpaceID `json:"userSpaceID"` // TODO 进行访问量统计时,当前客户端所属的存储ID。临时解决方案。 | |||
| Enabled bool | |||
| Listen string | |||
| RootCA *x509.CertPool | |||
| ServerCert tls.Certificate | |||
| ClientCerts map[string]*ClientCert | |||
| MaxBodySize int64 | |||
| UserSpaceID types.UserSpaceID | |||
| } | |||
| type ClientCert struct { | |||
| Cert *x509.Certificate | |||
| VerifyKey *signer.VerifyKey | |||
| } | |||
| @@ -0,0 +1 @@ | |||
| package types | |||
| @@ -1,12 +1,12 @@ | |||
| package http | |||
| package types | |||
| import ( | |||
| "fmt" | |||
| "github.com/gin-gonic/gin" | |||
| "gitlink.org.cn/cloudream/common/consts/errorcode" | |||
| "gitlink.org.cn/cloudream/common/pkgs/mq" | |||
| "gitlink.org.cn/cloudream/common/utils/serder" | |||
| "gitlink.org.cn/cloudream/jcs-pub/common/ecode" | |||
| ) | |||
| type Response struct { | |||
| @@ -23,15 +23,15 @@ func OK(data any) Response { | |||
| } | |||
| } | |||
| func Failed(code string, format string, args ...any) Response { | |||
| func Failed(code ecode.ErrorCode, format string, args ...any) Response { | |||
| return Response{ | |||
| Code: code, | |||
| Code: string(code), | |||
| Message: fmt.Sprintf(format, args...), | |||
| } | |||
| } | |||
| func FailedError(err error) Response { | |||
| if codeErr, ok := err.(*mq.CodeMessageError); ok { | |||
| if codeErr, ok := err.(*ecode.CodeError); ok { | |||
| return Failed(codeErr.Code, codeErr.Message) | |||
| } | |||
| @@ -1,5 +1,6 @@ | |||
| package http | |||
| /* | |||
| import ( | |||
| "bytes" | |||
| "context" | |||
| @@ -28,12 +29,12 @@ const ( | |||
| ) | |||
| type AWSAuth struct { | |||
| cfg *types.Config | |||
| cfg *types.ConfigJSON | |||
| cred aws.Credentials | |||
| signer *v4.Signer | |||
| } | |||
| func NewAWSAuth(cfg *types.Config) *AWSAuth { | |||
| func NewAWSAuth(cfg *types.ConfigJSON) *AWSAuth { | |||
| auth := &AWSAuth{ | |||
| cfg: cfg, | |||
| } | |||
| @@ -56,13 +57,13 @@ func (a *AWSAuth) Auth(c *gin.Context) { | |||
| authorizationHeader := c.GetHeader(AuthorizationHeader) | |||
| if authorizationHeader == "" { | |||
| c.AbortWithStatusJSON(http.StatusBadRequest, Failed(errorcode.Unauthorized, "authorization header is missing")) | |||
| c.AbortWithStatusJSON(http.StatusBadRequest, types.Failed(ecode.Unauthorized, "authorization header is missing")) | |||
| return | |||
| } | |||
| _, headers, reqSig, err := parseAuthorizationHeader(authorizationHeader) | |||
| if err != nil { | |||
| c.AbortWithStatusJSON(http.StatusBadRequest, Failed(errorcode.Unauthorized, "invalid Authorization header format")) | |||
| c.AbortWithStatusJSON(http.StatusBadRequest, types.Failed(ecode.Unauthorized, "invalid Authorization header format")) | |||
| return | |||
| } | |||
| @@ -70,18 +71,18 @@ func (a *AWSAuth) Auth(c *gin.Context) { | |||
| rd := io.LimitReader(c.Request.Body, a.cfg.MaxBodySize) | |||
| body, err := io.ReadAll(rd) | |||
| if err != nil { | |||
| c.AbortWithStatusJSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "read request body failed")) | |||
| c.AbortWithStatusJSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "read request body failed")) | |||
| return | |||
| } | |||
| timestamp, err := time.Parse("20060102T150405Z", c.GetHeader("X-Amz-Date")) | |||
| if err != nil { | |||
| c.AbortWithStatusJSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "invalid X-Amz-Date header format")) | |||
| c.AbortWithStatusJSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "invalid X-Amz-Date header format")) | |||
| return | |||
| } | |||
| if time.Now().After(timestamp.Add(5 * time.Minute)) { | |||
| c.AbortWithStatusJSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "X-Amz-Date is expired")) | |||
| c.AbortWithStatusJSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "X-Amz-Date is expired")) | |||
| return | |||
| } | |||
| @@ -91,7 +92,7 @@ func (a *AWSAuth) Auth(c *gin.Context) { | |||
| // 构造验签用的请求 | |||
| verifyReq, err := http.NewRequest(c.Request.Method, c.Request.URL.String(), nil) | |||
| if err != nil { | |||
| c.AbortWithStatusJSON(http.StatusOK, Failed(errorcode.OperationFailed, err.Error())) | |||
| c.AbortWithStatusJSON(http.StatusOK, types.Failed(ecode.OperationFailed, err.Error())) | |||
| return | |||
| } | |||
| for _, h := range headers { | |||
| @@ -108,14 +109,14 @@ func (a *AWSAuth) Auth(c *gin.Context) { | |||
| err = signer.SignHTTP(context.TODO(), a.cred, verifyReq, hexPayloadHash, AuthService, AuthRegion, timestamp) | |||
| if err != nil { | |||
| logger.Warnf("sign request: %v", err) | |||
| c.AbortWithStatusJSON(http.StatusOK, Failed(errorcode.OperationFailed, "sign request failed")) | |||
| c.AbortWithStatusJSON(http.StatusOK, types.Failed(ecode.OperationFailed, "sign request failed")) | |||
| return | |||
| } | |||
| verifySig := getSignatureFromAWSHeader(verifyReq) | |||
| if !strings.EqualFold(verifySig, reqSig) { | |||
| logger.Warnf("signature mismatch, input header: %s, verify: %s", authorizationHeader, verifyReq.Header.Get(AuthorizationHeader)) | |||
| c.AbortWithStatusJSON(http.StatusOK, Failed(errorcode.Unauthorized, "signature mismatch")) | |||
| c.AbortWithStatusJSON(http.StatusOK, types.Failed(ecode.Unauthorized, "signature mismatch")) | |||
| return | |||
| } | |||
| @@ -132,31 +133,31 @@ func (a *AWSAuth) AuthWithoutBody(c *gin.Context) { | |||
| authorizationHeader := c.GetHeader(AuthorizationHeader) | |||
| if authorizationHeader == "" { | |||
| c.AbortWithStatusJSON(http.StatusBadRequest, Failed(errorcode.Unauthorized, "authorization header is missing")) | |||
| c.AbortWithStatusJSON(http.StatusBadRequest, types.Failed(ecode.Unauthorized, "authorization header is missing")) | |||
| return | |||
| } | |||
| _, headers, reqSig, err := parseAuthorizationHeader(authorizationHeader) | |||
| if err != nil { | |||
| c.AbortWithStatusJSON(http.StatusBadRequest, Failed(errorcode.Unauthorized, "invalid Authorization header format")) | |||
| c.AbortWithStatusJSON(http.StatusBadRequest, types.Failed(ecode.Unauthorized, "invalid Authorization header format")) | |||
| return | |||
| } | |||
| timestamp, err := time.Parse("20060102T150405Z", c.GetHeader("X-Amz-Date")) | |||
| if err != nil { | |||
| c.AbortWithStatusJSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "invalid X-Amz-Date header format")) | |||
| c.AbortWithStatusJSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "invalid X-Amz-Date header format")) | |||
| return | |||
| } | |||
| if time.Now().After(timestamp.Add(5 * time.Minute)) { | |||
| c.AbortWithStatusJSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "X-Amz-Date is expired")) | |||
| c.AbortWithStatusJSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "X-Amz-Date is expired")) | |||
| return | |||
| } | |||
| // 构造验签用的请求 | |||
| verifyReq, err := http.NewRequest(c.Request.Method, c.Request.URL.String(), nil) | |||
| if err != nil { | |||
| c.AbortWithStatusJSON(http.StatusOK, Failed(errorcode.OperationFailed, err.Error())) | |||
| c.AbortWithStatusJSON(http.StatusOK, types.Failed(ecode.OperationFailed, err.Error())) | |||
| return | |||
| } | |||
| for _, h := range headers { | |||
| @@ -173,14 +174,14 @@ func (a *AWSAuth) AuthWithoutBody(c *gin.Context) { | |||
| if err != nil { | |||
| logger.Warnf("sign request: %v", err) | |||
| c.AbortWithStatusJSON(http.StatusOK, Failed(errorcode.OperationFailed, "sign request failed")) | |||
| c.AbortWithStatusJSON(http.StatusOK, types.Failed(ecode.OperationFailed, "sign request failed")) | |||
| return | |||
| } | |||
| verifySig := getSignatureFromAWSHeader(verifyReq) | |||
| if !strings.EqualFold(verifySig, reqSig) { | |||
| logger.Warnf("signature mismatch, input header: %s, verify: %s", authorizationHeader, verifySig) | |||
| c.AbortWithStatusJSON(http.StatusOK, Failed(errorcode.Unauthorized, "signature mismatch")) | |||
| c.AbortWithStatusJSON(http.StatusOK, types.Failed(ecode.Unauthorized, "signature mismatch")) | |||
| return | |||
| } | |||
| @@ -198,7 +199,7 @@ func (a *AWSAuth) PresignedAuth(c *gin.Context) { | |||
| signature := query.Get("X-Amz-Signature") | |||
| query.Del("X-Amz-Signature") | |||
| if signature == "" { | |||
| c.AbortWithStatusJSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing X-Amz-Signature query parameter")) | |||
| c.AbortWithStatusJSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing X-Amz-Signature query parameter")) | |||
| return | |||
| } | |||
| @@ -209,7 +210,7 @@ func (a *AWSAuth) PresignedAuth(c *gin.Context) { | |||
| expiresStr := query.Get("X-Expires") | |||
| expires, err := strconv.ParseInt(expiresStr, 10, 64) | |||
| if err != nil { | |||
| c.AbortWithStatusJSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "invalid X-Expires format")) | |||
| c.AbortWithStatusJSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "invalid X-Expires format")) | |||
| return | |||
| } | |||
| @@ -219,7 +220,7 @@ func (a *AWSAuth) PresignedAuth(c *gin.Context) { | |||
| verifyReq, err := http.NewRequest(c.Request.Method, c.Request.URL.String(), nil) | |||
| if err != nil { | |||
| c.AbortWithStatusJSON(http.StatusOK, Failed(errorcode.OperationFailed, err.Error())) | |||
| c.AbortWithStatusJSON(http.StatusOK, types.Failed(ecode.OperationFailed, err.Error())) | |||
| return | |||
| } | |||
| for _, h := range signedHeaders { | |||
| @@ -234,26 +235,26 @@ func (a *AWSAuth) PresignedAuth(c *gin.Context) { | |||
| timestamp, err := time.Parse("20060102T150405Z", date) | |||
| if err != nil { | |||
| c.AbortWithStatusJSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "invalid X-Amz-Date format")) | |||
| c.AbortWithStatusJSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "invalid X-Amz-Date format")) | |||
| return | |||
| } | |||
| if time.Now().After(timestamp.Add(time.Duration(expires) * time.Second)) { | |||
| c.AbortWithStatusJSON(http.StatusUnauthorized, Failed(errorcode.Unauthorized, "request expired")) | |||
| c.AbortWithStatusJSON(http.StatusUnauthorized, types.Failed(ecode.Unauthorized, "request expired")) | |||
| return | |||
| } | |||
| signer := v4.NewSigner() | |||
| uri, _, err := signer.PresignHTTP(context.TODO(), a.cred, verifyReq, "", AuthService, AuthRegion, timestamp) | |||
| if err != nil { | |||
| c.AbortWithStatusJSON(http.StatusOK, Failed(errorcode.OperationFailed, "sign request failed")) | |||
| c.AbortWithStatusJSON(http.StatusOK, types.Failed(ecode.OperationFailed, "sign request failed")) | |||
| return | |||
| } | |||
| verifySig := getSignatureFromAWSQuery(uri) | |||
| if !strings.EqualFold(verifySig, signature) { | |||
| logger.Warnf("signature mismatch, input: %s, verify: %s", signature, verifySig) | |||
| c.AbortWithStatusJSON(http.StatusOK, Failed(errorcode.Unauthorized, "signature mismatch")) | |||
| c.AbortWithStatusJSON(http.StatusOK, types.Failed(ecode.Unauthorized, "signature mismatch")) | |||
| return | |||
| } | |||
| @@ -319,3 +320,4 @@ func getSignatureFromAWSQuery(uri string) string { | |||
| return uri[idx+len("X-Amz-Signature=") : andIdx] | |||
| } | |||
| */ | |||
| @@ -6,9 +6,10 @@ import ( | |||
| "time" | |||
| "github.com/gin-gonic/gin" | |||
| "gitlink.org.cn/cloudream/common/consts/errorcode" | |||
| "gitlink.org.cn/cloudream/common/pkgs/logger" | |||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/types" | |||
| cliapi "gitlink.org.cn/cloudream/jcs-pub/client/sdk/api/v1" | |||
| "gitlink.org.cn/cloudream/jcs-pub/common/ecode" | |||
| ) | |||
| type BucketService struct { | |||
| @@ -27,18 +28,18 @@ func (s *BucketService) GetByName(ctx *gin.Context) { | |||
| var req cliapi.BucketGetByName | |||
| if err := ctx.ShouldBindQuery(&req); err != nil { | |||
| log.Warnf("binding query: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| bucket, err := s.svc.BucketSvc().GetBucketByName(req.Name) | |||
| if err != nil { | |||
| log.Warnf("getting bucket by name: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, FailedError(err)) | |||
| ctx.JSON(http.StatusOK, types.FailedError(err)) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.BucketGetByNameResp{ | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.BucketGetByNameResp{ | |||
| Bucket: bucket, | |||
| })) | |||
| } | |||
| @@ -49,18 +50,18 @@ func (s *BucketService) Create(ctx *gin.Context) { | |||
| var req cliapi.BucketCreate | |||
| if err := ctx.ShouldBindJSON(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| bucket, err := s.svc.BucketSvc().CreateBucket(req.Name, time.Now()) | |||
| if err != nil { | |||
| log.Warnf("creating bucket: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, FailedError(err)) | |||
| ctx.JSON(http.StatusOK, types.FailedError(err)) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.BucketCreateResp{ | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.BucketCreateResp{ | |||
| Bucket: bucket, | |||
| })) | |||
| } | |||
| @@ -71,17 +72,17 @@ func (s *BucketService) Delete(ctx *gin.Context) { | |||
| var req cliapi.BucketDelete | |||
| if err := ctx.ShouldBindJSON(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| if err := s.svc.BucketSvc().DeleteBucket(req.BucketID); err != nil { | |||
| log.Warnf("deleting bucket: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "delete bucket failed")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "delete bucket types.Failed")) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(nil)) | |||
| ctx.JSON(http.StatusOK, types.OK(nil)) | |||
| } | |||
| func (s *BucketService) ListAll(ctx *gin.Context) { | |||
| @@ -90,18 +91,18 @@ func (s *BucketService) ListAll(ctx *gin.Context) { | |||
| var req cliapi.BucketListAll | |||
| if err := ctx.ShouldBindQuery(&req); err != nil { | |||
| log.Warnf("binding query: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| buckets, err := s.svc.BucketSvc().ListAllBuckets() | |||
| if err != nil { | |||
| log.Warnf("list all buckets: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("list all buckets: %v", err))) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("list all buckets: %v", err))) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.BucketListAllResp{ | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.BucketListAllResp{ | |||
| Buckets: buckets, | |||
| })) | |||
| } | |||
| @@ -4,9 +4,10 @@ import ( | |||
| "net/http" | |||
| "github.com/gin-gonic/gin" | |||
| "gitlink.org.cn/cloudream/common/consts/errorcode" | |||
| "gitlink.org.cn/cloudream/common/pkgs/logger" | |||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/types" | |||
| cliapi "gitlink.org.cn/cloudream/jcs-pub/client/sdk/api/v1" | |||
| "gitlink.org.cn/cloudream/jcs-pub/common/ecode" | |||
| ) | |||
| type MountService struct { | |||
| @@ -25,12 +26,12 @@ func (m *MountService) DumpStatus(ctx *gin.Context) { | |||
| var req cliapi.MountDumpStatus | |||
| if err := ctx.ShouldBindQuery(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| dumpStatus := m.svc.Mount.Dump() | |||
| ctx.JSON(http.StatusOK, OK(cliapi.MountDumpStatusResp{ | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.MountDumpStatusResp{ | |||
| MountStatus: dumpStatus, | |||
| })) | |||
| } | |||
| @@ -40,10 +41,10 @@ func (m *MountService) StartReclaimSpace(ctx *gin.Context) { | |||
| // var req cliapi.MountReclaimSpace | |||
| // if err := ctx.ShouldBindJSON(&req); err != nil { | |||
| // log.Warnf("binding body: %s", err.Error()) | |||
| // ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| // ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| // return | |||
| // } | |||
| m.svc.Mount.StartReclaimSpace() | |||
| ctx.JSON(http.StatusOK, OK(cliapi.StartMountReclaimSpaceResp{})) | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.StartMountReclaimSpaceResp{})) | |||
| } | |||
| @@ -10,12 +10,13 @@ import ( | |||
| "path/filepath" | |||
| "github.com/gin-gonic/gin" | |||
| "gitlink.org.cn/cloudream/common/consts/errorcode" | |||
| "gitlink.org.cn/cloudream/common/pkgs/logger" | |||
| "gitlink.org.cn/cloudream/common/utils/math2" | |||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/downloader" | |||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/types" | |||
| cliapi "gitlink.org.cn/cloudream/jcs-pub/client/sdk/api/v1" | |||
| clitypes "gitlink.org.cn/cloudream/jcs-pub/client/types" | |||
| "gitlink.org.cn/cloudream/jcs-pub/common/ecode" | |||
| ) | |||
| type ObjectService struct { | |||
| @@ -34,18 +35,18 @@ func (s *ObjectService) ListByPath(ctx *gin.Context) { | |||
| var req cliapi.ObjectListByPath | |||
| if err := ctx.ShouldBindQuery(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| resp, err := s.svc.ObjectSvc().GetByPath(req) | |||
| if err != nil { | |||
| log.Warnf("listing objects: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("listing objects: %v", err))) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("listing objects: %v", err))) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(resp)) | |||
| ctx.JSON(http.StatusOK, types.OK(resp)) | |||
| } | |||
| func (s *ObjectService) ListByIDs(ctx *gin.Context) { | |||
| @@ -54,18 +55,18 @@ func (s *ObjectService) ListByIDs(ctx *gin.Context) { | |||
| var req cliapi.ObjectListByIDs | |||
| if err := ctx.ShouldBindQuery(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| objs, err := s.svc.ObjectSvc().GetByIDs(req.ObjectIDs) | |||
| if err != nil { | |||
| log.Warnf("listing objects: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("listing objects: %v", err))) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("listing objects: %v", err))) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.ObjectListByIDsResp{Objects: objs})) | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.ObjectListByIDsResp{Objects: objs})) | |||
| } | |||
| type ObjectUploadReq struct { | |||
| @@ -79,14 +80,14 @@ func (s *ObjectService) Upload(ctx *gin.Context) { | |||
| var req ObjectUploadReq | |||
| if err := ctx.ShouldBind(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| up, err := s.svc.Uploader.BeginUpdate(req.Info.PackageID, req.Info.Affinity, req.Info.CopyTo, req.Info.CopyToPath) | |||
| if err != nil { | |||
| log.Warnf("begin update: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("begin update: %v", err))) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("begin update: %v", err))) | |||
| return | |||
| } | |||
| defer up.Abort() | |||
| @@ -96,14 +97,14 @@ func (s *ObjectService) Upload(ctx *gin.Context) { | |||
| f, err := file.Open() | |||
| if err != nil { | |||
| log.Warnf("open file: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("open file %v: %v", file.Filename, err))) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("open file %v: %v", file.Filename, err))) | |||
| return | |||
| } | |||
| path, err := url.PathUnescape(file.Filename) | |||
| if err != nil { | |||
| log.Warnf("unescape filename: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("unescape filename %v: %v", file.Filename, err))) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("unescape filename %v: %v", file.Filename, err))) | |||
| return | |||
| } | |||
| path = filepath.ToSlash(path) | |||
| @@ -111,7 +112,7 @@ func (s *ObjectService) Upload(ctx *gin.Context) { | |||
| err = up.Upload(path, f) | |||
| if err != nil { | |||
| log.Warnf("uploading file: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("uploading file %v: %v", file.Filename, err))) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("uploading file %v: %v", file.Filename, err))) | |||
| return | |||
| } | |||
| pathes = append(pathes, path) | |||
| @@ -120,7 +121,7 @@ func (s *ObjectService) Upload(ctx *gin.Context) { | |||
| ret, err := up.Commit() | |||
| if err != nil { | |||
| log.Warnf("commit update: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("commit update: %v", err))) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("commit update: %v", err))) | |||
| return | |||
| } | |||
| @@ -129,7 +130,7 @@ func (s *ObjectService) Upload(ctx *gin.Context) { | |||
| uploadeds[i] = ret.Objects[pathes[i]] | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.ObjectUploadResp{Uploadeds: uploadeds})) | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.ObjectUploadResp{Uploadeds: uploadeds})) | |||
| } | |||
| func (s *ObjectService) Download(ctx *gin.Context) { | |||
| @@ -138,7 +139,7 @@ func (s *ObjectService) Download(ctx *gin.Context) { | |||
| var req cliapi.ObjectDownload | |||
| if err := ctx.ShouldBindQuery(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| @@ -155,12 +156,12 @@ func (s *ObjectService) Download(ctx *gin.Context) { | |||
| }) | |||
| if err != nil { | |||
| log.Warnf("downloading object: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "download object failed")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "download object failed")) | |||
| return | |||
| } | |||
| if file.File == nil { | |||
| log.Warnf("object not found: %d", req.ObjectID) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.DataNotFound, "object not found")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.DataNotFound, "object not found")) | |||
| return | |||
| } | |||
| defer file.File.Close() | |||
| @@ -186,7 +187,7 @@ func (s *ObjectService) DownloadByPath(ctx *gin.Context) { | |||
| var req cliapi.ObjectDownloadByPath | |||
| if err := ctx.ShouldBindQuery(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| @@ -195,13 +196,13 @@ func (s *ObjectService) DownloadByPath(ctx *gin.Context) { | |||
| }) | |||
| if err != nil { | |||
| log.Warnf("getting object by path: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "get object by path failed")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "get object by path failed")) | |||
| return | |||
| } | |||
| if len(resp.Objects) == 0 { | |||
| log.Warnf("object not found: %s", req.Path) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.DataNotFound, "object not found")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.DataNotFound, "object not found")) | |||
| return | |||
| } | |||
| @@ -218,7 +219,7 @@ func (s *ObjectService) DownloadByPath(ctx *gin.Context) { | |||
| }) | |||
| if err != nil { | |||
| log.Warnf("downloading object: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "download object failed")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "download object failed")) | |||
| return | |||
| } | |||
| defer file.File.Close() | |||
| @@ -243,18 +244,18 @@ func (s *ObjectService) UpdateInfo(ctx *gin.Context) { | |||
| var req cliapi.ObjectUpdateInfo | |||
| if err := ctx.ShouldBindJSON(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| sucs, err := s.svc.ObjectSvc().UpdateInfo(req.Updatings) | |||
| if err != nil { | |||
| log.Warnf("updating objects: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "update objects failed")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "update objects failed")) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.ObjectUpdateInfoResp{Successes: sucs})) | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.ObjectUpdateInfoResp{Successes: sucs})) | |||
| } | |||
| func (s *ObjectService) UpdateInfoByPath(ctx *gin.Context) { | |||
| @@ -263,7 +264,7 @@ func (s *ObjectService) UpdateInfoByPath(ctx *gin.Context) { | |||
| var req cliapi.ObjectUpdateInfoByPath | |||
| if err := ctx.ShouldBindJSON(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| @@ -272,12 +273,12 @@ func (s *ObjectService) UpdateInfoByPath(ctx *gin.Context) { | |||
| }) | |||
| if err != nil { | |||
| log.Warnf("getting object by path: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "get object by path failed")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "get object by path failed")) | |||
| return | |||
| } | |||
| if len(resp.Objects) == 0 { | |||
| log.Warnf("object not found: %s", req.Path) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.DataNotFound, "object not found")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.DataNotFound, "object not found")) | |||
| return | |||
| } | |||
| @@ -287,13 +288,13 @@ func (s *ObjectService) UpdateInfoByPath(ctx *gin.Context) { | |||
| }}) | |||
| if err != nil { | |||
| log.Warnf("updating objects: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "update objects failed")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "update objects failed")) | |||
| return | |||
| } | |||
| if len(sucs) == 0 { | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.ObjectUpdateInfoByPathResp{})) | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.ObjectUpdateInfoByPathResp{})) | |||
| } | |||
| func (s *ObjectService) Move(ctx *gin.Context) { | |||
| @@ -302,18 +303,18 @@ func (s *ObjectService) Move(ctx *gin.Context) { | |||
| var req cliapi.ObjectMove | |||
| if err := ctx.ShouldBindJSON(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| sucs, err := s.svc.ObjectSvc().Move(req.Movings) | |||
| if err != nil { | |||
| log.Warnf("moving objects: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "move objects failed")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "move objects failed")) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.ObjectMoveResp{Successes: sucs})) | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.ObjectMoveResp{Successes: sucs})) | |||
| } | |||
| func (s *ObjectService) Delete(ctx *gin.Context) { | |||
| @@ -322,18 +323,18 @@ func (s *ObjectService) Delete(ctx *gin.Context) { | |||
| var req cliapi.ObjectDelete | |||
| if err := ctx.ShouldBindJSON(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| err := s.svc.ObjectSvc().Delete(req.ObjectIDs) | |||
| if err != nil { | |||
| log.Warnf("deleting objects: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "delete objects failed")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "delete objects failed")) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(nil)) | |||
| ctx.JSON(http.StatusOK, types.OK(nil)) | |||
| } | |||
| func (s *ObjectService) DeleteByPath(ctx *gin.Context) { | |||
| @@ -342,7 +343,7 @@ func (s *ObjectService) DeleteByPath(ctx *gin.Context) { | |||
| var req cliapi.ObjectDeleteByPath | |||
| if err := ctx.ShouldBindJSON(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| @@ -351,22 +352,22 @@ func (s *ObjectService) DeleteByPath(ctx *gin.Context) { | |||
| }) | |||
| if err != nil { | |||
| log.Warnf("getting object by path: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "get object by path failed")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "get object by path failed")) | |||
| return | |||
| } | |||
| if len(resp.Objects) == 0 { | |||
| ctx.JSON(http.StatusOK, OK(nil)) | |||
| ctx.JSON(http.StatusOK, types.OK(nil)) | |||
| return | |||
| } | |||
| err = s.svc.ObjectSvc().Delete([]clitypes.ObjectID{resp.Objects[0].ObjectID}) | |||
| if err != nil { | |||
| log.Warnf("deleting objects: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "delete objects failed")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "delete objects failed")) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(nil)) | |||
| ctx.JSON(http.StatusOK, types.OK(nil)) | |||
| } | |||
| func (s *ObjectService) Clone(ctx *gin.Context) { | |||
| @@ -375,18 +376,18 @@ func (s *ObjectService) Clone(ctx *gin.Context) { | |||
| var req cliapi.ObjectClone | |||
| if err := ctx.ShouldBindJSON(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| objs, err := s.svc.ObjectSvc().Clone(req.Clonings) | |||
| if err != nil { | |||
| log.Warnf("cloning object: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "clone object failed")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "clone object failed")) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.ObjectCloneResp{Objects: objs})) | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.ObjectCloneResp{Objects: objs})) | |||
| } | |||
| func (s *ObjectService) GetPackageObjects(ctx *gin.Context) { | |||
| @@ -395,18 +396,18 @@ func (s *ObjectService) GetPackageObjects(ctx *gin.Context) { | |||
| var req cliapi.ObjectGetPackageObjects | |||
| if err := ctx.ShouldBindQuery(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| objs, err := s.svc.ObjectSvc().GetPackageObjects(req.PackageID) | |||
| if err != nil { | |||
| log.Warnf("getting package objects: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "get package object failed")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "get package object failed")) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.ObjectGetPackageObjectsResp{Objects: objs})) | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.ObjectGetPackageObjectsResp{Objects: objs})) | |||
| } | |||
| func (s *ObjectService) NewMultipartUpload(ctx *gin.Context) { | |||
| @@ -415,18 +416,18 @@ func (s *ObjectService) NewMultipartUpload(ctx *gin.Context) { | |||
| var req cliapi.ObjectNewMultipartUpload | |||
| if err := ctx.ShouldBindJSON(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| obj, err := s.svc.ObjectSvc().NewMultipartUploadObject(req.PackageID, req.Path) | |||
| if err != nil { | |||
| log.Warnf("new multipart upload object: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "new multipart upload object failed")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "new multipart upload object failed")) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.ObjectNewMultipartUploadResp{Object: obj})) | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.ObjectNewMultipartUploadResp{Object: obj})) | |||
| } | |||
| type ObjectUploadPartReq struct { | |||
| @@ -440,14 +441,14 @@ func (s *ObjectService) UploadPart(ctx *gin.Context) { | |||
| var req ObjectUploadPartReq | |||
| if err := ctx.ShouldBind(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| file, err := req.File.Open() | |||
| if err != nil { | |||
| log.Warnf("open file: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "open file failed")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "open file failed")) | |||
| return | |||
| } | |||
| defer file.Close() | |||
| @@ -455,11 +456,11 @@ func (s *ObjectService) UploadPart(ctx *gin.Context) { | |||
| err = s.svc.Uploader.UploadPart(req.Info.ObjectID, req.Info.Index, file) | |||
| if err != nil { | |||
| log.Warnf("uploading part: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("upload part: %v", err))) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("upload part: %v", err))) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.ObjectUploadPartResp{})) | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.ObjectUploadPartResp{})) | |||
| } | |||
| func (s *ObjectService) CompleteMultipartUpload(ctx *gin.Context) { | |||
| @@ -468,16 +469,16 @@ func (s *ObjectService) CompleteMultipartUpload(ctx *gin.Context) { | |||
| var req cliapi.ObjectCompleteMultipartUpload | |||
| if err := ctx.ShouldBindJSON(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| obj, err := s.svc.ObjectSvc().CompleteMultipartUpload(req.ObjectID, req.Indexes) | |||
| if err != nil { | |||
| log.Warnf("completing multipart upload: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("complete multipart upload: %v", err))) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("complete multipart upload: %v", err))) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.ObjectCompleteMultipartUploadResp{Object: obj})) | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.ObjectCompleteMultipartUploadResp{Object: obj})) | |||
| } | |||
| @@ -8,10 +8,11 @@ import ( | |||
| "path/filepath" | |||
| "github.com/gin-gonic/gin" | |||
| "gitlink.org.cn/cloudream/common/consts/errorcode" | |||
| "gitlink.org.cn/cloudream/common/pkgs/logger" | |||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/types" | |||
| cliapi "gitlink.org.cn/cloudream/jcs-pub/client/sdk/api/v1" | |||
| clitypes "gitlink.org.cn/cloudream/jcs-pub/client/types" | |||
| "gitlink.org.cn/cloudream/jcs-pub/common/ecode" | |||
| ) | |||
| // PackageService 包服务,负责处理包相关的HTTP请求。 | |||
| @@ -32,18 +33,18 @@ func (s *PackageService) Get(ctx *gin.Context) { | |||
| var req cliapi.PackageGetReq | |||
| if err := ctx.ShouldBindQuery(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| pkg, err := s.svc.PackageSvc().Get(req.PackageID) | |||
| if err != nil { | |||
| log.Warnf("getting package: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, FailedError(err)) | |||
| ctx.JSON(http.StatusOK, types.FailedError(err)) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.PackageGetResp{Package: pkg})) | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.PackageGetResp{Package: pkg})) | |||
| } | |||
| func (s *PackageService) GetByFullName(ctx *gin.Context) { | |||
| @@ -52,18 +53,18 @@ func (s *PackageService) GetByFullName(ctx *gin.Context) { | |||
| var req cliapi.PackageGetByFullName | |||
| if err := ctx.ShouldBindQuery(&req); err != nil { | |||
| log.Warnf("binding query: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| pkg, err := s.svc.PackageSvc().GetByFullName(req.BucketName, req.PackageName) | |||
| if err != nil { | |||
| log.Warnf("getting package by name: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, FailedError(err)) | |||
| ctx.JSON(http.StatusOK, types.FailedError(err)) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.PackageGetByFullNameResp{Package: pkg})) | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.PackageGetByFullNameResp{Package: pkg})) | |||
| } | |||
| // Create 处理创建新包的HTTP请求。 | |||
| @@ -72,18 +73,18 @@ func (s *PackageService) Create(ctx *gin.Context) { | |||
| var req cliapi.PackageCreate | |||
| if err := ctx.ShouldBindJSON(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| pkg, err := s.svc.PackageSvc().Create(req.BucketID, req.Name) | |||
| if err != nil { | |||
| log.Warnf("creating package: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, FailedError(err)) | |||
| ctx.JSON(http.StatusOK, types.FailedError(err)) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.PackageCreateResp{ | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.PackageCreateResp{ | |||
| Package: pkg, | |||
| })) | |||
| } | |||
| @@ -99,20 +100,20 @@ func (s *PackageService) CreateLoad(ctx *gin.Context) { | |||
| var req PackageCreateUpload | |||
| if err := ctx.ShouldBind(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| if len(req.Info.CopyTo) != len(req.Info.CopyToPath) { | |||
| log.Warnf("CopyTo and CopyToPath count not match") | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.BadArgument, "CopyTo and CopyToPath count not match")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.BadArgument, "CopyTo and CopyToPath count not match")) | |||
| return | |||
| } | |||
| up, err := s.svc.Uploader.BeginCreateUpload(req.Info.BucketID, req.Info.Name, req.Info.CopyTo, req.Info.CopyToPath) | |||
| if err != nil { | |||
| log.Warnf("begin package create upload: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "%v", err)) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "%v", err)) | |||
| return | |||
| } | |||
| defer up.Abort() | |||
| @@ -122,14 +123,14 @@ func (s *PackageService) CreateLoad(ctx *gin.Context) { | |||
| f, err := file.Open() | |||
| if err != nil { | |||
| log.Warnf("open file: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("open file %v: %v", file.Filename, err))) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("open file %v: %v", file.Filename, err))) | |||
| return | |||
| } | |||
| path, err := url.PathUnescape(file.Filename) | |||
| if err != nil { | |||
| log.Warnf("unescape filename: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("unescape filename %v: %v", file.Filename, err))) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("unescape filename %v: %v", file.Filename, err))) | |||
| return | |||
| } | |||
| path = filepath.ToSlash(path) | |||
| @@ -137,7 +138,7 @@ func (s *PackageService) CreateLoad(ctx *gin.Context) { | |||
| err = up.Upload(path, f) | |||
| if err != nil { | |||
| log.Warnf("uploading file: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("uploading file %v: %v", file.Filename, err))) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("uploading file %v: %v", file.Filename, err))) | |||
| return | |||
| } | |||
| pathes = append(pathes, path) | |||
| @@ -146,7 +147,7 @@ func (s *PackageService) CreateLoad(ctx *gin.Context) { | |||
| ret, err := up.Commit() | |||
| if err != nil { | |||
| log.Warnf("commit create upload: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("commit create upload: %v", err))) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("commit create upload: %v", err))) | |||
| return | |||
| } | |||
| @@ -155,7 +156,7 @@ func (s *PackageService) CreateLoad(ctx *gin.Context) { | |||
| objs[i] = ret.Objects[pathes[i]] | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.PackageCreateUploadResp{Package: ret.Package, Objects: objs})) | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.PackageCreateUploadResp{Package: ret.Package, Objects: objs})) | |||
| } | |||
| func (s *PackageService) Delete(ctx *gin.Context) { | |||
| @@ -164,18 +165,18 @@ func (s *PackageService) Delete(ctx *gin.Context) { | |||
| var req cliapi.PackageDelete | |||
| if err := ctx.ShouldBindJSON(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| err := s.svc.PackageSvc().DeletePackage(req.PackageID) | |||
| if err != nil { | |||
| log.Warnf("deleting package: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "delete package failed")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "delete package failed")) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(nil)) | |||
| ctx.JSON(http.StatusOK, types.OK(nil)) | |||
| } | |||
| func (s *PackageService) Clone(ctx *gin.Context) { | |||
| @@ -184,18 +185,18 @@ func (s *PackageService) Clone(ctx *gin.Context) { | |||
| var req cliapi.PackageClone | |||
| if err := ctx.ShouldBindJSON(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| pkg, err := s.svc.PackageSvc().Clone(req.PackageID, req.BucketID, req.Name) | |||
| if err != nil { | |||
| log.Warnf("cloning package: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "clone package failed")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "clone package failed")) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.PackageCloneResp{ | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.PackageCloneResp{ | |||
| Package: pkg, | |||
| })) | |||
| } | |||
| @@ -206,18 +207,18 @@ func (s *PackageService) ListBucketPackages(ctx *gin.Context) { | |||
| var req cliapi.PackageListBucketPackages | |||
| if err := ctx.ShouldBindQuery(&req); err != nil { | |||
| log.Warnf("binding query: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| pkgs, err := s.svc.PackageSvc().GetBucketPackages(req.BucketID) | |||
| if err != nil { | |||
| log.Warnf("getting bucket packages: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "get bucket packages failed")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "get bucket packages failed")) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.PackageListBucketPackagesResp{ | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.PackageListBucketPackagesResp{ | |||
| Packages: pkgs, | |||
| })) | |||
| } | |||
| @@ -9,11 +9,12 @@ import ( | |||
| "path/filepath" | |||
| "github.com/gin-gonic/gin" | |||
| "gitlink.org.cn/cloudream/common/consts/errorcode" | |||
| "gitlink.org.cn/cloudream/common/pkgs/logger" | |||
| "gitlink.org.cn/cloudream/common/utils/math2" | |||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/downloader" | |||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/types" | |||
| cliapi "gitlink.org.cn/cloudream/jcs-pub/client/sdk/api/v1" | |||
| "gitlink.org.cn/cloudream/jcs-pub/common/ecode" | |||
| ) | |||
| type PresignedService struct { | |||
| @@ -32,18 +33,18 @@ func (s *PresignedService) ObjectListByPath(ctx *gin.Context) { | |||
| var req cliapi.PresignedObjectListByPath | |||
| if err := ctx.ShouldBindQuery(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| resp, err := s.svc.ObjectSvc().GetByPath(req.ObjectListByPath) | |||
| if err != nil { | |||
| log.Warnf("listing objects: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("listing objects: %v", err))) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("listing objects: %v", err))) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(resp)) | |||
| ctx.JSON(http.StatusOK, types.OK(resp)) | |||
| } | |||
| func (s *PresignedService) ObjectDownloadByPath(ctx *gin.Context) { | |||
| @@ -52,7 +53,7 @@ func (s *PresignedService) ObjectDownloadByPath(ctx *gin.Context) { | |||
| var req cliapi.PresignedObjectDownloadByPath | |||
| if err := ctx.ShouldBindQuery(&req); err != nil { | |||
| log.Warnf("binding query: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| @@ -61,12 +62,12 @@ func (s *PresignedService) ObjectDownloadByPath(ctx *gin.Context) { | |||
| }) | |||
| if err != nil { | |||
| log.Warnf("getting object by path: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "get object by path failed")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "get object by path failed")) | |||
| return | |||
| } | |||
| if len(resp.Objects) == 0 { | |||
| log.Warnf("object not found: %s", req.Path) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.DataNotFound, "object not found")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.DataNotFound, "object not found")) | |||
| return | |||
| } | |||
| @@ -83,7 +84,7 @@ func (s *PresignedService) ObjectDownloadByPath(ctx *gin.Context) { | |||
| }) | |||
| if err != nil { | |||
| log.Warnf("downloading object: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "download object failed")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "download object failed")) | |||
| return | |||
| } | |||
| defer file.File.Close() | |||
| @@ -108,7 +109,7 @@ func (s *PresignedService) ObjectDownload(ctx *gin.Context) { | |||
| var req cliapi.PresignedObjectDownload | |||
| if err := ctx.ShouldBindQuery(&req); err != nil { | |||
| log.Warnf("binding query: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| @@ -125,7 +126,7 @@ func (s *PresignedService) ObjectDownload(ctx *gin.Context) { | |||
| }) | |||
| if err != nil { | |||
| log.Warnf("downloading object: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "download object failed")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "download object failed")) | |||
| return | |||
| } | |||
| defer file.File.Close() | |||
| @@ -150,14 +151,14 @@ func (s *PresignedService) ObjectUpload(ctx *gin.Context) { | |||
| var req cliapi.PresignedObjectUpload | |||
| if err := ctx.ShouldBindQuery(&req); err != nil { | |||
| log.Warnf("binding query: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| up, err := s.svc.Uploader.BeginUpdate(req.PackageID, req.Affinity, req.CopyTo, req.CopyToPath) | |||
| if err != nil { | |||
| log.Warnf("begin update: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("begin update: %v", err))) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("begin update: %v", err))) | |||
| return | |||
| } | |||
| defer up.Abort() | |||
| @@ -167,18 +168,18 @@ func (s *PresignedService) ObjectUpload(ctx *gin.Context) { | |||
| err = up.Upload(path, ctx.Request.Body) | |||
| if err != nil { | |||
| log.Warnf("uploading file: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("uploading file %v: %v", req.Path, err))) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("uploading file %v: %v", req.Path, err))) | |||
| return | |||
| } | |||
| ret, err := up.Commit() | |||
| if err != nil { | |||
| log.Warnf("commit update: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("commit update: %v", err))) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("commit update: %v", err))) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.PresignedObjectUploadResp{Object: ret.Objects[path]})) | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.PresignedObjectUploadResp{Object: ret.Objects[path]})) | |||
| } | |||
| func (s *PresignedService) ObjectNewMultipartUpload(ctx *gin.Context) { | |||
| @@ -187,18 +188,18 @@ func (s *PresignedService) ObjectNewMultipartUpload(ctx *gin.Context) { | |||
| var req cliapi.PresignedObjectNewMultipartUpload | |||
| if err := ctx.ShouldBindQuery(&req); err != nil { | |||
| log.Warnf("binding query: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| obj, err := s.svc.ObjectSvc().NewMultipartUploadObject(req.PackageID, req.Path) | |||
| if err != nil { | |||
| log.Warnf("new multipart upload: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("new multipart upload: %v", err))) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("new multipart upload: %v", err))) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.PresignedObjectUploadResp{Object: obj})) | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.PresignedObjectUploadResp{Object: obj})) | |||
| } | |||
| func (s *PresignedService) ObjectUploadPart(ctx *gin.Context) { | |||
| @@ -207,18 +208,18 @@ func (s *PresignedService) ObjectUploadPart(ctx *gin.Context) { | |||
| var req cliapi.PresignedObjectUploadPart | |||
| if err := ctx.ShouldBindQuery(&req); err != nil { | |||
| log.Warnf("binding query: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| err := s.svc.Uploader.UploadPart(req.ObjectID, req.Index, ctx.Request.Body) | |||
| if err != nil { | |||
| log.Warnf("uploading part: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("upload part: %v", err))) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("upload part: %v", err))) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.ObjectUploadPartResp{})) | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.ObjectUploadPartResp{})) | |||
| } | |||
| func (s *PresignedService) ObjectCompleteMultipartUpload(ctx *gin.Context) { | |||
| @@ -227,16 +228,16 @@ func (s *PresignedService) ObjectCompleteMultipartUpload(ctx *gin.Context) { | |||
| var req cliapi.PresignedObjectCompleteMultipartUpload | |||
| if err := ctx.ShouldBindQuery(&req); err != nil { | |||
| log.Warnf("binding query: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| obj, err := s.svc.ObjectSvc().CompleteMultipartUpload(req.ObjectID, req.Indexes) | |||
| if err != nil { | |||
| log.Warnf("completing multipart upload: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("complete multipart upload: %v", err))) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("complete multipart upload: %v", err))) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.ObjectCompleteMultipartUploadResp{Object: obj})) | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.ObjectCompleteMultipartUploadResp{Object: obj})) | |||
| } | |||
| @@ -2,6 +2,7 @@ package http | |||
| import ( | |||
| "github.com/gin-gonic/gin" | |||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/auth" | |||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/types" | |||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/services" | |||
| cliapi "gitlink.org.cn/cloudream/jcs-pub/client/sdk/api/v1" | |||
| @@ -19,57 +20,58 @@ func NewServer(cfg *types.Config, svc *services.Service) *Server { | |||
| } | |||
| } | |||
| func (s *Server) InitRouters(rt gin.IRoutes) { | |||
| awsAuth := NewAWSAuth(s.cfg) | |||
| func (s *Server) InitRouters(rt gin.IRoutes, ah *auth.Auth) { | |||
| certAuth := ah.RejectNoCertAuth | |||
| signAuth := ah.Presigned | |||
| rt.GET(cliapi.ObjectListPathByPath, awsAuth.Auth, s.Object().ListByPath) | |||
| rt.GET(cliapi.ObjectListByIDsPath, awsAuth.Auth, s.Object().ListByIDs) | |||
| rt.GET(cliapi.ObjectDownloadPath, awsAuth.Auth, s.Object().Download) | |||
| rt.GET(cliapi.ObjectDownloadByPathPath, awsAuth.Auth, s.Object().DownloadByPath) | |||
| rt.POST(cliapi.ObjectUploadPath, awsAuth.AuthWithoutBody, s.Object().Upload) | |||
| rt.GET(cliapi.ObjectGetPackageObjectsPath, awsAuth.Auth, s.Object().GetPackageObjects) | |||
| rt.POST(cliapi.ObjectUpdateInfoPath, awsAuth.Auth, s.Object().UpdateInfo) | |||
| rt.POST(cliapi.ObjectUpdateInfoByPathPath, awsAuth.Auth, s.Object().UpdateInfoByPath) | |||
| rt.POST(cliapi.ObjectMovePath, awsAuth.Auth, s.Object().Move) | |||
| rt.POST(cliapi.ObjectDeletePath, awsAuth.Auth, s.Object().Delete) | |||
| rt.POST(cliapi.ObjectDeleteByPathPath, awsAuth.Auth, s.Object().DeleteByPath) | |||
| rt.POST(cliapi.ObjectClonePath, awsAuth.Auth, s.Object().Clone) | |||
| rt.GET(cliapi.ObjectListPathByPath, certAuth, s.Object().ListByPath) | |||
| rt.GET(cliapi.ObjectListByIDsPath, certAuth, s.Object().ListByIDs) | |||
| rt.GET(cliapi.ObjectDownloadPath, certAuth, s.Object().Download) | |||
| rt.GET(cliapi.ObjectDownloadByPathPath, certAuth, s.Object().DownloadByPath) | |||
| rt.POST(cliapi.ObjectUploadPath, certAuth, s.Object().Upload) | |||
| rt.GET(cliapi.ObjectGetPackageObjectsPath, certAuth, s.Object().GetPackageObjects) | |||
| rt.POST(cliapi.ObjectUpdateInfoPath, certAuth, s.Object().UpdateInfo) | |||
| rt.POST(cliapi.ObjectUpdateInfoByPathPath, certAuth, s.Object().UpdateInfoByPath) | |||
| rt.POST(cliapi.ObjectMovePath, certAuth, s.Object().Move) | |||
| rt.POST(cliapi.ObjectDeletePath, certAuth, s.Object().Delete) | |||
| rt.POST(cliapi.ObjectDeleteByPathPath, certAuth, s.Object().DeleteByPath) | |||
| rt.POST(cliapi.ObjectClonePath, certAuth, s.Object().Clone) | |||
| rt.GET(cliapi.PackageGetPath, awsAuth.Auth, s.Package().Get) | |||
| rt.GET(cliapi.PackageGetByFullNamePath, awsAuth.Auth, s.Package().GetByFullName) | |||
| rt.POST(cliapi.PackageCreatePath, awsAuth.Auth, s.Package().Create) | |||
| rt.POST(cliapi.PackageCreateUploadPath, awsAuth.Auth, s.Package().CreateLoad) | |||
| rt.POST(cliapi.PackageDeletePath, awsAuth.Auth, s.Package().Delete) | |||
| rt.POST(cliapi.PackageClonePath, awsAuth.Auth, s.Package().Clone) | |||
| rt.GET(cliapi.PackageListBucketPackagesPath, awsAuth.Auth, s.Package().ListBucketPackages) | |||
| rt.GET(cliapi.PackageGetPath, certAuth, s.Package().Get) | |||
| rt.GET(cliapi.PackageGetByFullNamePath, certAuth, s.Package().GetByFullName) | |||
| rt.POST(cliapi.PackageCreatePath, certAuth, s.Package().Create) | |||
| rt.POST(cliapi.PackageCreateUploadPath, certAuth, s.Package().CreateLoad) | |||
| rt.POST(cliapi.PackageDeletePath, certAuth, s.Package().Delete) | |||
| rt.POST(cliapi.PackageClonePath, certAuth, s.Package().Clone) | |||
| rt.GET(cliapi.PackageListBucketPackagesPath, certAuth, s.Package().ListBucketPackages) | |||
| rt.POST(cliapi.UserSpaceDownloadPackagePath, awsAuth.Auth, s.UserSpace().DownloadPackage) | |||
| rt.POST(cliapi.UserSpaceCreatePackagePath, awsAuth.Auth, s.UserSpace().CreatePackage) | |||
| rt.GET(cliapi.UserSpaceGetPath, awsAuth.Auth, s.UserSpace().Get) | |||
| rt.POST(cliapi.UserSpaceCreatePath, awsAuth.Auth, s.UserSpace().Create) | |||
| rt.POST(cliapi.UserSpaceUpdatePath, awsAuth.Auth, s.UserSpace().Update) | |||
| rt.POST(cliapi.UserSpaceDeletePath, awsAuth.Auth, s.UserSpace().Delete) | |||
| rt.POST(cliapi.UserSpaceTestPath, awsAuth.Auth, s.UserSpace().Test) | |||
| rt.POST(cliapi.UserSpaceSpaceToSpacePath, awsAuth.Auth, s.UserSpace().SpaceToSpace) | |||
| rt.POST(cliapi.UserSpaceDownloadPackagePath, certAuth, s.UserSpace().DownloadPackage) | |||
| rt.POST(cliapi.UserSpaceCreatePackagePath, certAuth, s.UserSpace().CreatePackage) | |||
| rt.GET(cliapi.UserSpaceGetPath, certAuth, s.UserSpace().Get) | |||
| rt.POST(cliapi.UserSpaceCreatePath, certAuth, s.UserSpace().Create) | |||
| rt.POST(cliapi.UserSpaceUpdatePath, certAuth, s.UserSpace().Update) | |||
| rt.POST(cliapi.UserSpaceDeletePath, certAuth, s.UserSpace().Delete) | |||
| rt.POST(cliapi.UserSpaceTestPath, certAuth, s.UserSpace().Test) | |||
| rt.POST(cliapi.UserSpaceSpaceToSpacePath, certAuth, s.UserSpace().SpaceToSpace) | |||
| rt.GET(cliapi.BucketGetByNamePath, awsAuth.Auth, s.Bucket().GetByName) | |||
| rt.POST(cliapi.BucketCreatePath, awsAuth.Auth, s.Bucket().Create) | |||
| rt.POST(cliapi.BucketDeletePath, awsAuth.Auth, s.Bucket().Delete) | |||
| rt.GET(cliapi.BucketListAllPath, awsAuth.Auth, s.Bucket().ListAll) | |||
| rt.GET(cliapi.BucketGetByNamePath, certAuth, s.Bucket().GetByName) | |||
| rt.POST(cliapi.BucketCreatePath, certAuth, s.Bucket().Create) | |||
| rt.POST(cliapi.BucketDeletePath, certAuth, s.Bucket().Delete) | |||
| rt.GET(cliapi.BucketListAllPath, certAuth, s.Bucket().ListAll) | |||
| rt.POST(cliapi.ObjectNewMultipartUploadPath, awsAuth.Auth, s.Object().NewMultipartUpload) | |||
| rt.POST(cliapi.ObjectUploadPartPath, awsAuth.AuthWithoutBody, s.Object().UploadPart) | |||
| rt.POST(cliapi.ObjectCompleteMultipartUploadPath, awsAuth.Auth, s.Object().CompleteMultipartUpload) | |||
| rt.POST(cliapi.ObjectNewMultipartUploadPath, certAuth, s.Object().NewMultipartUpload) | |||
| rt.POST(cliapi.ObjectUploadPartPath, certAuth, s.Object().UploadPart) | |||
| rt.POST(cliapi.ObjectCompleteMultipartUploadPath, certAuth, s.Object().CompleteMultipartUpload) | |||
| rt.GET(cliapi.PresignedObjectListByPathPath, awsAuth.PresignedAuth, s.Presigned().ObjectListByPath) | |||
| rt.GET(cliapi.PresignedObjectDownloadByPathPath, awsAuth.PresignedAuth, s.Presigned().ObjectDownloadByPath) | |||
| rt.GET(cliapi.PresignedObjectDownloadPath, awsAuth.PresignedAuth, s.Presigned().ObjectDownload) | |||
| rt.POST(cliapi.PresignedObjectUploadPath, awsAuth.PresignedAuth, s.Presigned().ObjectUpload) | |||
| rt.GET(cliapi.PresignedObjectListByPathPath, signAuth, s.Presigned().ObjectListByPath) | |||
| rt.GET(cliapi.PresignedObjectDownloadByPathPath, signAuth, s.Presigned().ObjectDownloadByPath) | |||
| rt.GET(cliapi.PresignedObjectDownloadPath, signAuth, s.Presigned().ObjectDownload) | |||
| rt.POST(cliapi.PresignedObjectUploadPath, signAuth, s.Presigned().ObjectUpload) | |||
| rt.POST(cliapi.PresignedObjectNewMultipartUploadPath, awsAuth.PresignedAuth, s.Presigned().ObjectNewMultipartUpload) | |||
| rt.POST(cliapi.PresignedObjectUploadPartPath, awsAuth.PresignedAuth, s.Presigned().ObjectUploadPart) | |||
| rt.POST(cliapi.PresignedObjectCompleteMultipartUploadPath, awsAuth.PresignedAuth, s.Presigned().ObjectCompleteMultipartUpload) | |||
| rt.POST(cliapi.PresignedObjectNewMultipartUploadPath, signAuth, s.Presigned().ObjectNewMultipartUpload) | |||
| rt.POST(cliapi.PresignedObjectUploadPartPath, signAuth, s.Presigned().ObjectUploadPart) | |||
| rt.POST(cliapi.PresignedObjectCompleteMultipartUploadPath, signAuth, s.Presigned().ObjectCompleteMultipartUpload) | |||
| rt.GET(cliapi.MountDumpStatusPath, awsAuth.Auth, s.Mount().DumpStatus) | |||
| rt.POST(cliapi.MountStartReclaimSpacePath, awsAuth.Auth, s.Mount().StartReclaimSpace) | |||
| rt.GET(cliapi.MountDumpStatusPath, certAuth, s.Mount().DumpStatus) | |||
| rt.POST(cliapi.MountStartReclaimSpacePath, certAuth, s.Mount().StartReclaimSpace) | |||
| } | |||
| @@ -5,9 +5,10 @@ import ( | |||
| "net/http" | |||
| "github.com/gin-gonic/gin" | |||
| "gitlink.org.cn/cloudream/common/consts/errorcode" | |||
| "gitlink.org.cn/cloudream/common/pkgs/logger" | |||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/types" | |||
| cliapi "gitlink.org.cn/cloudream/jcs-pub/client/sdk/api/v1" | |||
| "gitlink.org.cn/cloudream/jcs-pub/common/ecode" | |||
| ) | |||
| type UserSpaceService struct { | |||
| @@ -26,18 +27,18 @@ func (s *UserSpaceService) DownloadPackage(ctx *gin.Context) { | |||
| var req cliapi.UserSpaceDownloadPackageReq | |||
| if err := ctx.ShouldBindJSON(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| err := s.svc.UserSpaceSvc().DownloadPackage(req.PackageID, req.UserSpaceID, req.RootPath) | |||
| if err != nil { | |||
| log.Warnf("downloading package: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "%v", err)) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "%v", err)) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.UserSpaceDownloadPackageResp{})) | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.UserSpaceDownloadPackageResp{})) | |||
| } | |||
| func (s *UserSpaceService) CreatePackage(ctx *gin.Context) { | |||
| @@ -46,18 +47,18 @@ func (s *UserSpaceService) CreatePackage(ctx *gin.Context) { | |||
| var req cliapi.UserSpaceCreatePackageReq | |||
| if err := ctx.ShouldBindJSON(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| pkg, err := s.svc.Uploader.UserSpaceUpload(req.UserSpaceID, req.Path, req.BucketID, req.Name, req.SpaceAffinity) | |||
| if err != nil { | |||
| log.Warnf("userspace create package: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("userspace create package: %v", err))) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("userspace create package: %v", err))) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.UserSpaceCreatePackageResp{ | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.UserSpaceCreatePackageResp{ | |||
| Package: *pkg, | |||
| })) | |||
| } | |||
| @@ -68,18 +69,18 @@ func (s *UserSpaceService) Get(ctx *gin.Context) { | |||
| var req cliapi.UserSpaceGet | |||
| if err := ctx.ShouldBindQuery(&req); err != nil { | |||
| log.Warnf("binding query: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| info, err := s.svc.UserSpaceSvc().Get(req.UserSpaceID) | |||
| if err != nil { | |||
| log.Warnf("getting info: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "get userspace inf failed")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "get userspace inf failed")) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.UserSpaceGetResp{ | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.UserSpaceGetResp{ | |||
| UserSpace: info, | |||
| })) | |||
| } | |||
| @@ -87,42 +88,42 @@ func (s *UserSpaceService) Get(ctx *gin.Context) { | |||
| func (s *UserSpaceService) Create(ctx *gin.Context) { | |||
| log := logger.WithField("HTTP", "UserSpace.Create") | |||
| req, err := ShouldBindJSONEx[cliapi.UserSpaceCreate](ctx) | |||
| req, err := types.ShouldBindJSONEx[cliapi.UserSpaceCreate](ctx) | |||
| if err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| resp, cerr := s.svc.UserSpaceSvc().Create(req) | |||
| if cerr != nil { | |||
| log.Warnf("creating userspace: %v", cerr) | |||
| ctx.JSON(http.StatusOK, Failed(string(cerr.Code), cerr.Message)) | |||
| ctx.JSON(http.StatusOK, types.Failed(cerr.Code, cerr.Message)) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(resp)) | |||
| ctx.JSON(http.StatusOK, types.OK(resp)) | |||
| } | |||
| func (s *UserSpaceService) Update(ctx *gin.Context) { | |||
| log := logger.WithField("HTTP", "UserSpace.Update") | |||
| var req cliapi.UserSpaceUpdate | |||
| req, err := ShouldBindJSONEx[cliapi.UserSpaceUpdate](ctx) | |||
| req, err := types.ShouldBindJSONEx[cliapi.UserSpaceUpdate](ctx) | |||
| if err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| resp, cerr := s.svc.UserSpaceSvc().Update(req) | |||
| if cerr != nil { | |||
| log.Warnf("updating userspace: %v", cerr) | |||
| ctx.JSON(http.StatusOK, Failed(string(cerr.Code), cerr.Message)) | |||
| ctx.JSON(http.StatusOK, types.Failed(cerr.Code, cerr.Message)) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(resp)) | |||
| ctx.JSON(http.StatusOK, types.OK(resp)) | |||
| } | |||
| func (s *UserSpaceService) Delete(ctx *gin.Context) { | |||
| @@ -131,39 +132,39 @@ func (s *UserSpaceService) Delete(ctx *gin.Context) { | |||
| var req cliapi.UserSpaceDelete | |||
| if err := ctx.ShouldBindJSON(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| resp, cerr := s.svc.UserSpaceSvc().Delete(req) | |||
| if cerr != nil { | |||
| log.Warnf("deleting userspace: %v", cerr) | |||
| ctx.JSON(http.StatusOK, Failed(string(cerr.Code), cerr.Message)) | |||
| ctx.JSON(http.StatusOK, types.Failed(cerr.Code, cerr.Message)) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(resp)) | |||
| ctx.JSON(http.StatusOK, types.OK(resp)) | |||
| } | |||
| func (s *UserSpaceService) Test(ctx *gin.Context) { | |||
| log := logger.WithField("HTTP", "UserSpace.Test") | |||
| var req cliapi.UserSpaceTest | |||
| req, err := ShouldBindJSONEx[cliapi.UserSpaceTest](ctx) | |||
| req, err := types.ShouldBindJSONEx[cliapi.UserSpaceTest](ctx) | |||
| if err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| resp, cerr := s.svc.UserSpaceSvc().Test(req) | |||
| if cerr != nil { | |||
| log.Warnf("testing userspace: %v", cerr) | |||
| ctx.JSON(http.StatusOK, Failed(string(cerr.Code), cerr.Message)) | |||
| ctx.JSON(http.StatusOK, types.Failed(cerr.Code, cerr.Message)) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(resp)) | |||
| ctx.JSON(http.StatusOK, types.OK(resp)) | |||
| } | |||
| func (s *UserSpaceService) SpaceToSpace(ctx *gin.Context) { | |||
| @@ -172,18 +173,18 @@ func (s *UserSpaceService) SpaceToSpace(ctx *gin.Context) { | |||
| var req cliapi.UserSpaceSpaceToSpace | |||
| if err := ctx.ShouldBindJSON(&req); err != nil { | |||
| log.Warnf("binding body: %s", err.Error()) | |||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||
| return | |||
| } | |||
| ret, err := s.svc.UserSpaceSvc().SpaceToSpace(req.SrcUserSpaceID, req.SrcPath, req.DstUserSpaceID, req.DstPath) | |||
| if err != nil { | |||
| log.Warnf("space2space: %s", err.Error()) | |||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "space2space failed")) | |||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "space2space failed")) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, OK(cliapi.UserSpaceSpaceToSpaceResp{ | |||
| ctx.JSON(http.StatusOK, types.OK(cliapi.UserSpaceSpaceToSpaceResp{ | |||
| SpaceToSpaceResult: ret, | |||
| })) | |||
| } | |||
| @@ -0,0 +1,150 @@ | |||
| package signer | |||
| import ( | |||
| "crypto/ecdsa" | |||
| "crypto/rand" | |||
| "crypto/sha256" | |||
| "encoding/hex" | |||
| "fmt" | |||
| "net/url" | |||
| "strconv" | |||
| "strings" | |||
| "time" | |||
| "gitlink.org.cn/cloudream/common/utils/sort2" | |||
| ) | |||
| var ErrSignatureMismatch = fmt.Errorf("signature mismatch") | |||
| var ErrExpired = fmt.Errorf("signature expired") | |||
| const ( | |||
| DateQueryKey = "x-jcs-date" | |||
| ExpiresQueryKey = "x-jcs-expires" | |||
| SignatureQueryKey = "x-jcs-signature" | |||
| AccessKeyIDQueryKey = "x-jcs-access-key-id" | |||
| AlgorithmQueryKey = "x-jcs-algorithm" | |||
| AlgorithmValue = "ECDSA256" | |||
| DateFormat = "20060102T150405Z" | |||
| ) | |||
| type SignKey struct { | |||
| privateKey *ecdsa.PrivateKey | |||
| accessKeyID string | |||
| } | |||
| func PresignURL(key *SignKey, method string, u *url.URL, signingTime time.Time, expiresSeconds int) error { | |||
| date := signingTime.Format(DateFormat) | |||
| queries := u.Query() | |||
| queries.Set(DateQueryKey, date) | |||
| queries.Set(ExpiresQueryKey, fmt.Sprintf("%v", expiresSeconds)) | |||
| queries.Set(AccessKeyIDQueryKey, key.accessKeyID) | |||
| queries.Set(AlgorithmQueryKey, AlgorithmValue) | |||
| ss := makeStringToSign(method, u.Host, u.Path, queries) | |||
| ssHash := sha256.Sum256([]byte(ss)) | |||
| sign, err := ecdsa.SignASN1(rand.Reader, key.privateKey, ssHash[:]) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| queries.Set(SignatureQueryKey, hex.EncodeToString(sign)) | |||
| u.RawQuery = queries.Encode() | |||
| return nil | |||
| } | |||
| type VerifyKey struct { | |||
| publicKey *ecdsa.PublicKey | |||
| } | |||
| func NewVerifyKey(publicKey *ecdsa.PublicKey) *VerifyKey { | |||
| return &VerifyKey{publicKey: publicKey} | |||
| } | |||
| func GetAccessKeyID(u *url.URL) string { | |||
| return u.Query().Get(AccessKeyIDQueryKey) | |||
| } | |||
| func VerifyPresigned(key *VerifyKey, method string, u *url.URL) error { | |||
| queries := u.Query() | |||
| dateStr := queries.Get(DateQueryKey) | |||
| if dateStr == "" { | |||
| return fmt.Errorf("missing date in query string") | |||
| } | |||
| date, err := time.Parse(DateFormat, dateStr) | |||
| if err != nil { | |||
| return fmt.Errorf("invalid date format: %v", err) | |||
| } | |||
| expiresStr := queries.Get(ExpiresQueryKey) | |||
| if expiresStr == "" { | |||
| return fmt.Errorf("missing expires in query string") | |||
| } | |||
| expires, err := strconv.Atoi(expiresStr) | |||
| if err != nil { | |||
| return fmt.Errorf("invalid expires format: %v", err) | |||
| } | |||
| if time.Now().After(date.Add(time.Duration(expires) * time.Second)) { | |||
| return ErrExpired | |||
| } | |||
| signatureStr := queries.Get(SignatureQueryKey) | |||
| signature, err := hex.DecodeString(signatureStr) | |||
| if err != nil { | |||
| return fmt.Errorf("invalid signature format: %v", err) | |||
| } | |||
| queries.Del(SignatureQueryKey) | |||
| ss := makeStringToSign(method, u.Host, u.Path, queries) | |||
| ssHash := sha256.Sum256([]byte(ss)) | |||
| if !ecdsa.VerifyASN1(key.publicKey, ssHash[:], signature) { | |||
| return ErrSignatureMismatch | |||
| } | |||
| return nil | |||
| } | |||
| func makeStringToSign(method string, host string, path string, queries url.Values) string { | |||
| type queryKv struct { | |||
| Key string | |||
| Values []string | |||
| } | |||
| var queryKvs []queryKv | |||
| for k, vs := range queries { | |||
| vs = sort2.SortAsc(vs) | |||
| queryKvs = append(queryKvs, queryKv{Key: k, Values: vs}) | |||
| } | |||
| queryKvs = sort2.Sort(queryKvs, func(left, right queryKv) int { | |||
| return strings.Compare(left.Key, right.Key) | |||
| }) | |||
| var str strings.Builder | |||
| str.WriteString(method) | |||
| str.WriteByte('\n') | |||
| str.WriteString(host) | |||
| str.WriteByte('\n') | |||
| str.WriteString(path) | |||
| str.WriteByte('\n') | |||
| for _, kv := range queryKvs { | |||
| str.WriteString(kv.Key) | |||
| str.WriteByte('=') | |||
| for i, v := range kv.Values { | |||
| if i > 0 { | |||
| str.WriteByte(',') | |||
| } | |||
| str.WriteString(v) | |||
| } | |||
| str.WriteByte('\n') | |||
| } | |||
| return str.String() | |||
| } | |||
| @@ -79,6 +79,7 @@ func createClient(stgType *cortypes.OBSType, cred *cortypes.OBSCred) (*s3.Client | |||
| } | |||
| awsConfig.Credentials = &credentials.StaticCredentialsProvider{Value: cre} | |||
| awsConfig.Region = stgType.Region | |||
| awsConfig.RetryMaxAttempts = 1 | |||
| options := []func(*s3.Options){} | |||
| options = append(options, func(s3Opt *s3.Options) { | |||
| @@ -1,8 +1,9 @@ | |||
| package cmd | |||
| import ( | |||
| "crypto/ecdsa" | |||
| "crypto/elliptic" | |||
| "crypto/rand" | |||
| "crypto/rsa" | |||
| "crypto/x509" | |||
| "crypto/x509/pkix" | |||
| "encoding/pem" | |||
| @@ -58,7 +59,7 @@ func init() { | |||
| } | |||
| func certRoot(output string) { | |||
| caPriv, _ := rsa.GenerateKey(rand.Reader, 2048) | |||
| caPriv, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | |||
| // 创建 CA 证书模板 | |||
| caTemplate := &x509.Certificate{ | |||
| @@ -78,7 +79,9 @@ func certRoot(output string) { | |||
| // 保存 CA 证书和私钥 | |||
| writePem(filepath.Join(output, "ca_cert.pem"), "CERTIFICATE", caCertDER) | |||
| writePem(filepath.Join(output, "ca_key.pem"), "RSA PRIVATE KEY", x509.MarshalPKCS1PrivateKey(caPriv)) | |||
| privPem, _ := x509.MarshalECPrivateKey(caPriv) | |||
| writePem(filepath.Join(output, "ca_key.pem"), "EC PRIVATE KEY", privPem) | |||
| fmt.Println("CA certificate and key saved to", output) | |||
| } | |||
| @@ -111,14 +114,14 @@ func certServer(certFile string, keyFile string, output string) { | |||
| return | |||
| } | |||
| caKey, err := x509.ParsePKCS1PrivateKey(caKeyPEMBlock.Bytes) | |||
| caKey, err := x509.ParseECPrivateKey(caKeyPEMBlock.Bytes) | |||
| if err != nil { | |||
| fmt.Println("Failed to parse CA key:", err) | |||
| return | |||
| } | |||
| // 生成服务端私钥 | |||
| serverPriv, _ := rsa.GenerateKey(rand.Reader, 2048) | |||
| serverPriv, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | |||
| // 服务端证书模板 | |||
| serverTemplate := &x509.Certificate{ | |||
| @@ -141,7 +144,9 @@ func certServer(certFile string, keyFile string, output string) { | |||
| // 保存服务端证书和私钥 | |||
| writePem(filepath.Join(output, "server_cert.pem"), "CERTIFICATE", serverCertDER) | |||
| writePem(filepath.Join(output, "server_key.pem"), "RSA PRIVATE KEY", x509.MarshalPKCS1PrivateKey(serverPriv)) | |||
| privPem, _ := x509.MarshalECPrivateKey(serverPriv) | |||
| writePem(filepath.Join(output, "server_key.pem"), "EC PRIVATE KEY", privPem) | |||
| fmt.Println("Server certificate and key saved to", output) | |||
| } | |||
| @@ -174,14 +179,14 @@ func certClient(certFile string, keyFile string, output string) { | |||
| return | |||
| } | |||
| caKey, err := x509.ParsePKCS1PrivateKey(caKeyPEMBlock.Bytes) | |||
| caKey, err := x509.ParseECPrivateKey(caKeyPEMBlock.Bytes) | |||
| if err != nil { | |||
| fmt.Println("Failed to parse CA key:", err) | |||
| return | |||
| } | |||
| // 生成客户端私钥 | |||
| clientPriv, _ := rsa.GenerateKey(rand.Reader, 2048) | |||
| clientPriv, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | |||
| // 客户端证书模板 | |||
| clientTemplate := &x509.Certificate{ | |||
| @@ -201,7 +206,9 @@ func certClient(certFile string, keyFile string, output string) { | |||
| // 保存客户端证书和私钥 | |||
| writePem(filepath.Join(output, "client_cert.pem"), "CERTIFICATE", clientCertDER) | |||
| writePem(filepath.Join(output, "client_key.pem"), "RSA PRIVATE KEY", x509.MarshalPKCS1PrivateKey(clientPriv)) | |||
| privPem, _ := x509.MarshalECPrivateKey(clientPriv) | |||
| writePem(filepath.Join(output, "client_key.pem"), "EC PRIVATE KEY", privPem) | |||
| fmt.Println("Client certificate and key saved to", output) | |||
| } | |||