客户端鉴权改为证书

This commit is contained in:
Sydonian 2025-06-09 10:51:56 +08:00
parent e8cac2cd1d
commit 15a9bb1642
21 changed files with 845 additions and 259 deletions

View File

@ -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()
}

View File

@ -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()

View File

@ -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()

View File

@ -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"`
}

View File

@ -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()
}

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -0,0 +1 @@
package types

View File

@ -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)
}

View File

@ -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]
}
*/

View File

@ -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,
}))
}

View File

@ -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{}))
}

View File

@ -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}))
}

View File

@ -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,
}))
}

View File

@ -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}))
}

View File

@ -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)
}

View File

@ -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,
}))
}

150
client/sdk/signer/signer.go Normal file
View File

@ -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()
}

View File

@ -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) {

View File

@ -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)
}