客户端鉴权改为证书
This commit is contained in:
parent
e8cac2cd1d
commit
15a9bb1642
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue